Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pidfd: add P_PIDFD to waitid()

This adds the P_PIDFD type to waitid().
One of the last remaining bits for the pidfd api is to make it possible
to wait on pidfds. With P_PIDFD added to waitid() the parts of userspace
that want to use the pidfd api to exclusively manage processes can do so
now.

One of the things this will unblock in the future is the ability to make
it possible to retrieve the exit status via waitid(P_PIDFD) for
non-parent processes if handed a _suitable_ pidfd that has this feature
set. This is similar to what you can do on FreeBSD with kqueue(). It
might even end up being possible to wait on a process as a non-parent if
an appropriate property is enabled on the pidfd.

With P_PIDFD no scoping of the process identified by the pidfd is
possible, i.e. it explicitly blocks things such as wait4(-1), wait4(0),
waitid(P_ALL), waitid(P_PGID) etc. It only allows for semantics
equivalent to wait4(pid), waitid(P_PID). Users that need scoping should
rely on pid-based wait*() syscalls for now.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Joel Fernandes (Google) <joel@joelfernandes.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: David Howells <dhowells@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Andy Lutomirsky <luto@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Aleksa Sarai <cyphar@cyphar.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Link: https://lore.kernel.org/r/20190727222229.6516-2-christian@brauner.io

+48 -5
+4
include/linux/pid.h
··· 72 72 73 73 extern const struct file_operations pidfd_fops; 74 74 75 + struct file; 76 + 77 + extern struct pid *pidfd_pid(const struct file *file); 78 + 75 79 static inline struct pid *get_pid(struct pid *pid) 76 80 { 77 81 if (pid)
+1
include/uapi/linux/wait.h
··· 17 17 #define P_ALL 0 18 18 #define P_PID 1 19 19 #define P_PGID 2 20 + #define P_PIDFD 3 20 21 21 22 22 23 #endif /* _UAPI_LINUX_WAIT_H */
+30 -3
kernel/exit.c
··· 1552 1552 return retval; 1553 1553 } 1554 1554 1555 + static struct pid *pidfd_get_pid(unsigned int fd) 1556 + { 1557 + struct fd f; 1558 + struct pid *pid; 1559 + 1560 + f = fdget(fd); 1561 + if (!f.file) 1562 + return ERR_PTR(-EBADF); 1563 + 1564 + pid = pidfd_pid(f.file); 1565 + if (!IS_ERR(pid)) 1566 + get_pid(pid); 1567 + 1568 + fdput(f); 1569 + return pid; 1570 + } 1571 + 1555 1572 static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop, 1556 1573 int options, struct rusage *ru) 1557 1574 { ··· 1591 1574 type = PIDTYPE_PID; 1592 1575 if (upid <= 0) 1593 1576 return -EINVAL; 1577 + 1578 + pid = find_get_pid(upid); 1594 1579 break; 1595 1580 case P_PGID: 1596 1581 type = PIDTYPE_PGID; 1597 1582 if (upid <= 0) 1598 1583 return -EINVAL; 1584 + 1585 + pid = find_get_pid(upid); 1586 + break; 1587 + case P_PIDFD: 1588 + type = PIDTYPE_PID; 1589 + if (upid < 0) 1590 + return -EINVAL; 1591 + 1592 + pid = pidfd_get_pid(upid); 1593 + if (IS_ERR(pid)) 1594 + return PTR_ERR(pid); 1599 1595 break; 1600 1596 default: 1601 1597 return -EINVAL; 1602 1598 } 1603 - 1604 - if (type < PIDTYPE_MAX) 1605 - pid = find_get_pid(upid); 1606 1599 1607 1600 wo.wo_type = type; 1608 1601 wo.wo_pid = pid;
+8
kernel/fork.c
··· 1690 1690 #endif /* #ifdef CONFIG_TASKS_RCU */ 1691 1691 } 1692 1692 1693 + struct pid *pidfd_pid(const struct file *file) 1694 + { 1695 + if (file->f_op == &pidfd_fops) 1696 + return file->private_data; 1697 + 1698 + return ERR_PTR(-EBADF); 1699 + } 1700 + 1693 1701 static int pidfd_release(struct inode *inode, struct file *file) 1694 1702 { 1695 1703 struct pid *pid = file->private_data;
+5 -2
kernel/signal.c
··· 3672 3672 3673 3673 static struct pid *pidfd_to_pid(const struct file *file) 3674 3674 { 3675 - if (file->f_op == &pidfd_fops) 3676 - return file->private_data; 3675 + struct pid *pid; 3676 + 3677 + pid = pidfd_pid(file); 3678 + if (!IS_ERR(pid)) 3679 + return pid; 3677 3680 3678 3681 return tgid_pidfd_to_pid(file); 3679 3682 }