scm_recv_one_fd() allocates a descriptor, writes the number into the control message and installs the file right there, one descriptor at a time. Everything that recvmsg() does after scm_detach_fds() can still fail though. When it does the syscall returns -EFAULT while the received descriptors are already in the table and the caller has no way to tell. Reserve the descriptor with fd_prepare() and stage the file with fd_stage(). The number is written to userspace as before, but the file is only installed when recvmsg() returns success and dropped together with the descriptor when it returns an error. A control message that doesn't fit still gets only the descriptors it can report and MSG_CTRUNC. IORING_OP_RECVMSG reaches the same code from io-wq workers and the SQPOLL thread. io_uring requests commit their reservations before the completion is posted. Signed-off-by: Christian Brauner (Amutable) --- net/core/scm.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/core/scm.c b/net/core/scm.c index f0d44ecdb11f..f05931eef54d 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -355,6 +355,7 @@ int scm_recv_one_fd(struct file *f, int __user *ufd, unsigned int flags, bool notrunc) { int error; + const struct fd_slot *fd; if (!ufd) return -EFAULT; @@ -363,16 +364,16 @@ int scm_recv_one_fd(struct file *f, int __user *ufd, unsigned int flags, if (error) return notrunc ? put_user(error, ufd) : error; - FD_PREPARE(fdf, flags, get_file(f)); - if (fdf.err) - return fdf.err; + fd = fd_prepare(flags); + if (IS_ERR(fd)) + return PTR_ERR(fd); - error = put_user(fd_prepare_fd(fdf), ufd); + error = put_user(fd_prepare_fd(fd), ufd); if (error) return error; - __receive_sock(fd_prepare_file(fdf)); - return fd_publish(fdf); + __receive_sock(f); + return fd_stage(fd, get_file(f)); } void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm, bool notrunc) -- 2.53.0