fix breakage caused by d_find_alias() semantics change
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 25 Apr 2018 14:28:38 +0000 (10:28 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 13 May 2018 19:47:58 +0000 (15:47 -0400)
"VFS: don't keep disconnected dentries on d_anon" had a non-trivial
side-effect - d_unhashed() now returns true for those dentries,
making d_find_alias() skip them altogether.  For most of its callers
that's fine - we really want a connected alias there.  However,
there is a codepath where we relied upon picking such aliases
if nothing else could be found - selinux delayed initialization
of contexts for inodes on already mounted filesystems used to
rely upon that.

Cc: stable@kernel.org # f1ee616214cb "VFS: don't keep disconnected dentries on d_anon"
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
security/selinux/hooks.c

index 4cafe6a..398d165 100644 (file)
@@ -1568,8 +1568,15 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        /* Called from d_instantiate or d_splice_alias. */
                        dentry = dget(opt_dentry);
                } else {
-                       /* Called from selinux_complete_init, try to find a dentry. */
+                       /*
+                        * Called from selinux_complete_init, try to find a dentry.
+                        * Some filesystems really want a connected one, so try
+                        * that first.  We could split SECURITY_FS_USE_XATTR in
+                        * two, depending upon that...
+                        */
                        dentry = d_find_alias(inode);
+                       if (!dentry)
+                               dentry = d_find_any_alias(inode);
                }
                if (!dentry) {
                        /*
@@ -1674,14 +1681,19 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
                        /* We must have a dentry to determine the label on
                         * procfs inodes */
-                       if (opt_dentry)
+                       if (opt_dentry) {
                                /* Called from d_instantiate or
                                 * d_splice_alias. */
                                dentry = dget(opt_dentry);
-                       else
+                       } else {
                                /* Called from selinux_complete_init, try to
-                                * find a dentry. */
+                                * find a dentry.  Some filesystems really want
+                                * a connected one, so try that first.
+                                */
                                dentry = d_find_alias(inode);
+                               if (!dentry)
+                                       dentry = d_find_any_alias(inode);
+                       }
                        /*
                         * This can be hit on boot when a file is accessed
                         * before the policy is loaded.  When we load policy we