Skip to content

Commit 0492a03

Browse files
congwanggregkh
authored andcommitted
af_unix: move unix_mknod() out of bindlock
[ 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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent e674c70 commit 0492a03

1 file changed

Lines changed: 16 additions & 11 deletions

File tree

net/unix/af_unix.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
994994
unsigned int hash;
995995
struct unix_address *addr;
996996
struct hlist_head *list;
997+
struct path path = { NULL, NULL };
997998

998999
err = -EINVAL;
9991000
if (sunaddr->sun_family != AF_UNIX)
@@ -1009,9 +1010,20 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
10091010
goto out;
10101011
addr_len = err;
10111012

1013+
if (sun_path[0]) {
1014+
umode_t mode = S_IFSOCK |
1015+
(SOCK_INODE(sock)->i_mode & ~current_umask());
1016+
err = unix_mknod(sun_path, mode, &path);
1017+
if (err) {
1018+
if (err == -EEXIST)
1019+
err = -EADDRINUSE;
1020+
goto out;
1021+
}
1022+
}
1023+
10121024
err = mutex_lock_interruptible(&u->bindlock);
10131025
if (err)
1014-
goto out;
1026+
goto out_put;
10151027

10161028
err = -EINVAL;
10171029
if (u->addr)
@@ -1028,16 +1040,6 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
10281040
atomic_set(&addr->refcnt, 1);
10291041

10301042
if (sun_path[0]) {
1031-
struct path path;
1032-
umode_t mode = S_IFSOCK |
1033-
(SOCK_INODE(sock)->i_mode & ~current_umask());
1034-
err = unix_mknod(sun_path, mode, &path);
1035-
if (err) {
1036-
if (err == -EEXIST)
1037-
err = -EADDRINUSE;
1038-
unix_release_addr(addr);
1039-
goto out_up;
1040-
}
10411043
addr->hash = UNIX_HASH_SIZE;
10421044
hash = d_real_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);
10431045
spin_lock(&unix_table_lock);
@@ -1064,6 +1066,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
10641066
spin_unlock(&unix_table_lock);
10651067
out_up:
10661068
mutex_unlock(&u->bindlock);
1069+
out_put:
1070+
if (err)
1071+
path_put(&path);
10671072
out:
10681073
return err;
10691074
}

0 commit comments

Comments
 (0)