]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.3-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 11 Nov 2019 08:48:29 +0000 (09:48 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 11 Nov 2019 08:48:29 +0000 (09:48 +0100)
added patches:
configfs-fix-a-deadlock-in-configfs_symlink.patch

queue-5.3/configfs-fix-a-deadlock-in-configfs_symlink.patch [new file with mode: 0644]
queue-5.3/series

diff --git a/queue-5.3/configfs-fix-a-deadlock-in-configfs_symlink.patch b/queue-5.3/configfs-fix-a-deadlock-in-configfs_symlink.patch
new file mode 100644 (file)
index 0000000..20896a9
--- /dev/null
@@ -0,0 +1,81 @@
+From 351e5d869e5ac10cb40c78b5f2d7dfc816ad4587 Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Sat, 3 Aug 2019 11:51:18 -0400
+Subject: configfs: fix a deadlock in configfs_symlink()
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+commit 351e5d869e5ac10cb40c78b5f2d7dfc816ad4587 upstream.
+
+Configfs abuses symlink(2).  Unlike the normal filesystems, it
+wants the target resolved at symlink(2) time, like link(2) would've
+done.  The problem is that ->symlink() is called with the parent
+directory locked exclusive, so resolving the target inside the
+->symlink() is easily deadlocked.
+
+Short of really ugly games in sys_symlink() itself, all we can
+do is to unlock the parent before resolving the target and
+relock it after.  However, that invalidates the checks done
+by the caller of ->symlink(), so we have to
+       * check that dentry is still where it used to be
+(it couldn't have been moved, but it could've been unhashed)
+       * recheck that it's still negative (somebody else
+might've successfully created a symlink with the same name
+while we were looking the target up)
+       * recheck the permissions on the parent directory.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/configfs/symlink.c |   33 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 32 insertions(+), 1 deletion(-)
+
+--- a/fs/configfs/symlink.c
++++ b/fs/configfs/symlink.c
+@@ -143,11 +143,42 @@ int configfs_symlink(struct inode *dir,
+           !type->ct_item_ops->allow_link)
+               goto out_put;
++      /*
++       * This is really sick.  What they wanted was a hybrid of
++       * link(2) and symlink(2) - they wanted the target resolved
++       * at syscall time (as link(2) would've done), be a directory
++       * (which link(2) would've refused to do) *AND* be a deep
++       * fucking magic, making the target busy from rmdir POV.
++       * symlink(2) is nothing of that sort, and the locking it
++       * gets matches the normal symlink(2) semantics.  Without
++       * attempts to resolve the target (which might very well
++       * not even exist yet) done prior to locking the parent
++       * directory.  This perversion, OTOH, needs to resolve
++       * the target, which would lead to obvious deadlocks if
++       * attempted with any directories locked.
++       *
++       * Unfortunately, that garbage is userland ABI and we should've
++       * said "no" back in 2005.  Too late now, so we get to
++       * play very ugly games with locking.
++       *
++       * Try *ANYTHING* of that sort in new code, and you will
++       * really regret it.  Just ask yourself - what could a BOFH
++       * do to me and do I want to find it out first-hand?
++       *
++       *  AV, a thoroughly annoyed bastard.
++       */
++      inode_unlock(dir);
+       ret = get_target(symname, &path, &target_item, dentry->d_sb);
++      inode_lock(dir);
+       if (ret)
+               goto out_put;
+-      ret = type->ct_item_ops->allow_link(parent_item, target_item);
++      if (dentry->d_inode || d_unhashed(dentry))
++              ret = -EEXIST;
++      else
++              ret = inode_permission(dir, MAY_WRITE | MAY_EXEC);
++      if (!ret)
++              ret = type->ct_item_ops->allow_link(parent_item, target_item);
+       if (!ret) {
+               mutex_lock(&configfs_symlink_mutex);
+               ret = create_link(parent_item, target_item, dentry);
index 47ccceca0db60963f3b25af451a4c989f7b32ffb..7e3dc8be3c7411d436e6e5c3c4597a95fab43189 100644 (file)
@@ -78,3 +78,4 @@ can-gs_usb-gs_can_open-prevent-memory-leak.patch
 can-dev-add-missing-of_node_put-after-calling-of_get_child_by_name.patch
 can-mcba_usb-fix-use-after-free-on-disconnect.patch
 can-peak_usb-fix-slab-info-leak.patch
+configfs-fix-a-deadlock-in-configfs_symlink.patch