aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2017-01-23 14:17:35 -0500
committerDavid S. Miller <davem@davemloft.net>2017-01-24 14:30:56 -0500
commit0fb44559ffd67de8517098b81f675fa0210f13f0 (patch)
tree4fe2e2d2f415b7b831e8c3ee999a1915a24d2d4e /net/unix/af_unix.c
parenta59b7e0246774e28193126fe7fdbbd0ae9c67dcc (diff)
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 <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>
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r--net/unix/af_unix.c27
1 files changed, 16 insertions, 11 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 127656ebe7be..cef79873b09d 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -995,6 +995,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
995 unsigned int hash; 995 unsigned int hash;
996 struct unix_address *addr; 996 struct unix_address *addr;
997 struct hlist_head *list; 997 struct hlist_head *list;
998 struct path path = { NULL, NULL };
998 999
999 err = -EINVAL; 1000 err = -EINVAL;
1000 if (sunaddr->sun_family != AF_UNIX) 1001 if (sunaddr->sun_family != AF_UNIX)
@@ -1010,9 +1011,20 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
1010 goto out; 1011 goto out;
1011 addr_len = err; 1012 addr_len = err;
1012 1013
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
1013 err = mutex_lock_interruptible(&u->bindlock); 1025 err = mutex_lock_interruptible(&u->bindlock);
1014 if (err) 1026 if (err)
1015 goto out; 1027 goto out_put;
1016 1028
1017 err = -EINVAL; 1029 err = -EINVAL;
1018 if (u->addr) 1030 if (u->addr)
@@ -1029,16 +1041,6 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
1029 atomic_set(&addr->refcnt, 1); 1041 atomic_set(&addr->refcnt, 1);
1030 1042
1031 if (sun_path[0]) { 1043 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 }
1042 addr->hash = UNIX_HASH_SIZE; 1044 addr->hash = UNIX_HASH_SIZE;
1043 hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1); 1045 hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);
1044 spin_lock(&unix_table_lock); 1046 spin_lock(&unix_table_lock);
@@ -1065,6 +1067,9 @@ out_unlock:
1065 spin_unlock(&unix_table_lock); 1067 spin_unlock(&unix_table_lock);
1066out_up: 1068out_up:
1067 mutex_unlock(&u->bindlock); 1069 mutex_unlock(&u->bindlock);
1070out_put:
1071 if (err)
1072 path_put(&path);
1068out: 1073out:
1069 return err; 1074 return err;
1070} 1075}