Merge tag 'pidfd-updates-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/braun...
[sfrench/cifs-2.6.git] / kernel / pid.c
index e5cad0c7d5ddea08c054419b1f1525bada065bbf..16263b5265604dd7931d4431920d51b633429050 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/syscalls.h>
 #include <linux/proc_ns.h>
 #include <linux/proc_fs.h>
+#include <linux/anon_inodes.h>
+#include <linux/sched/signal.h>
 #include <linux/sched/task.h>
 #include <linux/idr.h>
 
@@ -214,6 +216,8 @@ struct pid *alloc_pid(struct pid_namespace *ns)
        for (type = 0; type < PIDTYPE_MAX; ++type)
                INIT_HLIST_HEAD(&pid->tasks[type]);
 
+       init_waitqueue_head(&pid->wait_pidfd);
+
        upid = pid->numbers + ns->level;
        spin_lock_irq(&pidmap_lock);
        if (!(ns->pid_allocated & PIDNS_ADDING))
@@ -451,6 +455,73 @@ struct pid *find_ge_pid(int nr, struct pid_namespace *ns)
        return idr_get_next(&ns->idr, &nr);
 }
 
+/**
+ * pidfd_create() - Create a new pid file descriptor.
+ *
+ * @pid:  struct pid that the pidfd will reference
+ *
+ * This creates a new pid file descriptor with the O_CLOEXEC flag set.
+ *
+ * Note, that this function can only be called after the fd table has
+ * been unshared to avoid leaking the pidfd to the new process.
+ *
+ * Return: On success, a cloexec pidfd is returned.
+ *         On error, a negative errno number will be returned.
+ */
+static int pidfd_create(struct pid *pid)
+{
+       int fd;
+
+       fd = anon_inode_getfd("[pidfd]", &pidfd_fops, get_pid(pid),
+                             O_RDWR | O_CLOEXEC);
+       if (fd < 0)
+               put_pid(pid);
+
+       return fd;
+}
+
+/**
+ * pidfd_open() - Open new pid file descriptor.
+ *
+ * @pid:   pid for which to retrieve a pidfd
+ * @flags: flags to pass
+ *
+ * This creates a new pid file descriptor with the O_CLOEXEC flag set for
+ * the process identified by @pid. Currently, the process identified by
+ * @pid must be a thread-group leader. This restriction currently exists
+ * for all aspects of pidfds including pidfd creation (CLONE_PIDFD cannot
+ * be used with CLONE_THREAD) and pidfd polling (only supports thread group
+ * leaders).
+ *
+ * Return: On success, a cloexec pidfd is returned.
+ *         On error, a negative errno number will be returned.
+ */
+SYSCALL_DEFINE2(pidfd_open, pid_t, pid, unsigned int, flags)
+{
+       int fd, ret;
+       struct pid *p;
+
+       if (flags)
+               return -EINVAL;
+
+       if (pid <= 0)
+               return -EINVAL;
+
+       p = find_get_pid(pid);
+       if (!p)
+               return -ESRCH;
+
+       ret = 0;
+       rcu_read_lock();
+       if (!pid_task(p, PIDTYPE_TGID))
+               ret = -EINVAL;
+       rcu_read_unlock();
+
+       fd = ret ?: pidfd_create(p);
+       put_pid(p);
+       return fd;
+}
+
 void __init pid_idr_init(void)
 {
        /* Verify no one has done anything silly: */