[PATCH] UNTESTED UNTESTED DRAFT DRAFT

From: Christian Brauner
Date: Tue Apr 25 2023 - 08:21:18 EST


---
include/linux/file.h | 20 ++++++++++++++++++++
include/linux/pid.h | 3 ++-
kernel/fork.c | 35 +++++++++++++++++++----------------
kernel/pid.c | 14 +++++++-------
4 files changed, 48 insertions(+), 24 deletions(-)

diff --git a/include/linux/file.h b/include/linux/file.h
index 39704eae83e2..fdadaaa9f70b 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -39,6 +39,11 @@ struct fd {
#define FDPUT_FPUT 1
#define FDPUT_POS_UNLOCK 2

+struct fd_file {
+ struct file *file;
+ int fd;
+};
+
static inline void fdput(struct fd fd)
{
if (fd.flags & FDPUT_FPUT)
@@ -90,6 +95,21 @@ extern void put_unused_fd(unsigned int fd);

extern void fd_install(unsigned int fd, struct file *file);

+static inline void fd_publish(struct fd_file *fdf)
+{
+ if (fdf->file)
+ fd_install(fdf->fd, fdf->file);
+}
+
+static inline void fd_discard(struct fd_file *fdf)
+{
+ if (fdf->file) {
+ fput(fdf->file);
+ put_unused_fd(fdf->fd);
+
+ }
+}
+
extern int __receive_fd(struct file *file, int __user *ufd,
unsigned int o_flags);

diff --git a/include/linux/pid.h b/include/linux/pid.h
index b75de288a8c2..0b0695459508 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -75,12 +75,13 @@ extern struct pid init_struct_pid;
extern const struct file_operations pidfd_fops;

struct file;
+struct fd_file;

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);
-int pidfd_prepare(struct pid *pid, unsigned int flags, struct file **ret);
+int pidfd_prepare(struct pid *pid, unsigned int flags, struct fd_file *fdf);

static inline struct pid *get_pid(struct pid *pid)
{
diff --git a/kernel/fork.c b/kernel/fork.c
index bfe73db1c26c..2072d8cc91d2 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1989,7 +1989,8 @@ const struct file_operations pidfd_fops = {
* error, a negative error code is returned from the function and the
* last argument remains unchanged.
*/
-static int __pidfd_prepare(struct pid *pid, unsigned int flags, struct file **ret)
+static int __pidfd_prepare(struct pid *pid, unsigned int flags,
+ struct fd_file *fdf)
{
int pidfd;
struct file *pidfd_file;
@@ -2008,8 +2009,11 @@ static int __pidfd_prepare(struct pid *pid, unsigned int flags, struct file **re
return PTR_ERR(pidfd_file);
}
get_pid(pid); /* held by pidfd_file now */
- *ret = pidfd_file;
- return pidfd;
+
+ fdf->file = pidfd_file;
+ fdf->fd = pidfd;
+
+ return 0;
}

/**
@@ -2038,12 +2042,12 @@ static int __pidfd_prepare(struct pid *pid, unsigned int flags, struct file **re
* error, a negative error code is returned from the function and the
* last argument remains unchanged.
*/
-int pidfd_prepare(struct pid *pid, unsigned int flags, struct file **ret)
+int pidfd_prepare(struct pid *pid, unsigned int flags, struct fd_file *fdf)
{
if (!pid || !pid_has_task(pid, PIDTYPE_TGID))
return -EINVAL;

- return __pidfd_prepare(pid, flags, ret);
+ return __pidfd_prepare(pid, flags, fdf);
}

static void __delayed_free_task(struct rcu_head *rhp)
@@ -2106,10 +2110,12 @@ __latent_entropy struct task_struct *copy_process(
int node,
struct kernel_clone_args *args)
{
- int pidfd = -1, retval;
+ int retval;
+ struct fd_file pidfd = {
+ .fd = -1,
+ };
struct task_struct *p;
struct multiprocess_signals delayed;
- struct file *pidfile = NULL;
const u64 clone_flags = args->flags;
struct nsproxy *nsp = current->nsproxy;

@@ -2395,12 +2401,11 @@ __latent_entropy struct task_struct *copy_process(
*/
if (clone_flags & CLONE_PIDFD) {
/* Note that no task has been attached to @pid yet. */
- retval = __pidfd_prepare(pid, O_RDWR | O_CLOEXEC, &pidfile);
+ retval = __pidfd_prepare(pid, O_RDWR | O_CLOEXEC, &pidfd);
if (retval < 0)
goto bad_fork_free_pid;
- pidfd = retval;

- retval = put_user(pidfd, args->pidfd);
+ retval = put_user(pidfd.fd, args->pidfd);
if (retval)
goto bad_fork_put_pidfd;
}
@@ -2584,8 +2589,8 @@ __latent_entropy struct task_struct *copy_process(
syscall_tracepoint_update(p);
write_unlock_irq(&tasklist_lock);

- if (pidfile)
- fd_install(pidfd, pidfile);
+ if (clone_flags & CLONE_PIDFD)
+ fd_publish(&pidfd);

proc_fork_connector(p);
sched_post_fork(p);
@@ -2605,10 +2610,8 @@ __latent_entropy struct task_struct *copy_process(
write_unlock_irq(&tasklist_lock);
cgroup_cancel_fork(p, args);
bad_fork_put_pidfd:
- if (clone_flags & CLONE_PIDFD) {
- fput(pidfile);
- put_unused_fd(pidfd);
- }
+ if (clone_flags & CLONE_PIDFD)
+ fd_discard(&pidfd);
bad_fork_free_pid:
if (pid != &init_struct_pid)
free_pid(pid);
diff --git a/kernel/pid.c b/kernel/pid.c
index f93954a0384d..6cd46002aca3 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -594,15 +594,15 @@ struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags)
*/
int pidfd_create(struct pid *pid, unsigned int flags)
{
- int pidfd;
- struct file *pidfd_file;
+ int ret;
+ struct fd_file pidfd;

- pidfd = pidfd_prepare(pid, flags, &pidfd_file);
- if (pidfd < 0)
- return pidfd;
+ ret = pidfd_prepare(pid, flags, &pidfd);
+ if (ret < 0)
+ return ret;

- fd_install(pidfd, pidfd_file);
- return pidfd;
+ fd_publish(&pidfd);
+ return pidfd.fd;
}

/**
--
2.34.1