Skip to content

Commit 0fb4455

Browse files
congwangdavem330
authored andcommitted
af_unix: move unix_mknod() out of bindlock
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 <[email protected]> Tested-by: Dmitry Vyukov <[email protected]> Cc: Rainer Weikusat <[email protected]> Cc: Al Viro <[email protected]> Signed-off-by: Cong Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a59b7e0 commit 0fb4455

File tree

1 file changed

+16
-11
lines changed

1 file changed

+16
-11
lines changed

net/unix/af_unix.c

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

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

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

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

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

0 commit comments

Comments
 (0)