[PATCH 1/3] [HERE BE DRAGONS - DRAFT - __UNTESTED__] pid: add pidfd_file_create()

From: Christian Brauner
Date: Wed Mar 22 2023 - 10:59:02 EST


Reserve and fd and pidfile, do stuff that might fail, install fd when
point of no return.

[HERE BE DRAGONS - DRAFT - __UNTESTED__] pid: add pidfd_file_create()

Signed-off-by: Christian Brauner <brauner@xxxxxxxxxx>
---
include/linux/pid.h | 1 +
kernel/pid.c | 45 +++++++++++++++++++++++++++++++++------------
2 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/include/linux/pid.h b/include/linux/pid.h
index 343abf22092e..c486dbc4d7b6 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -80,6 +80,7 @@ extern struct pid *pidfd_pid(const struct file *file);
struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags);
struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags);
int pidfd_create(struct pid *pid, unsigned int flags);
+struct file *pidfd_file_create(struct pid *pid, unsigned int flags, int *pidfd);

static inline struct pid *get_pid(struct pid *pid)
{
diff --git a/kernel/pid.c b/kernel/pid.c
index 3fbc5e46b721..8d0924f1dbf6 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -576,6 +576,32 @@ struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags)
return task;
}

+struct file *pidfd_file_create(struct pid *pid, unsigned int flags, int *pidfd)
+{
+ int fd;
+ struct file *pidfile;
+
+ if (!pid || !pid_has_task(pid, PIDTYPE_TGID))
+ return ERR_PTR(-EINVAL);
+
+ if (flags & ~(O_NONBLOCK | O_RDWR | O_CLOEXEC))
+ return ERR_PTR(-EINVAL);
+
+ fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ return ERR_PTR(fd);
+
+ pidfile = anon_inode_getfile("[pidfd]", &pidfd_fops, pid,
+ flags | O_RDWR | O_CLOEXEC);
+ if (IS_ERR(pidfile)) {
+ put_unused_fd(fd);
+ return pidfile;
+ }
+ get_pid(pid); /* held by pidfile now */
+ *pidfd = fd;
+ return pidfile;
+}
+
/**
* pidfd_create() - Create a new pid file descriptor.
*
@@ -594,20 +620,15 @@ struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags)
*/
int pidfd_create(struct pid *pid, unsigned int flags)
{
- int fd;
+ int pidfd;
+ struct file *pidfile;

- if (!pid || !pid_has_task(pid, PIDTYPE_TGID))
- return -EINVAL;
+ pidfile = pidfd_file_create(pid, flags, &pidfd);
+ if (IS_ERR(pidfile))
+ return PTR_ERR(pidfile);

- if (flags & ~(O_NONBLOCK | O_RDWR | O_CLOEXEC))
- return -EINVAL;
-
- fd = anon_inode_getfd("[pidfd]", &pidfd_fops, get_pid(pid),
- flags | O_RDWR | O_CLOEXEC);
- if (fd < 0)
- put_pid(pid);
-
- return fd;
+ fd_install(pidfd, pidfile);
+ return pidfd;
}

/**
--
2.34.1