mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-09-21 03:43:03 +00:00
af_unix: move unix_mknod() out of bindlock
commit 0fb44559ffd67de8517098b81f675fa0210f13f0 upstream. 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: Willy Tarreau <w@1wt.eu>
This commit is contained in:
parent
863f3de254
commit
2c18ec57d8
|
@ -978,6 +978,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||||
unsigned int hash;
|
unsigned int hash;
|
||||||
struct unix_address *addr;
|
struct unix_address *addr;
|
||||||
struct hlist_head *list;
|
struct hlist_head *list;
|
||||||
|
struct path path = { NULL, NULL };
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if (sunaddr->sun_family != AF_UNIX)
|
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;
|
goto out;
|
||||||
addr_len = err;
|
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);
|
err = mutex_lock_interruptible(&u->readlock);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out_put;
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if (u->addr)
|
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);
|
atomic_set(&addr->refcnt, 1);
|
||||||
|
|
||||||
if (sun_path[0]) {
|
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;
|
addr->hash = UNIX_HASH_SIZE;
|
||||||
hash = path.dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1);
|
hash = path.dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1);
|
||||||
spin_lock(&unix_table_lock);
|
spin_lock(&unix_table_lock);
|
||||||
|
@ -1048,6 +1050,9 @@ out_unlock:
|
||||||
spin_unlock(&unix_table_lock);
|
spin_unlock(&unix_table_lock);
|
||||||
out_up:
|
out_up:
|
||||||
mutex_unlock(&u->readlock);
|
mutex_unlock(&u->readlock);
|
||||||
|
out_put:
|
||||||
|
if (err)
|
||||||
|
path_put(&path);
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue