lkml.org 
[lkml]   [2020]   [Jun]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 03/11] fs: Add fd_install_received() wrapper for __fd_install_received()
    Date
    For both pidfd and seccomp, the __user pointer is not used. Update
    __fd_install_received() to make writing to ufd optional. (ufd
    itself cannot checked for NULL because this changes the SCM_RIGHTS
    interface behavior.) In these cases, the new fd needs to be returned
    on success. Update the existing callers to handle it. Add new wrapper
    fd_install_received() for pidfd and seccomp that does not use the ufd
    argument.

    Signed-off-by: Kees Cook <keescook@chromium.org>
    ---
    fs/file.c | 26 +++++++++++++++++---------
    include/linux/file.h | 10 +++++++---
    net/compat.c | 2 +-
    net/core/scm.c | 2 +-
    4 files changed, 26 insertions(+), 14 deletions(-)

    diff --git a/fs/file.c b/fs/file.c
    index fcfddae0d252..14a8ef74efb2 100644
    --- a/fs/file.c
    +++ b/fs/file.c
    @@ -944,11 +944,14 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
    * @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. Optionally writes the fd number to userspace.
    + * checks and count updates. Optionally writes the fd number to userspace, if
    + * @ufd_required is true (@ufd cannot just be tested for NULL because NULL may
    + * actually get passed into SCM_RIGHTS).
    *
    - * Returns -ve on error.
    + * Returns newly install fd or -ve on error.
    */
    -int __fd_install_received(struct file *file, int __user *ufd, unsigned int o_flags)
    +int __fd_install_received(struct file *file, bool ufd_required, int __user *ufd,
    + unsigned int o_flags)
    {
    struct socket *sock;
    int new_fd;
    @@ -962,20 +965,25 @@ int __fd_install_received(struct file *file, int __user *ufd, unsigned int o_fla
    if (new_fd < 0)
    return new_fd;

    - error = put_user(new_fd, ufd);
    - if (error) {
    - put_unused_fd(new_fd);
    - return error;
    + if (ufd_required) {
    + error = put_user(new_fd, ufd);
    + if (error) {
    + put_unused_fd(new_fd);
    + return error;
    + }
    }

    - /* Bump the usage count and install the file. */
    + /* Bump the usage count and install the file. The resulting value of
    + * "error" is ignored here since we only need to take action when
    + * the file is a socket and testing "sock" for NULL is sufficient.
    + */
    sock = sock_from_file(file, &error);
    if (sock) {
    sock_update_netprioidx(&sock->sk->sk_cgrp_data);
    sock_update_classid(&sock->sk->sk_cgrp_data);
    }
    fd_install(new_fd, get_file(file));
    - return 0;
    + return new_fd;
    }

    static int ksys_dup3(unsigned int oldfd, unsigned int newfd, int flags)
    diff --git a/include/linux/file.h b/include/linux/file.h
    index fe18a1a0d555..999a2c56db07 100644
    --- a/include/linux/file.h
    +++ b/include/linux/file.h
    @@ -91,12 +91,16 @@ extern void put_unused_fd(unsigned int fd);

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

    -extern int __fd_install_received(struct file *file, int __user *ufd,
    - unsigned int o_flags);
    +extern int __fd_install_received(struct file *file, bool ufd_required,
    + int __user *ufd, unsigned int o_flags);
    static inline int fd_install_received_user(struct file *file, int __user *ufd,
    unsigned int o_flags)
    {
    - return __fd_install_received(file, ufd, o_flags);
    + return __fd_install_received(file, true, ufd, o_flags);
    +}
    +static inline int fd_install_received(struct file *file, unsigned int o_flags)
    +{
    + return __fd_install_received(file, false, NULL, o_flags);
    }

    extern void flush_delayed_fput(void);
    diff --git a/net/compat.c b/net/compat.c
    index 94f288e8dac5..71494337cca7 100644
    --- a/net/compat.c
    +++ b/net/compat.c
    @@ -299,7 +299,7 @@ void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)

    for (i = 0; i < fdmax; i++) {
    err = fd_install_received_user(scm->fp->fp[i], cmsg_data + i, o_flags);
    - if (err)
    + if (err < 0)
    break;
    }

    diff --git a/net/core/scm.c b/net/core/scm.c
    index df190f1fdd28..b9a0442ebd26 100644
    --- a/net/core/scm.c
    +++ b/net/core/scm.c
    @@ -307,7 +307,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)

    for (i = 0; i < fdmax; i++) {
    err = fd_install_received_user(scm->fp->fp[i], cmsg_data + i, o_flags);
    - if (err)
    + if (err < 0)
    break;
    }

    --
    2.25.1
    \
     
     \ /
      Last update: 2020-06-16 05:27    [W:4.088 / U:0.040 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site