forked from Minki/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
This commit is contained in:
parent
5f9e832c13
commit
3695eae5fe
@ -72,6 +72,10 @@ extern struct pid init_struct_pid;
|
||||
|
||||
extern const struct file_operations pidfd_fops;
|
||||
|
||||
struct file;
|
||||
|
||||
extern struct pid *pidfd_pid(const struct file *file);
|
||||
|
||||
static inline struct pid *get_pid(struct pid *pid)
|
||||
{
|
||||
if (pid)
|
||||
|
@ -17,6 +17,7 @@
|
||||
#define P_ALL 0
|
||||
#define P_PID 1
|
||||
#define P_PGID 2
|
||||
#define P_PIDFD 3
|
||||
|
||||
|
||||
#endif /* _UAPI_LINUX_WAIT_H */
|
||||
|
@ -1552,6 +1552,23 @@ end:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct pid *pidfd_get_pid(unsigned int fd)
|
||||
{
|
||||
struct fd f;
|
||||
struct pid *pid;
|
||||
|
||||
f = fdget(fd);
|
||||
if (!f.file)
|
||||
return ERR_PTR(-EBADF);
|
||||
|
||||
pid = pidfd_pid(f.file);
|
||||
if (!IS_ERR(pid))
|
||||
get_pid(pid);
|
||||
|
||||
fdput(f);
|
||||
return pid;
|
||||
}
|
||||
|
||||
static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
|
||||
int options, struct rusage *ru)
|
||||
{
|
||||
@ -1574,19 +1591,29 @@ static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
|
||||
type = PIDTYPE_PID;
|
||||
if (upid <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
pid = find_get_pid(upid);
|
||||
break;
|
||||
case P_PGID:
|
||||
type = PIDTYPE_PGID;
|
||||
if (upid <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
pid = find_get_pid(upid);
|
||||
break;
|
||||
case P_PIDFD:
|
||||
type = PIDTYPE_PID;
|
||||
if (upid < 0)
|
||||
return -EINVAL;
|
||||
|
||||
pid = pidfd_get_pid(upid);
|
||||
if (IS_ERR(pid))
|
||||
return PTR_ERR(pid);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type < PIDTYPE_MAX)
|
||||
pid = find_get_pid(upid);
|
||||
|
||||
wo.wo_type = type;
|
||||
wo.wo_pid = pid;
|
||||
wo.wo_flags = options;
|
||||
|
@ -1690,6 +1690,14 @@ static inline void rcu_copy_process(struct task_struct *p)
|
||||
#endif /* #ifdef CONFIG_TASKS_RCU */
|
||||
}
|
||||
|
||||
struct pid *pidfd_pid(const struct file *file)
|
||||
{
|
||||
if (file->f_op == &pidfd_fops)
|
||||
return file->private_data;
|
||||
|
||||
return ERR_PTR(-EBADF);
|
||||
}
|
||||
|
||||
static int pidfd_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct pid *pid = file->private_data;
|
||||
|
@ -3672,8 +3672,11 @@ static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo, siginfo_t *info)
|
||||
|
||||
static struct pid *pidfd_to_pid(const struct file *file)
|
||||
{
|
||||
if (file->f_op == &pidfd_fops)
|
||||
return file->private_data;
|
||||
struct pid *pid;
|
||||
|
||||
pid = pidfd_pid(file);
|
||||
if (!IS_ERR(pid))
|
||||
return pid;
|
||||
|
||||
return tgid_pidfd_to_pid(file);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user