From f86d6c0b04d31c3aed14ed7f9fac14def4d5dba7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 28 Feb 2017 22:28:47 +0100 Subject: [PATCH] 3.18 patches --- ...ert-af_unix-fix-splice-bind-deadlock.patch | 161 ++++++++++++++++++ queue-3.18/series | 1 + 2 files changed, 162 insertions(+) create mode 100644 queue-3.18/revert-af_unix-fix-splice-bind-deadlock.patch diff --git a/queue-3.18/revert-af_unix-fix-splice-bind-deadlock.patch b/queue-3.18/revert-af_unix-fix-splice-bind-deadlock.patch new file mode 100644 index 00000000000..5216fb72d2c --- /dev/null +++ b/queue-3.18/revert-af_unix-fix-splice-bind-deadlock.patch @@ -0,0 +1,161 @@ +From 38f7bd94a97b542de86a2be9229289717e33a7a4 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Thu, 1 Sep 2016 14:56:49 -0700 +Subject: Revert "af_unix: Fix splice-bind deadlock" + +From: Linus Torvalds + +commit 38f7bd94a97b542de86a2be9229289717e33a7a4 upstream. + +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 +Reviewed-by: Shmulik Ladkani +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/unix/af_unix.c | 68 +++++++++++++++++++++-------------------------------- + 1 file changed, 27 insertions(+), 41 deletions(-) + +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -940,20 +940,32 @@ fail: + return NULL; + } + +-static int unix_mknod(struct dentry *dentry, struct path *path, umode_t mode, +- struct path *res) ++static int unix_mknod(const char *sun_path, umode_t mode, struct path *res) + { +- int err; +- +- err = security_path_mknod(path, dentry, mode, 0); ++ struct dentry *dentry; ++ struct path path; ++ int err = 0; ++ /* ++ * Get the parent directory, calculate the hash for last ++ * component. ++ */ ++ dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); ++ err = PTR_ERR(dentry); ++ if (IS_ERR(dentry)) ++ return err; ++ ++ /* ++ * All right, let's create it. ++ */ ++ err = security_path_mknod(&path, dentry, mode, 0); + if (!err) { +- err = vfs_mknod(d_inode(path->dentry), dentry, mode, 0); ++ err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0); + if (!err) { +- res->mnt = mntget(path->mnt); ++ res->mnt = mntget(path.mnt); + res->dentry = dget(dentry); + } + } +- ++ done_path_create(&path, dentry); + return err; + } + +@@ -964,12 +976,10 @@ static int unix_bind(struct socket *sock + struct unix_sock *u = unix_sk(sk); + struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; + char *sun_path = sunaddr->sun_path; +- int err, name_err; ++ int err; + unsigned int hash; + struct unix_address *addr; + struct hlist_head *list; +- struct path path; +- struct dentry *dentry; + + err = -EINVAL; + if (sunaddr->sun_family != AF_UNIX) +@@ -985,34 +995,14 @@ static int unix_bind(struct socket *sock + goto out; + addr_len = err; + +- name_err = 0; +- dentry = NULL; +- if (sun_path[0]) { +- /* Get the parent directory, calculate the hash for last +- * component. +- */ +- dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); +- +- if (IS_ERR(dentry)) { +- /* delay report until after 'already bound' check */ +- name_err = PTR_ERR(dentry); +- dentry = NULL; +- } +- } +- + err = mutex_lock_interruptible(&u->readlock); + if (err) +- goto out_path; ++ goto out; + + err = -EINVAL; + if (u->addr) + goto out_up; + +- if (name_err) { +- err = name_err == -EEXIST ? -EADDRINUSE : name_err; +- goto out_up; +- } +- + err = -ENOMEM; + addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL); + if (!addr) +@@ -1023,11 +1013,11 @@ static int unix_bind(struct socket *sock + addr->hash = hash ^ sk->sk_type; + atomic_set(&addr->refcnt, 1); + +- if (dentry) { +- struct path u_path; ++ if (sun_path[0]) { ++ struct path path; + umode_t mode = S_IFSOCK | + (SOCK_INODE(sock)->i_mode & ~current_umask()); +- err = unix_mknod(dentry, &path, mode, &u_path); ++ err = unix_mknod(sun_path, mode, &path); + if (err) { + if (err == -EEXIST) + err = -EADDRINUSE; +@@ -1035,9 +1025,9 @@ static int unix_bind(struct socket *sock + goto out_up; + } + addr->hash = UNIX_HASH_SIZE; +- hash = d_backing_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1); ++ hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE-1); + spin_lock(&unix_table_lock); +- u->path = u_path; ++ u->path = path; + list = &unix_socket_table[hash]; + } else { + spin_lock(&unix_table_lock); +@@ -1060,10 +1050,6 @@ out_unlock: + spin_unlock(&unix_table_lock); + out_up: + mutex_unlock(&u->readlock); +-out_path: +- if (dentry) +- done_path_create(&path, dentry); +- + out: + return err; + } diff --git a/queue-3.18/series b/queue-3.18/series index f896acbf354..5c9d7fb5082 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -1,3 +1,4 @@ +revert-af_unix-fix-splice-bind-deadlock.patch can-fix-kernel-panic-at-security_sock_rcv_skb.patch ipv6-fix-ip6_tnl_parse_tlv_enc_lim.patch ipv6-pointer-math-error-in-ip6_tnl_parse_tlv_enc_lim.patch -- 2.47.3