lkml.org 
[lkml]   [2017]   [Mar]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.12 020/113] af_unix: move unix_mknod() out of bindlock
    Date
    From: WANG Cong <xiyou.wangcong@gmail.com>

    3.12-stable review patch. If anyone has any objections, please let me know.

    ===============

    [ Upstream commit 0fb44559ffd67de8517098b81f675fa0210f13f0 ]

    Dmitry reported a deadlock scenario:

    unix_bind() path:
    u->bindlock ==> sb_writer

    do_splice() path:
    sb_writer ==> pipe->mutex ==> u->bindlock

    In the unix_bind() code path, unix_mknod() does not have to
    be done with u->bindlock held, since it is a pure fs operation,
    so we can just move unix_mknod() out.

    Reported-by: Dmitry Vyukov <dvyukov@google.com>
    Tested-by: Dmitry Vyukov <dvyukov@google.com>
    Cc: Rainer Weikusat <rweikusat@mobileactivedefense.com>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Jiri Slaby <jslaby@suse.cz>
    ---
    net/unix/af_unix.c | 27 ++++++++++++++++-----------
    1 file changed, 16 insertions(+), 11 deletions(-)

    diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
    index 3974413f78e7..339532b15223 100644
    --- a/net/unix/af_unix.c
    +++ b/net/unix/af_unix.c
    @@ -978,6 +978,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
    unsigned int hash;
    struct unix_address *addr;
    struct hlist_head *list;
    + struct path path = { NULL, NULL };

    err = -EINVAL;
    if (sunaddr->sun_family != AF_UNIX)
    @@ -993,9 +994,20 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
    goto out;
    addr_len = err;

    + if (sun_path[0]) {
    + umode_t mode = S_IFSOCK |
    + (SOCK_INODE(sock)->i_mode & ~current_umask());
    + err = unix_mknod(sun_path, mode, &path);
    + if (err) {
    + if (err == -EEXIST)
    + err = -EADDRINUSE;
    + goto out;
    + }
    + }
    +
    err = mutex_lock_interruptible(&u->readlock);
    if (err)
    - goto out;
    + goto out_put;

    err = -EINVAL;
    if (u->addr)
    @@ -1012,16 +1024,6 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
    atomic_set(&addr->refcnt, 1);

    if (sun_path[0]) {
    - struct path path;
    - umode_t mode = S_IFSOCK |
    - (SOCK_INODE(sock)->i_mode & ~current_umask());
    - err = unix_mknod(sun_path, mode, &path);
    - if (err) {
    - if (err == -EEXIST)
    - err = -EADDRINUSE;
    - unix_release_addr(addr);
    - goto out_up;
    - }
    addr->hash = UNIX_HASH_SIZE;
    hash = path.dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1);
    spin_lock(&unix_table_lock);
    @@ -1048,6 +1050,9 @@ out_unlock:
    spin_unlock(&unix_table_lock);
    out_up:
    mutex_unlock(&u->readlock);
    +out_put:
    + if (err)
    + path_put(&path);
    out:
    return err;
    }
    --
    2.12.0
    \
     
     \ /
      Last update: 2017-03-06 10:40    [W:2.650 / U:0.100 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site