Skip to content

Commit

Permalink
BACKPORT: copy_process(): don't use ksys_close() on cleanups
Browse files Browse the repository at this point in the history
anon_inode_getfd() should be used *ONLY* in situations when we are
guaranteed to be past the last failure point (including copying the
descriptor number to userland, at that).  And ksys_close() should
not be used for cleanups at all.

anon_inode_getfile() is there for all nontrivial cases like that.
Just use that...

Bug: 254441685
Fixes: b3e5838 ("clone: add CLONE_PIDFD")
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Reviewed-by: Jann Horn <jannh@google.com>
Signed-off-by: Christian Brauner <christian@brauner.io>
(cherry picked from commit 6fd2fe4)
Signed-off-by: Lee Jones <joneslee@google.com>
Change-Id: Ib24efa6d9776ad1a6f9b8ca08e3aa8deefacfc20
  • Loading branch information
Al Viro authored and lag-google committed Feb 1, 2023
1 parent 435c9b1 commit 9d8945c
Showing 1 changed file with 18 additions and 28 deletions.
46 changes: 18 additions & 28 deletions kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -1712,31 +1712,6 @@ const struct file_operations pidfd_fops = {
#endif
};

/**
* 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;
}

static void copy_oom_score_adj(u64 clone_flags, struct task_struct *tsk)
{
/* Skip if kernel thread */
Expand Down Expand Up @@ -1778,6 +1753,7 @@ static __latent_entropy struct task_struct *copy_process(
int pidfd = -1, retval;
struct task_struct *p;
struct multiprocess_signals delayed;
struct file *pidfile = NULL;

/*
* Don't allow sharing the root directory with processes in a different
Expand Down Expand Up @@ -2050,11 +2026,20 @@ static __latent_entropy struct task_struct *copy_process(
* if the fd table isn't shared).
*/
if (clone_flags & CLONE_PIDFD) {
retval = pidfd_create(pid);
retval = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
if (retval < 0)
goto bad_fork_free_pid;

pidfd = retval;

pidfile = anon_inode_getfile("[pidfd]", &pidfd_fops, pid,
O_RDWR | O_CLOEXEC);
if (IS_ERR(pidfile)) {
put_unused_fd(pidfd);
goto bad_fork_free_pid;
}
get_pid(pid); /* held by pidfile now */

retval = put_user(pidfd, parent_tidptr);
if (retval)
goto bad_fork_put_pidfd;
Expand Down Expand Up @@ -2166,6 +2151,9 @@ static __latent_entropy struct task_struct *copy_process(
goto bad_fork_cancel_cgroup;
}

/* past the last point of failure */
if (pidfile)
fd_install(pidfd, pidfile);

init_task_pid_links(p);
if (likely(p->pid)) {
Expand Down Expand Up @@ -2234,8 +2222,10 @@ static __latent_entropy struct task_struct *copy_process(
bad_fork_cgroup_threadgroup_change_end:
cgroup_threadgroup_change_end(current);
bad_fork_put_pidfd:
if (clone_flags & CLONE_PIDFD)
ksys_close(pidfd);
if (clone_flags & CLONE_PIDFD) {
fput(pidfile);
put_unused_fd(pidfd);
}
bad_fork_free_pid:
if (pid != &init_struct_pid)
free_pid(pid);
Expand Down

0 comments on commit 9d8945c

Please sign in to comment.