@@ -78,11 +78,15 @@ struct file;
* __pidfd_get_pid() - Retrieve a pid associated with the specified pidfd.
*
* @pidfd: The pidfd whose pid we want, or the fd of a /proc/<pid> file if
- * @alloc_proc is also set.
+ * @alloc_proc is also set, or PIDFD_SELF_* to refer to the current
+ * thread or thread group leader.
* @allow_proc: If set, then an fd of a /proc/<pid> file can be passed instead
* of a pidfd, and this will be used to determine the pid.
+
* @flags: Output variable, if non-NULL, then the file->f_flags of the
- * pidfd will be set here.
+ * pidfd will be set here or If PIDFD_SELF_THREAD is set, this is
+ * set to PIDFD_THREAD, otherwise if PIDFD_SELF_THREAD_GROUP then
+ * this is set to zero.
*
* Returns: If successful, the pid associated with the pidfd, otherwise an
* error.
@@ -29,4 +29,14 @@
#define PIDFD_GET_USER_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 9)
#define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10)
+/*
+ * Special sentinel values which can be used to refer to the current thread or
+ * thread group leader (which from a userland perspective is the process).
+ */
+#define PIDFD_SELF PIDFD_SELF_THREAD
+#define PIDFD_SELF_PROCESS PIDFD_SELF_THREAD_GROUP
+
+#define PIDFD_SELF_THREAD -10000 /* Current thread. */
+#define PIDFD_SELF_THREAD_GROUP -20000 /* Current thread group leader. */
+
#endif /* _UAPI_LINUX_PIDFD_H */
@@ -71,6 +71,7 @@
#include <linux/user_events.h>
#include <linux/uaccess.h>
+#include <uapi/linux/pidfd.h>
#include <uapi/linux/wait.h>
#include <asm/unistd.h>
@@ -1739,7 +1740,8 @@ int kernel_waitid_prepare(struct wait_opts *wo, int which, pid_t upid,
break;
case P_PIDFD:
type = PIDTYPE_PID;
- if (upid < 0)
+ if (upid < 0 && upid != PIDFD_SELF_THREAD &&
+ upid != PIDFD_SELF_THREAD_GROUP)
return -EINVAL;
pid = pidfd_get_pid(upid, &f_flags);
@@ -550,6 +550,7 @@ SYSCALL_DEFINE2(setns, int, fd, int, flags)
struct nsset nsset = {};
int err = 0;
+ /* If fd is PIDFD_SELF_*, implicitly fail here, as invalid. */
if (!fd_file(f))
return -EBADF;
@@ -535,33 +535,48 @@ struct pid *find_ge_pid(int nr, struct pid_namespace *ns)
}
EXPORT_SYMBOL_GPL(find_ge_pid);
+static struct pid *pidfd_get_pid_self(unsigned int pidfd, unsigned int *flags)
+{
+ bool is_thread = pidfd == PIDFD_SELF_THREAD;
+ enum pid_type type = is_thread ? PIDTYPE_PID : PIDTYPE_TGID;
+ struct pid *pid = *task_pid_ptr(current, type);
+
+ /* The caller expects an elevated reference count. */
+ get_pid(pid);
+ return pid;
+}
+
struct pid *__pidfd_get_pid(unsigned int pidfd, bool allow_proc,
unsigned int *flags)
{
- struct pid *pid;
- struct fd f = fdget(pidfd);
- struct file *file = fd_file(f);
+ if (pidfd == PIDFD_SELF_THREAD || pidfd == PIDFD_SELF_THREAD_GROUP) {
+ return pidfd_get_pid_self(pidfd, flags);
+ } else {
+ struct pid *pid;
+ struct fd f = fdget(pidfd);
+ struct file *file = fd_file(f);
- if (!file)
- return ERR_PTR(-EBADF);
+ if (!file)
+ return ERR_PTR(-EBADF);
- pid = pidfd_pid(file);
- /* If we allow opening a pidfd via /proc/<pid>, do so. */
- if (IS_ERR(pid) && allow_proc)
- pid = tgid_pidfd_to_pid(file);
+ pid = pidfd_pid(file);
+ /* If we allow opening a pidfd via /proc/<pid>, do so. */
+ if (IS_ERR(pid) && allow_proc)
+ pid = tgid_pidfd_to_pid(file);
- if (IS_ERR(pid)) {
+ if (IS_ERR(pid)) {
+ fdput(f);
+ return pid;
+ }
+
+ /* Pin pid before we release fd. */
+ get_pid(pid);
+ if (flags)
+ *flags = file->f_flags;
fdput(f);
+
return pid;
}
-
- /* Pin pid before we release fd. */
- get_pid(pid);
- if (flags)
- *flags = file->f_flags;
- fdput(f);
-
- return pid;
}
/**