Commit 250a25e7 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'work.audit' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

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
...@@ -1043,6 +1043,31 @@ struct dentry *d_find_alias(struct inode *inode) ...@@ -1043,6 +1043,31 @@ struct dentry *d_find_alias(struct inode *inode)
} }
EXPORT_SYMBOL(d_find_alias); 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. * Try to kill dentries associated with this inode.
* WARNING: you must own a reference to inode. * WARNING: you must own a reference to inode.
......
...@@ -262,6 +262,8 @@ extern void d_tmpfile(struct dentry *, struct inode *); ...@@ -262,6 +262,8 @@ extern void d_tmpfile(struct dentry *, struct inode *);
extern struct dentry *d_find_alias(struct inode *); extern struct dentry *d_find_alias(struct inode *);
extern void d_prune_aliases(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 */ /* test whether we have any submounts in a subdir tree */
extern int path_has_submounts(const struct path *); extern int path_has_submounts(const struct path *);
......
...@@ -291,18 +291,19 @@ static void dump_common_audit_data(struct audit_buffer *ab, ...@@ -291,18 +291,19 @@ static void dump_common_audit_data(struct audit_buffer *ab,
struct dentry *dentry; struct dentry *dentry;
struct inode *inode; struct inode *inode;
rcu_read_lock();
inode = a->u.inode; inode = a->u.inode;
dentry = d_find_alias(inode); dentry = d_find_alias_rcu(inode);
if (dentry) { if (dentry) {
audit_log_format(ab, " name="); audit_log_format(ab, " name=");
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
audit_log_untrustedstring(ab, dentry->d_name.name); audit_log_untrustedstring(ab, dentry->d_name.name);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
dput(dentry);
} }
audit_log_format(ab, " dev="); audit_log_format(ab, " dev=");
audit_log_untrustedstring(ab, inode->i_sb->s_id); audit_log_untrustedstring(ab, inode->i_sb->s_id);
audit_log_format(ab, " ino=%lu", inode->i_ino); audit_log_format(ab, " ino=%lu", inode->i_ino);
rcu_read_unlock();
break; break;
} }
case LSM_AUDIT_DATA_TASK: { case LSM_AUDIT_DATA_TASK: {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment