The answer is (or at least starts) in fs/proc/base.c
(unchanged from kernel 3.12 to 4.2 at least)
742 static int proc_pid_permission(struct inode *inode, int mask)
743 {
744 struct pid_namespace *pid = inode->i_sb->s_fs_info;
745 struct task_struct *task;
746 bool has_perms;
747
748 task = get_proc_task(inode);
749 if (!task)
750 return -ESRCH;
751 has_perms = has_pid_permissions(pid, task, 1);
752 put_task_struct(task);
753
754 if (!has_perms) {
755 if (pid->hide_pid == 2) {
756 /*
757 * Let's make getdents(), stat(), and open()
758 * consistent with each other. If a process
759 * may not stat() a file, it shouldn't be seen
760 * in procfs at all.
761 */
762 return -ENOENT;
763 }
764
765 return -EPERM;
766 }
767 return generic_permission(inode, mask);
768 }
The code above is the starting point for determining if a specific /proc/PID
entry can been seen to exist or not. When hide_pid
is set to 2 it returns -ENOENT
if you don't have the required permission. Permissions are checked via:
has_pid_permissions()
→
ptrace_may_access()
→
__ptrace_may_access()
__ptrace_may_access()
denies access because the process is not "dumpable" as it was created from an unreadable executable image, as determined during process creation:
setup_new_exec()
→
would_dump()
1118 void would_dump(struct linux_binprm *bprm, struct file *file)
1119 {
1120 if (inode_permission(file_inode(file), MAY_READ) < 0)
1121 bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
1122 }
To background itself, that application forks a child process and exits the parent. The shell knows of the parent process as that's the one it has forked itself before executing the command itself, but it has no visibility on the children or grand-children that that process may have spawned.
A simpler example of such a backgrounding command would be:
$ sh -c 'ps -j; sleep 10 &'
PID PGID SID TTY TIME CMD
6562 6562 14469 pts/13 00:00:00 sh
6563 6562 14469 pts/13 00:00:00 ps
14469 14469 14469 pts/13 00:00:00 zsh
My zsh
knows about that sh
process and its process group.
However, all it sees is that 6562 process exiting. It has no way to know that 6562 process has spawned a 6563 one.
$ ps -j
PID PGID SID TTY TIME CMD
6564 6562 14469 pts/13 00:00:00 sleep
6565 6565 14469 pts/13 00:00:00 ps
14469 14469 14469 pts/13 00:00:00 zsh
However, you can see the process running sleep
is also in that 6562 process group (though, there's nothing stopping commands start new process groups, or even sessions (as daemons typically do)).
Those process groups are only created when the shell is interactive though.
Another thing you could do is:
cmd | cat &
wait
If the processes that cmd spawns don't close their stdout, then cat
won't die until they have all died.
Best Answer
Check the kernel documentation for information about files in
/proc
.There is one such file per process because not all processes see the same mount points. Chroot is a traditional Unix feature that makes it possible to restrict processes to a subtree of the filesystem tree. A chrooted process would not see mount points outside its root. Linux takes this further with namespaces: a process can compose its own view of the filesystem by grafting subtrees around.
For more information on mount namespaces, see per process private file system mount points and Michael Kerrisk's articles on namespaces on LWN.