fix breakage caused by d_find_alias() semantics change

"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 # f1ee616214 "VFS: don't keep disconnected dentries on d_anon"
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2018-04-25 10:28:38 -04:00
parent 79f546a696
commit b127125d9d

View 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. */ /* Called from d_instantiate or d_splice_alias. */
dentry = dget(opt_dentry); dentry = dget(opt_dentry);
} else { } 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); dentry = d_find_alias(inode);
if (!dentry)
dentry = d_find_any_alias(inode);
} }
if (!dentry) { 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)) { if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
/* We must have a dentry to determine the label on /* We must have a dentry to determine the label on
* procfs inodes */ * procfs inodes */
if (opt_dentry) if (opt_dentry) {
/* Called from d_instantiate or /* Called from d_instantiate or
* d_splice_alias. */ * d_splice_alias. */
dentry = dget(opt_dentry); dentry = dget(opt_dentry);
else } else {
/* Called from selinux_complete_init, try to /* 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); dentry = d_find_alias(inode);
if (!dentry)
dentry = d_find_any_alias(inode);
}
/* /*
* This can be hit on boot when a file is accessed * This can be hit on boot when a file is accessed
* before the policy is loaded. When we load policy we * before the policy is loaded. When we load policy we