]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.18 patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Feb 2017 21:28:47 +0000 (22:28 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Feb 2017 21:28:47 +0000 (22:28 +0100)
queue-3.18/revert-af_unix-fix-splice-bind-deadlock.patch [new file with mode: 0644]
queue-3.18/series

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 (file)
index 0000000..5216fb7
--- /dev/null
@@ -0,0 +1,161 @@
+From 38f7bd94a97b542de86a2be9229289717e33a7a4 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Thu, 1 Sep 2016 14:56:49 -0700
+Subject: Revert "af_unix: Fix splice-bind deadlock"
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+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 <torvalds@linux-foundation.org>
+Reviewed-by: Shmulik Ladkani <shmulik.ladkani@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
+ }
index f896acbf3548b2a00242575d417b53a11e3ccea8..5c9d7fb50820b6e3cc84598326c1d58c000261c1 100644 (file)
@@ -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