]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
fs: Add receive_fd() wrapper for __receive_fd()
authorKees Cook <keescook@chromium.org>
Thu, 11 Jun 2020 03:47:45 +0000 (20:47 -0700)
committerKees Cook <keescook@chromium.org>
Mon, 13 Jul 2020 18:03:44 +0000 (11:03 -0700)
For both pidfd and seccomp, the __user pointer is not used. Update
__receive_fd() to make writing to ufd optional via a NULL check. However,
for the receive_fd_user() wrapper, ufd is NULL checked so an -EFAULT
can be returned to avoid changing the SCM_RIGHTS interface behavior. Add
new wrapper receive_fd() for pidfd and seccomp that does not use the ufd
argument. For the new helper, the allocated fd needs to be returned on
success. Update the existing callers to handle it.

Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org
Reviewed-by: Sargun Dhillon <sargun@sargun.me>
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
fs/file.c
include/linux/file.h
net/compat.c
net/core/scm.c

index 0cd598cab47648191062e4c4103bfe26b387ca63..56d96d5c0c9fbceb17303cfe6422948e798b69b2 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -944,12 +944,13 @@ out_unlock:
  * @o_flags: the O_* flags to apply to the new fd entry
  *
  * Installs a received file into the file descriptor table, with appropriate
- * checks and count updates. Writes the fd number to userspace.
+ * checks and count updates. Optionally writes the fd number to userspace, if
+ * @ufd is non-NULL.
  *
  * This helper handles its own reference counting of the incoming
  * struct file.
  *
- * Returns -ve on error.
+ * Returns newly install fd or -ve on error.
  */
 int __receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
 {
@@ -964,16 +965,18 @@ int __receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
        if (new_fd < 0)
                return new_fd;
 
-       error = put_user(new_fd, ufd);
-       if (error) {
-               put_unused_fd(new_fd);
-               return error;
+       if (ufd) {
+               error = put_user(new_fd, ufd);
+               if (error) {
+                       put_unused_fd(new_fd);
+                       return error;
+               }
        }
 
        /* Bump the sock usage counts, if any. */
        __receive_sock(file);
        fd_install(new_fd, get_file(file));
-       return 0;
+       return new_fd;
 }
 
 static int ksys_dup3(unsigned int oldfd, unsigned int newfd, int flags)
index b14ff2ffd0bdd7e0a3a87b2e12f1c1a391f9e897..d9fee9f5c8daf0b4e999270fc77bf25f449d9db6 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <linux/posix_types.h>
+#include <linux/errno.h>
 
 struct file;
 
@@ -96,8 +97,14 @@ extern int __receive_fd(struct file *file, int __user *ufd,
 static inline int receive_fd_user(struct file *file, int __user *ufd,
                                  unsigned int o_flags)
 {
+       if (ufd == NULL)
+               return -EFAULT;
        return __receive_fd(file, ufd, o_flags);
 }
+static inline int receive_fd(struct file *file, unsigned int o_flags)
+{
+       return __receive_fd(file, NULL, o_flags);
+}
 
 extern void flush_delayed_fput(void);
 extern void __fput_sync(struct file *);
index e74cd3dae8b054433bd83e87475c89239653bab4..dc7ddbc2b15e93c382b854c46d0464fde04a8892 100644 (file)
@@ -299,7 +299,7 @@ void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
 
        for (i = 0; i < fdmax; i++) {
                err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags);
-               if (err)
+               if (err < 0)
                        break;
        }
 
index 67c166a7820dfbc947e0eac3ad7e611b29c9c227..8156d4fb8a3966122fdfcfd0ebc9e5520aa7b67c 100644 (file)
@@ -307,7 +307,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
 
        for (i = 0; i < fdmax; i++) {
                err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags);
-               if (err)
+               if (err < 0)
                        break;
        }