Commit 250a25e7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull RCU-safe common_lsm_audit() from Al Viro:
 "Make common_lsm_audit() non-blocking and usable from RCU pathwalk
  context.

  We don't really need to grab/drop dentry in there - rcu_read_lock() is
  enough. There's a couple of followups using that to simplify the
  logics in selinux, but those hadn't soaked in -next yet, so they'll
  have to go in next window"

* 'work.audit' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  make dump_common_audit_data() safe to be called from RCU pathwalk
  new helper: d_find_alias_rcu()
parents 205f92d7 23d8f5b6
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -1043,6 +1043,31 @@ struct dentry *d_find_alias(struct inode *inode)
}
EXPORT_SYMBOL(d_find_alias);

/*
 *  Caller MUST be holding rcu_read_lock() and be guaranteed
 *  that inode won't get freed until rcu_read_unlock().
 */
struct dentry *d_find_alias_rcu(struct inode *inode)
{
	struct hlist_head *l = &inode->i_dentry;
	struct dentry *de = NULL;

	spin_lock(&inode->i_lock);
	// ->i_dentry and ->i_rcu are colocated, but the latter won't be
	// used without having I_FREEING set, which means no aliases left
	if (likely(!(inode->i_state & I_FREEING) && !hlist_empty(l))) {
		if (S_ISDIR(inode->i_mode)) {
			de = hlist_entry(l->first, struct dentry, d_u.d_alias);
		} else {
			hlist_for_each_entry(de, l, d_u.d_alias)
				if (!d_unhashed(de))
					break;
		}
	}
	spin_unlock(&inode->i_lock);
	return de;
}

/*
 *	Try to kill dentries associated with this inode.
 * WARNING: you must own a reference to inode.
+2 −0
Original line number Diff line number Diff line
@@ -262,6 +262,8 @@ extern void d_tmpfile(struct dentry *, struct inode *);
extern struct dentry *d_find_alias(struct inode *);
extern void d_prune_aliases(struct inode *);

extern struct dentry *d_find_alias_rcu(struct inode *);

/* test whether we have any submounts in a subdir tree */
extern int path_has_submounts(const struct path *);

+3 −2
Original line number Diff line number Diff line
@@ -291,18 +291,19 @@ static void dump_common_audit_data(struct audit_buffer *ab,
		struct dentry *dentry;
		struct inode *inode;

		rcu_read_lock();
		inode = a->u.inode;
		dentry = d_find_alias(inode);
		dentry = d_find_alias_rcu(inode);
		if (dentry) {
			audit_log_format(ab, " name=");
			spin_lock(&dentry->d_lock);
			audit_log_untrustedstring(ab, dentry->d_name.name);
			spin_unlock(&dentry->d_lock);
			dput(dentry);
		}
		audit_log_format(ab, " dev=");
		audit_log_untrustedstring(ab, inode->i_sb->s_id);
		audit_log_format(ab, " ino=%lu", inode->i_ino);
		rcu_read_unlock();
		break;
	}
	case LSM_AUDIT_DATA_TASK: {