aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-09-01 17:56:49 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-04 16:29:29 -0400
commit38f7bd94a97b542de86a2be9229289717e33a7a4 (patch)
treed66b5037baec1e73674d20c179221f90ace84431 /net/unix/af_unix.c
parent2f83a53a81f5695b0f13635d411cd78367e547d6 (diff)
Revert "af_unix: Fix splice-bind deadlock"
This reverts commit c845acb324aa85a39650a14e7696982ceea75dc1. It turns out that it just replaces one deadlock with another one: we can still get the wrong lock ordering with the readlock due to overlayfs calling back into the filesystem layer and still taking the vfs locks after the readlock. The proper solution ends up being to just split the readlock into two pieces: the bind lock (taken *outside* the vfs locks) and the IO lock (taken *inside* the filesystem locks). The two locks are independent anyway. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Reviewed-by: Shmulik Ladkani <shmulik.ladkani@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.c66
1 files changed, 26 insertions, 40 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index f1dffe84f0d5..433ae1bbef97 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -954,20 +954,32 @@ fail:
954 return NULL; 954 return NULL;
955} 955}
956 956
957static int unix_mknod(struct dentry *dentry, const struct path *path, umode_t mode, 957static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
958 struct path *res)
959{ 958{
960 int err; 959 struct dentry *dentry;
960 struct path path;
961 int err = 0;
962 /*
963 * Get the parent directory, calculate the hash for last
964 * component.
965 */
966 dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
967 err = PTR_ERR(dentry);
968 if (IS_ERR(dentry))
969 return err;
961 970
962 err = security_path_mknod(path, dentry, mode, 0); 971 /*
972 * All right, let's create it.
973 */
974 err = security_path_mknod(&path, dentry, mode, 0);
963 if (!err) { 975 if (!err) {
964 err = vfs_mknod(d_inode(path->dentry), dentry, mode, 0); 976 err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0);
965 if (!err) { 977 if (!err) {
966 res->mnt = mntget(path->mnt); 978 res->mnt = mntget(path.mnt);
967 res->dentry = dget(dentry); 979 res->dentry = dget(dentry);
968 } 980 }
969 } 981 }
970 982 done_path_create(&path, dentry);
971 return err; 983 return err;
972} 984}
973 985
@@ -978,12 +990,10 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
978 struct unix_sock *u = unix_sk(sk); 990 struct unix_sock *u = unix_sk(sk);
979 struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; 991 struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
980 char *sun_path = sunaddr->sun_path; 992 char *sun_path = sunaddr->sun_path;
981 int err, name_err; 993 int err;
982 unsigned int hash; 994 unsigned int hash;
983 struct unix_address *addr; 995 struct unix_address *addr;
984 struct hlist_head *list; 996 struct hlist_head *list;
985 struct path path;
986 struct dentry *dentry;
987 997
988 err = -EINVAL; 998 err = -EINVAL;
989 if (sunaddr->sun_family != AF_UNIX) 999 if (sunaddr->sun_family != AF_UNIX)
@@ -999,34 +1009,14 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
999 goto out; 1009 goto out;
1000 addr_len = err; 1010 addr_len = err;
1001 1011
1002 name_err = 0;
1003 dentry = NULL;
1004 if (sun_path[0]) {
1005 /* Get the parent directory, calculate the hash for last
1006 * component.
1007 */
1008 dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
1009
1010 if (IS_ERR(dentry)) {
1011 /* delay report until after 'already bound' check */
1012 name_err = PTR_ERR(dentry);
1013 dentry = NULL;
1014 }
1015 }
1016
1017 err = mutex_lock_interruptible(&u->readlock); 1012 err = mutex_lock_interruptible(&u->readlock);
1018 if (err) 1013 if (err)
1019 goto out_path; 1014 goto out;
1020 1015
1021 err = -EINVAL; 1016 err = -EINVAL;
1022 if (u->addr) 1017 if (u->addr)
1023 goto out_up; 1018 goto out_up;
1024 1019
1025 if (name_err) {
1026 err = name_err == -EEXIST ? -EADDRINUSE : name_err;
1027 goto out_up;
1028 }
1029
1030 err = -ENOMEM; 1020 err = -ENOMEM;
1031 addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL); 1021 addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
1032 if (!addr) 1022 if (!addr)
@@ -1037,11 +1027,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
1037 addr->hash = hash ^ sk->sk_type; 1027 addr->hash = hash ^ sk->sk_type;
1038 atomic_set(&addr->refcnt, 1); 1028 atomic_set(&addr->refcnt, 1);
1039 1029
1040 if (dentry) { 1030 if (sun_path[0]) {
1041 struct path u_path; 1031 struct path path;
1042 umode_t mode = S_IFSOCK | 1032 umode_t mode = S_IFSOCK |
1043 (SOCK_INODE(sock)->i_mode & ~current_umask()); 1033 (SOCK_INODE(sock)->i_mode & ~current_umask());
1044 err = unix_mknod(dentry, &path, mode, &u_path); 1034 err = unix_mknod(sun_path, mode, &path);
1045 if (err) { 1035 if (err) {
1046 if (err == -EEXIST) 1036 if (err == -EEXIST)
1047 err = -EADDRINUSE; 1037 err = -EADDRINUSE;
@@ -1049,9 +1039,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
1049 goto out_up; 1039 goto out_up;
1050 } 1040 }
1051 addr->hash = UNIX_HASH_SIZE; 1041 addr->hash = UNIX_HASH_SIZE;
1052 hash = d_real_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1); 1042 hash = d_real_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);
1053 spin_lock(&unix_table_lock); 1043 spin_lock(&unix_table_lock);
1054 u->path = u_path; 1044 u->path = path;
1055 list = &unix_socket_table[hash]; 1045 list = &unix_socket_table[hash];
1056 } else { 1046 } else {
1057 spin_lock(&unix_table_lock); 1047 spin_lock(&unix_table_lock);
@@ -1074,10 +1064,6 @@ out_unlock:
1074 spin_unlock(&unix_table_lock); 1064 spin_unlock(&unix_table_lock);
1075out_up: 1065out_up:
1076 mutex_unlock(&u->readlock); 1066 mutex_unlock(&u->readlock);
1077out_path:
1078 if (dentry)
1079 done_path_create(&path, dentry);
1080
1081out: 1067out:
1082 return err; 1068 return err;
1083} 1069}