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) <[email protected]>
---
 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


Reply via email to