xref: /openbmc/linux/kernel/audit_tree.c (revision e61ce867)
174c3cbe3SAl Viro #include "audit.h"
228a3a7ebSEric Paris #include <linux/fsnotify_backend.h>
374c3cbe3SAl Viro #include <linux/namei.h>
474c3cbe3SAl Viro #include <linux/mount.h>
5916d7576SAl Viro #include <linux/kthread.h>
65a0e3ad6STejun Heo #include <linux/slab.h>
774c3cbe3SAl Viro 
874c3cbe3SAl Viro struct audit_tree;
974c3cbe3SAl Viro struct audit_chunk;
1074c3cbe3SAl Viro 
1174c3cbe3SAl Viro struct audit_tree {
1274c3cbe3SAl Viro 	atomic_t count;
1374c3cbe3SAl Viro 	int goner;
1474c3cbe3SAl Viro 	struct audit_chunk *root;
1574c3cbe3SAl Viro 	struct list_head chunks;
1674c3cbe3SAl Viro 	struct list_head rules;
1774c3cbe3SAl Viro 	struct list_head list;
1874c3cbe3SAl Viro 	struct list_head same_root;
1974c3cbe3SAl Viro 	struct rcu_head head;
2074c3cbe3SAl Viro 	char pathname[];
2174c3cbe3SAl Viro };
2274c3cbe3SAl Viro 
2374c3cbe3SAl Viro struct audit_chunk {
2474c3cbe3SAl Viro 	struct list_head hash;
25e61ce867SEric Paris 	struct fsnotify_mark mark;
2674c3cbe3SAl Viro 	struct list_head trees;		/* with root here */
2774c3cbe3SAl Viro 	int dead;
2874c3cbe3SAl Viro 	int count;
298f7b0ba1SAl Viro 	atomic_long_t refs;
3074c3cbe3SAl Viro 	struct rcu_head head;
3174c3cbe3SAl Viro 	struct node {
3274c3cbe3SAl Viro 		struct list_head list;
3374c3cbe3SAl Viro 		struct audit_tree *owner;
3474c3cbe3SAl Viro 		unsigned index;		/* index; upper bit indicates 'will prune' */
3574c3cbe3SAl Viro 	} owners[];
3674c3cbe3SAl Viro };
3774c3cbe3SAl Viro 
3874c3cbe3SAl Viro static LIST_HEAD(tree_list);
3974c3cbe3SAl Viro static LIST_HEAD(prune_list);
4074c3cbe3SAl Viro 
4174c3cbe3SAl Viro /*
4274c3cbe3SAl Viro  * One struct chunk is attached to each inode of interest.
4374c3cbe3SAl Viro  * We replace struct chunk on tagging/untagging.
4474c3cbe3SAl Viro  * Rules have pointer to struct audit_tree.
4574c3cbe3SAl Viro  * Rules have struct list_head rlist forming a list of rules over
4674c3cbe3SAl Viro  * the same tree.
4774c3cbe3SAl Viro  * References to struct chunk are collected at audit_inode{,_child}()
4874c3cbe3SAl Viro  * time and used in AUDIT_TREE rule matching.
4974c3cbe3SAl Viro  * These references are dropped at the same time we are calling
5074c3cbe3SAl Viro  * audit_free_names(), etc.
5174c3cbe3SAl Viro  *
5274c3cbe3SAl Viro  * Cyclic lists galore:
5374c3cbe3SAl Viro  * tree.chunks anchors chunk.owners[].list			hash_lock
5474c3cbe3SAl Viro  * tree.rules anchors rule.rlist				audit_filter_mutex
5574c3cbe3SAl Viro  * chunk.trees anchors tree.same_root				hash_lock
5674c3cbe3SAl Viro  * chunk.hash is a hash with middle bits of watch.inode as
5774c3cbe3SAl Viro  * a hash function.						RCU, hash_lock
5874c3cbe3SAl Viro  *
5974c3cbe3SAl Viro  * tree is refcounted; one reference for "some rules on rules_list refer to
6074c3cbe3SAl Viro  * it", one for each chunk with pointer to it.
6174c3cbe3SAl Viro  *
6228a3a7ebSEric Paris  * chunk is refcounted by embedded fsnotify_mark + .refs (non-zero refcount
638f7b0ba1SAl Viro  * of watch contributes 1 to .refs).
6474c3cbe3SAl Viro  *
6574c3cbe3SAl Viro  * node.index allows to get from node.list to containing chunk.
6674c3cbe3SAl Viro  * MSB of that sucker is stolen to mark taggings that we might have to
6774c3cbe3SAl Viro  * revert - several operations have very unpleasant cleanup logics and
6874c3cbe3SAl Viro  * that makes a difference.  Some.
6974c3cbe3SAl Viro  */
7074c3cbe3SAl Viro 
7128a3a7ebSEric Paris static struct fsnotify_group *audit_tree_group;
7274c3cbe3SAl Viro 
7374c3cbe3SAl Viro static struct audit_tree *alloc_tree(const char *s)
7474c3cbe3SAl Viro {
7574c3cbe3SAl Viro 	struct audit_tree *tree;
7674c3cbe3SAl Viro 
7774c3cbe3SAl Viro 	tree = kmalloc(sizeof(struct audit_tree) + strlen(s) + 1, GFP_KERNEL);
7874c3cbe3SAl Viro 	if (tree) {
7974c3cbe3SAl Viro 		atomic_set(&tree->count, 1);
8074c3cbe3SAl Viro 		tree->goner = 0;
8174c3cbe3SAl Viro 		INIT_LIST_HEAD(&tree->chunks);
8274c3cbe3SAl Viro 		INIT_LIST_HEAD(&tree->rules);
8374c3cbe3SAl Viro 		INIT_LIST_HEAD(&tree->list);
8474c3cbe3SAl Viro 		INIT_LIST_HEAD(&tree->same_root);
8574c3cbe3SAl Viro 		tree->root = NULL;
8674c3cbe3SAl Viro 		strcpy(tree->pathname, s);
8774c3cbe3SAl Viro 	}
8874c3cbe3SAl Viro 	return tree;
8974c3cbe3SAl Viro }
9074c3cbe3SAl Viro 
9174c3cbe3SAl Viro static inline void get_tree(struct audit_tree *tree)
9274c3cbe3SAl Viro {
9374c3cbe3SAl Viro 	atomic_inc(&tree->count);
9474c3cbe3SAl Viro }
9574c3cbe3SAl Viro 
9674c3cbe3SAl Viro static void __put_tree(struct rcu_head *rcu)
9774c3cbe3SAl Viro {
9874c3cbe3SAl Viro 	struct audit_tree *tree = container_of(rcu, struct audit_tree, head);
9974c3cbe3SAl Viro 	kfree(tree);
10074c3cbe3SAl Viro }
10174c3cbe3SAl Viro 
10274c3cbe3SAl Viro static inline void put_tree(struct audit_tree *tree)
10374c3cbe3SAl Viro {
10474c3cbe3SAl Viro 	if (atomic_dec_and_test(&tree->count))
10574c3cbe3SAl Viro 		call_rcu(&tree->head, __put_tree);
10674c3cbe3SAl Viro }
10774c3cbe3SAl Viro 
10874c3cbe3SAl Viro /* to avoid bringing the entire thing in audit.h */
10974c3cbe3SAl Viro const char *audit_tree_path(struct audit_tree *tree)
11074c3cbe3SAl Viro {
11174c3cbe3SAl Viro 	return tree->pathname;
11274c3cbe3SAl Viro }
11374c3cbe3SAl Viro 
1148f7b0ba1SAl Viro static void free_chunk(struct audit_chunk *chunk)
11574c3cbe3SAl Viro {
11674c3cbe3SAl Viro 	int i;
11774c3cbe3SAl Viro 
11874c3cbe3SAl Viro 	for (i = 0; i < chunk->count; i++) {
11974c3cbe3SAl Viro 		if (chunk->owners[i].owner)
12074c3cbe3SAl Viro 			put_tree(chunk->owners[i].owner);
12174c3cbe3SAl Viro 	}
12274c3cbe3SAl Viro 	kfree(chunk);
12374c3cbe3SAl Viro }
12474c3cbe3SAl Viro 
12574c3cbe3SAl Viro void audit_put_chunk(struct audit_chunk *chunk)
12674c3cbe3SAl Viro {
1278f7b0ba1SAl Viro 	if (atomic_long_dec_and_test(&chunk->refs))
1288f7b0ba1SAl Viro 		free_chunk(chunk);
1298f7b0ba1SAl Viro }
1308f7b0ba1SAl Viro 
1318f7b0ba1SAl Viro static void __put_chunk(struct rcu_head *rcu)
1328f7b0ba1SAl Viro {
1338f7b0ba1SAl Viro 	struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
1348f7b0ba1SAl Viro 	audit_put_chunk(chunk);
13574c3cbe3SAl Viro }
13674c3cbe3SAl Viro 
137e61ce867SEric Paris static void audit_tree_destroy_watch(struct fsnotify_mark *entry)
13828a3a7ebSEric Paris {
13928a3a7ebSEric Paris 	struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
14028a3a7ebSEric Paris 	call_rcu(&chunk->head, __put_chunk);
14128a3a7ebSEric Paris }
14228a3a7ebSEric Paris 
14328a3a7ebSEric Paris static struct audit_chunk *alloc_chunk(int count)
14428a3a7ebSEric Paris {
14528a3a7ebSEric Paris 	struct audit_chunk *chunk;
14628a3a7ebSEric Paris 	size_t size;
14728a3a7ebSEric Paris 	int i;
14828a3a7ebSEric Paris 
14928a3a7ebSEric Paris 	size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
15028a3a7ebSEric Paris 	chunk = kzalloc(size, GFP_KERNEL);
15128a3a7ebSEric Paris 	if (!chunk)
15228a3a7ebSEric Paris 		return NULL;
15328a3a7ebSEric Paris 
15428a3a7ebSEric Paris 	INIT_LIST_HEAD(&chunk->hash);
15528a3a7ebSEric Paris 	INIT_LIST_HEAD(&chunk->trees);
15628a3a7ebSEric Paris 	chunk->count = count;
15728a3a7ebSEric Paris 	atomic_long_set(&chunk->refs, 1);
15828a3a7ebSEric Paris 	for (i = 0; i < count; i++) {
15928a3a7ebSEric Paris 		INIT_LIST_HEAD(&chunk->owners[i].list);
16028a3a7ebSEric Paris 		chunk->owners[i].index = i;
16128a3a7ebSEric Paris 	}
16228a3a7ebSEric Paris 	fsnotify_init_mark(&chunk->mark, audit_tree_destroy_watch);
16328a3a7ebSEric Paris 	return chunk;
16428a3a7ebSEric Paris }
16528a3a7ebSEric Paris 
16674c3cbe3SAl Viro enum {HASH_SIZE = 128};
16774c3cbe3SAl Viro static struct list_head chunk_hash_heads[HASH_SIZE];
16874c3cbe3SAl Viro static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock);
16974c3cbe3SAl Viro 
17074c3cbe3SAl Viro static inline struct list_head *chunk_hash(const struct inode *inode)
17174c3cbe3SAl Viro {
17274c3cbe3SAl Viro 	unsigned long n = (unsigned long)inode / L1_CACHE_BYTES;
17374c3cbe3SAl Viro 	return chunk_hash_heads + n % HASH_SIZE;
17474c3cbe3SAl Viro }
17574c3cbe3SAl Viro 
17628a3a7ebSEric Paris /* hash_lock & entry->lock is held by caller */
17774c3cbe3SAl Viro static void insert_hash(struct audit_chunk *chunk)
17874c3cbe3SAl Viro {
179e61ce867SEric Paris 	struct fsnotify_mark *entry = &chunk->mark;
18028a3a7ebSEric Paris 	struct list_head *list;
18128a3a7ebSEric Paris 
1822823e04dSEric Paris 	if (!entry->i.inode)
18328a3a7ebSEric Paris 		return;
1842823e04dSEric Paris 	list = chunk_hash(entry->i.inode);
18574c3cbe3SAl Viro 	list_add_rcu(&chunk->hash, list);
18674c3cbe3SAl Viro }
18774c3cbe3SAl Viro 
18874c3cbe3SAl Viro /* called under rcu_read_lock */
18974c3cbe3SAl Viro struct audit_chunk *audit_tree_lookup(const struct inode *inode)
19074c3cbe3SAl Viro {
19174c3cbe3SAl Viro 	struct list_head *list = chunk_hash(inode);
1926793a051SPaul E. McKenney 	struct audit_chunk *p;
19374c3cbe3SAl Viro 
1946793a051SPaul E. McKenney 	list_for_each_entry_rcu(p, list, hash) {
19528a3a7ebSEric Paris 		/* mark.inode may have gone NULL, but who cares? */
1962823e04dSEric Paris 		if (p->mark.i.inode == inode) {
1978f7b0ba1SAl Viro 			atomic_long_inc(&p->refs);
19874c3cbe3SAl Viro 			return p;
19974c3cbe3SAl Viro 		}
20074c3cbe3SAl Viro 	}
20174c3cbe3SAl Viro 	return NULL;
20274c3cbe3SAl Viro }
20374c3cbe3SAl Viro 
20474c3cbe3SAl Viro int audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
20574c3cbe3SAl Viro {
20674c3cbe3SAl Viro 	int n;
20774c3cbe3SAl Viro 	for (n = 0; n < chunk->count; n++)
20874c3cbe3SAl Viro 		if (chunk->owners[n].owner == tree)
20974c3cbe3SAl Viro 			return 1;
21074c3cbe3SAl Viro 	return 0;
21174c3cbe3SAl Viro }
21274c3cbe3SAl Viro 
21374c3cbe3SAl Viro /* tagging and untagging inodes with trees */
21474c3cbe3SAl Viro 
2158f7b0ba1SAl Viro static struct audit_chunk *find_chunk(struct node *p)
21674c3cbe3SAl Viro {
2178f7b0ba1SAl Viro 	int index = p->index & ~(1U<<31);
2188f7b0ba1SAl Viro 	p -= index;
2198f7b0ba1SAl Viro 	return container_of(p, struct audit_chunk, owners[0]);
2208f7b0ba1SAl Viro }
2218f7b0ba1SAl Viro 
2228f7b0ba1SAl Viro static void untag_chunk(struct node *p)
2238f7b0ba1SAl Viro {
2248f7b0ba1SAl Viro 	struct audit_chunk *chunk = find_chunk(p);
225e61ce867SEric Paris 	struct fsnotify_mark *entry = &chunk->mark;
22674c3cbe3SAl Viro 	struct audit_chunk *new;
22774c3cbe3SAl Viro 	struct audit_tree *owner;
22874c3cbe3SAl Viro 	int size = chunk->count - 1;
22974c3cbe3SAl Viro 	int i, j;
23074c3cbe3SAl Viro 
23128a3a7ebSEric Paris 	fsnotify_get_mark(entry);
2328f7b0ba1SAl Viro 
2338f7b0ba1SAl Viro 	spin_unlock(&hash_lock);
2348f7b0ba1SAl Viro 
23528a3a7ebSEric Paris 	spin_lock(&entry->lock);
2362823e04dSEric Paris 	if (chunk->dead || !entry->i.inode) {
23728a3a7ebSEric Paris 		spin_unlock(&entry->lock);
2388f7b0ba1SAl Viro 		goto out;
23974c3cbe3SAl Viro 	}
24074c3cbe3SAl Viro 
24174c3cbe3SAl Viro 	owner = p->owner;
24274c3cbe3SAl Viro 
24374c3cbe3SAl Viro 	if (!size) {
24474c3cbe3SAl Viro 		chunk->dead = 1;
24574c3cbe3SAl Viro 		spin_lock(&hash_lock);
24674c3cbe3SAl Viro 		list_del_init(&chunk->trees);
24774c3cbe3SAl Viro 		if (owner->root == chunk)
24874c3cbe3SAl Viro 			owner->root = NULL;
24974c3cbe3SAl Viro 		list_del_init(&p->list);
25074c3cbe3SAl Viro 		list_del_rcu(&chunk->hash);
25174c3cbe3SAl Viro 		spin_unlock(&hash_lock);
25228a3a7ebSEric Paris 		spin_unlock(&entry->lock);
25328a3a7ebSEric Paris 		fsnotify_destroy_mark_by_entry(entry);
25428a3a7ebSEric Paris 		fsnotify_put_mark(entry);
2558f7b0ba1SAl Viro 		goto out;
25674c3cbe3SAl Viro 	}
25774c3cbe3SAl Viro 
25874c3cbe3SAl Viro 	new = alloc_chunk(size);
25974c3cbe3SAl Viro 	if (!new)
26074c3cbe3SAl Viro 		goto Fallback;
26128a3a7ebSEric Paris 	fsnotify_duplicate_mark(&new->mark, entry);
2622823e04dSEric Paris 	if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, 1)) {
26374c3cbe3SAl Viro 		free_chunk(new);
26474c3cbe3SAl Viro 		goto Fallback;
26574c3cbe3SAl Viro 	}
26674c3cbe3SAl Viro 
26774c3cbe3SAl Viro 	chunk->dead = 1;
26874c3cbe3SAl Viro 	spin_lock(&hash_lock);
26974c3cbe3SAl Viro 	list_replace_init(&chunk->trees, &new->trees);
27074c3cbe3SAl Viro 	if (owner->root == chunk) {
27174c3cbe3SAl Viro 		list_del_init(&owner->same_root);
27274c3cbe3SAl Viro 		owner->root = NULL;
27374c3cbe3SAl Viro 	}
27474c3cbe3SAl Viro 
2756f5d5114SAl Viro 	for (i = j = 0; j <= size; i++, j++) {
27674c3cbe3SAl Viro 		struct audit_tree *s;
27774c3cbe3SAl Viro 		if (&chunk->owners[j] == p) {
27874c3cbe3SAl Viro 			list_del_init(&p->list);
27974c3cbe3SAl Viro 			i--;
28074c3cbe3SAl Viro 			continue;
28174c3cbe3SAl Viro 		}
28274c3cbe3SAl Viro 		s = chunk->owners[j].owner;
28374c3cbe3SAl Viro 		new->owners[i].owner = s;
28474c3cbe3SAl Viro 		new->owners[i].index = chunk->owners[j].index - j + i;
28574c3cbe3SAl Viro 		if (!s) /* result of earlier fallback */
28674c3cbe3SAl Viro 			continue;
28774c3cbe3SAl Viro 		get_tree(s);
2886f5d5114SAl Viro 		list_replace_init(&chunk->owners[j].list, &new->owners[i].list);
28974c3cbe3SAl Viro 	}
29074c3cbe3SAl Viro 
29174c3cbe3SAl Viro 	list_replace_rcu(&chunk->hash, &new->hash);
29274c3cbe3SAl Viro 	list_for_each_entry(owner, &new->trees, same_root)
29374c3cbe3SAl Viro 		owner->root = new;
29474c3cbe3SAl Viro 	spin_unlock(&hash_lock);
29528a3a7ebSEric Paris 	spin_unlock(&entry->lock);
29628a3a7ebSEric Paris 	fsnotify_destroy_mark_by_entry(entry);
29728a3a7ebSEric Paris 	fsnotify_put_mark(entry);
2988f7b0ba1SAl Viro 	goto out;
29974c3cbe3SAl Viro 
30074c3cbe3SAl Viro Fallback:
30174c3cbe3SAl Viro 	// do the best we can
30274c3cbe3SAl Viro 	spin_lock(&hash_lock);
30374c3cbe3SAl Viro 	if (owner->root == chunk) {
30474c3cbe3SAl Viro 		list_del_init(&owner->same_root);
30574c3cbe3SAl Viro 		owner->root = NULL;
30674c3cbe3SAl Viro 	}
30774c3cbe3SAl Viro 	list_del_init(&p->list);
30874c3cbe3SAl Viro 	p->owner = NULL;
30974c3cbe3SAl Viro 	put_tree(owner);
31074c3cbe3SAl Viro 	spin_unlock(&hash_lock);
31128a3a7ebSEric Paris 	spin_unlock(&entry->lock);
3128f7b0ba1SAl Viro out:
31328a3a7ebSEric Paris 	fsnotify_put_mark(entry);
3148f7b0ba1SAl Viro 	spin_lock(&hash_lock);
31574c3cbe3SAl Viro }
31674c3cbe3SAl Viro 
31774c3cbe3SAl Viro static int create_chunk(struct inode *inode, struct audit_tree *tree)
31874c3cbe3SAl Viro {
319e61ce867SEric Paris 	struct fsnotify_mark *entry;
32074c3cbe3SAl Viro 	struct audit_chunk *chunk = alloc_chunk(1);
32174c3cbe3SAl Viro 	if (!chunk)
32274c3cbe3SAl Viro 		return -ENOMEM;
32374c3cbe3SAl Viro 
32428a3a7ebSEric Paris 	entry = &chunk->mark;
32528a3a7ebSEric Paris 	if (fsnotify_add_mark(entry, audit_tree_group, inode, 0)) {
32674c3cbe3SAl Viro 		free_chunk(chunk);
32774c3cbe3SAl Viro 		return -ENOSPC;
32874c3cbe3SAl Viro 	}
32974c3cbe3SAl Viro 
33028a3a7ebSEric Paris 	spin_lock(&entry->lock);
33174c3cbe3SAl Viro 	spin_lock(&hash_lock);
33274c3cbe3SAl Viro 	if (tree->goner) {
33374c3cbe3SAl Viro 		spin_unlock(&hash_lock);
33474c3cbe3SAl Viro 		chunk->dead = 1;
33528a3a7ebSEric Paris 		spin_unlock(&entry->lock);
33628a3a7ebSEric Paris 		fsnotify_destroy_mark_by_entry(entry);
33728a3a7ebSEric Paris 		fsnotify_put_mark(entry);
33874c3cbe3SAl Viro 		return 0;
33974c3cbe3SAl Viro 	}
34074c3cbe3SAl Viro 	chunk->owners[0].index = (1U << 31);
34174c3cbe3SAl Viro 	chunk->owners[0].owner = tree;
34274c3cbe3SAl Viro 	get_tree(tree);
34374c3cbe3SAl Viro 	list_add(&chunk->owners[0].list, &tree->chunks);
34474c3cbe3SAl Viro 	if (!tree->root) {
34574c3cbe3SAl Viro 		tree->root = chunk;
34674c3cbe3SAl Viro 		list_add(&tree->same_root, &chunk->trees);
34774c3cbe3SAl Viro 	}
34874c3cbe3SAl Viro 	insert_hash(chunk);
34974c3cbe3SAl Viro 	spin_unlock(&hash_lock);
35028a3a7ebSEric Paris 	spin_unlock(&entry->lock);
35174c3cbe3SAl Viro 	return 0;
35274c3cbe3SAl Viro }
35374c3cbe3SAl Viro 
35474c3cbe3SAl Viro /* the first tagged inode becomes root of tree */
35574c3cbe3SAl Viro static int tag_chunk(struct inode *inode, struct audit_tree *tree)
35674c3cbe3SAl Viro {
357e61ce867SEric Paris 	struct fsnotify_mark *old_entry, *chunk_entry;
35874c3cbe3SAl Viro 	struct audit_tree *owner;
35974c3cbe3SAl Viro 	struct audit_chunk *chunk, *old;
36074c3cbe3SAl Viro 	struct node *p;
36174c3cbe3SAl Viro 	int n;
36274c3cbe3SAl Viro 
36328a3a7ebSEric Paris 	spin_lock(&inode->i_lock);
36428a3a7ebSEric Paris 	old_entry = fsnotify_find_mark_entry(audit_tree_group, inode);
36528a3a7ebSEric Paris 	spin_unlock(&inode->i_lock);
36628a3a7ebSEric Paris 	if (!old_entry)
36774c3cbe3SAl Viro 		return create_chunk(inode, tree);
36874c3cbe3SAl Viro 
36928a3a7ebSEric Paris 	old = container_of(old_entry, struct audit_chunk, mark);
37074c3cbe3SAl Viro 
37174c3cbe3SAl Viro 	/* are we already there? */
37274c3cbe3SAl Viro 	spin_lock(&hash_lock);
37374c3cbe3SAl Viro 	for (n = 0; n < old->count; n++) {
37474c3cbe3SAl Viro 		if (old->owners[n].owner == tree) {
37574c3cbe3SAl Viro 			spin_unlock(&hash_lock);
37628a3a7ebSEric Paris 			fsnotify_put_mark(old_entry);
37774c3cbe3SAl Viro 			return 0;
37874c3cbe3SAl Viro 		}
37974c3cbe3SAl Viro 	}
38074c3cbe3SAl Viro 	spin_unlock(&hash_lock);
38174c3cbe3SAl Viro 
38274c3cbe3SAl Viro 	chunk = alloc_chunk(old->count + 1);
383b4c30aadSAl Viro 	if (!chunk) {
38428a3a7ebSEric Paris 		fsnotify_put_mark(old_entry);
38574c3cbe3SAl Viro 		return -ENOMEM;
386b4c30aadSAl Viro 	}
38774c3cbe3SAl Viro 
38828a3a7ebSEric Paris 	chunk_entry = &chunk->mark;
38928a3a7ebSEric Paris 
39028a3a7ebSEric Paris 	spin_lock(&old_entry->lock);
3912823e04dSEric Paris 	if (!old_entry->i.inode) {
39228a3a7ebSEric Paris 		/* old_entry is being shot, lets just lie */
39328a3a7ebSEric Paris 		spin_unlock(&old_entry->lock);
39428a3a7ebSEric Paris 		fsnotify_put_mark(old_entry);
39574c3cbe3SAl Viro 		free_chunk(chunk);
39628a3a7ebSEric Paris 		return -ENOENT;
39728a3a7ebSEric Paris 	}
39828a3a7ebSEric Paris 
39928a3a7ebSEric Paris 	fsnotify_duplicate_mark(chunk_entry, old_entry);
4002823e04dSEric Paris 	if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, 1)) {
40128a3a7ebSEric Paris 		spin_unlock(&old_entry->lock);
40228a3a7ebSEric Paris 		free_chunk(chunk);
40328a3a7ebSEric Paris 		fsnotify_put_mark(old_entry);
40474c3cbe3SAl Viro 		return -ENOSPC;
40574c3cbe3SAl Viro 	}
40628a3a7ebSEric Paris 
40728a3a7ebSEric Paris 	/* even though we hold old_entry->lock, this is safe since chunk_entry->lock could NEVER have been grabbed before */
40828a3a7ebSEric Paris 	spin_lock(&chunk_entry->lock);
40974c3cbe3SAl Viro 	spin_lock(&hash_lock);
41028a3a7ebSEric Paris 
41128a3a7ebSEric Paris 	/* we now hold old_entry->lock, chunk_entry->lock, and hash_lock */
41274c3cbe3SAl Viro 	if (tree->goner) {
41374c3cbe3SAl Viro 		spin_unlock(&hash_lock);
41474c3cbe3SAl Viro 		chunk->dead = 1;
41528a3a7ebSEric Paris 		spin_unlock(&chunk_entry->lock);
41628a3a7ebSEric Paris 		spin_unlock(&old_entry->lock);
41728a3a7ebSEric Paris 
41828a3a7ebSEric Paris 		fsnotify_destroy_mark_by_entry(chunk_entry);
41928a3a7ebSEric Paris 
42028a3a7ebSEric Paris 		fsnotify_put_mark(chunk_entry);
42128a3a7ebSEric Paris 		fsnotify_put_mark(old_entry);
42274c3cbe3SAl Viro 		return 0;
42374c3cbe3SAl Viro 	}
42474c3cbe3SAl Viro 	list_replace_init(&old->trees, &chunk->trees);
42574c3cbe3SAl Viro 	for (n = 0, p = chunk->owners; n < old->count; n++, p++) {
42674c3cbe3SAl Viro 		struct audit_tree *s = old->owners[n].owner;
42774c3cbe3SAl Viro 		p->owner = s;
42874c3cbe3SAl Viro 		p->index = old->owners[n].index;
42974c3cbe3SAl Viro 		if (!s) /* result of fallback in untag */
43074c3cbe3SAl Viro 			continue;
43174c3cbe3SAl Viro 		get_tree(s);
43274c3cbe3SAl Viro 		list_replace_init(&old->owners[n].list, &p->list);
43374c3cbe3SAl Viro 	}
43474c3cbe3SAl Viro 	p->index = (chunk->count - 1) | (1U<<31);
43574c3cbe3SAl Viro 	p->owner = tree;
43674c3cbe3SAl Viro 	get_tree(tree);
43774c3cbe3SAl Viro 	list_add(&p->list, &tree->chunks);
43874c3cbe3SAl Viro 	list_replace_rcu(&old->hash, &chunk->hash);
43974c3cbe3SAl Viro 	list_for_each_entry(owner, &chunk->trees, same_root)
44074c3cbe3SAl Viro 		owner->root = chunk;
44174c3cbe3SAl Viro 	old->dead = 1;
44274c3cbe3SAl Viro 	if (!tree->root) {
44374c3cbe3SAl Viro 		tree->root = chunk;
44474c3cbe3SAl Viro 		list_add(&tree->same_root, &chunk->trees);
44574c3cbe3SAl Viro 	}
44674c3cbe3SAl Viro 	spin_unlock(&hash_lock);
44728a3a7ebSEric Paris 	spin_unlock(&chunk_entry->lock);
44828a3a7ebSEric Paris 	spin_unlock(&old_entry->lock);
44928a3a7ebSEric Paris 	fsnotify_destroy_mark_by_entry(old_entry);
45028a3a7ebSEric Paris 	fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */
45128a3a7ebSEric Paris 	fsnotify_put_mark(old_entry); /* and kill it */
45274c3cbe3SAl Viro 	return 0;
45374c3cbe3SAl Viro }
45474c3cbe3SAl Viro 
45574c3cbe3SAl Viro static void kill_rules(struct audit_tree *tree)
45674c3cbe3SAl Viro {
45774c3cbe3SAl Viro 	struct audit_krule *rule, *next;
45874c3cbe3SAl Viro 	struct audit_entry *entry;
45974c3cbe3SAl Viro 	struct audit_buffer *ab;
46074c3cbe3SAl Viro 
46174c3cbe3SAl Viro 	list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
46274c3cbe3SAl Viro 		entry = container_of(rule, struct audit_entry, rule);
46374c3cbe3SAl Viro 
46474c3cbe3SAl Viro 		list_del_init(&rule->rlist);
46574c3cbe3SAl Viro 		if (rule->tree) {
46674c3cbe3SAl Viro 			/* not a half-baked one */
46774c3cbe3SAl Viro 			ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
4689d960985SEric Paris 			audit_log_format(ab, "op=");
4699d960985SEric Paris 			audit_log_string(ab, "remove rule");
4709d960985SEric Paris 			audit_log_format(ab, " dir=");
47174c3cbe3SAl Viro 			audit_log_untrustedstring(ab, rule->tree->pathname);
4729d960985SEric Paris 			audit_log_key(ab, rule->filterkey);
47374c3cbe3SAl Viro 			audit_log_format(ab, " list=%d res=1", rule->listnr);
47474c3cbe3SAl Viro 			audit_log_end(ab);
47574c3cbe3SAl Viro 			rule->tree = NULL;
47674c3cbe3SAl Viro 			list_del_rcu(&entry->list);
477e45aa212SAl Viro 			list_del(&entry->rule.list);
47874c3cbe3SAl Viro 			call_rcu(&entry->rcu, audit_free_rule_rcu);
47974c3cbe3SAl Viro 		}
48074c3cbe3SAl Viro 	}
48174c3cbe3SAl Viro }
48274c3cbe3SAl Viro 
48374c3cbe3SAl Viro /*
48474c3cbe3SAl Viro  * finish killing struct audit_tree
48574c3cbe3SAl Viro  */
48674c3cbe3SAl Viro static void prune_one(struct audit_tree *victim)
48774c3cbe3SAl Viro {
48874c3cbe3SAl Viro 	spin_lock(&hash_lock);
48974c3cbe3SAl Viro 	while (!list_empty(&victim->chunks)) {
49074c3cbe3SAl Viro 		struct node *p;
49174c3cbe3SAl Viro 
49274c3cbe3SAl Viro 		p = list_entry(victim->chunks.next, struct node, list);
49374c3cbe3SAl Viro 
4948f7b0ba1SAl Viro 		untag_chunk(p);
49574c3cbe3SAl Viro 	}
49674c3cbe3SAl Viro 	spin_unlock(&hash_lock);
49774c3cbe3SAl Viro 	put_tree(victim);
49874c3cbe3SAl Viro }
49974c3cbe3SAl Viro 
50074c3cbe3SAl Viro /* trim the uncommitted chunks from tree */
50174c3cbe3SAl Viro 
50274c3cbe3SAl Viro static void trim_marked(struct audit_tree *tree)
50374c3cbe3SAl Viro {
50474c3cbe3SAl Viro 	struct list_head *p, *q;
50574c3cbe3SAl Viro 	spin_lock(&hash_lock);
50674c3cbe3SAl Viro 	if (tree->goner) {
50774c3cbe3SAl Viro 		spin_unlock(&hash_lock);
50874c3cbe3SAl Viro 		return;
50974c3cbe3SAl Viro 	}
51074c3cbe3SAl Viro 	/* reorder */
51174c3cbe3SAl Viro 	for (p = tree->chunks.next; p != &tree->chunks; p = q) {
51274c3cbe3SAl Viro 		struct node *node = list_entry(p, struct node, list);
51374c3cbe3SAl Viro 		q = p->next;
51474c3cbe3SAl Viro 		if (node->index & (1U<<31)) {
51574c3cbe3SAl Viro 			list_del_init(p);
51674c3cbe3SAl Viro 			list_add(p, &tree->chunks);
51774c3cbe3SAl Viro 		}
51874c3cbe3SAl Viro 	}
51974c3cbe3SAl Viro 
52074c3cbe3SAl Viro 	while (!list_empty(&tree->chunks)) {
52174c3cbe3SAl Viro 		struct node *node;
52274c3cbe3SAl Viro 
52374c3cbe3SAl Viro 		node = list_entry(tree->chunks.next, struct node, list);
52474c3cbe3SAl Viro 
52574c3cbe3SAl Viro 		/* have we run out of marked? */
52674c3cbe3SAl Viro 		if (!(node->index & (1U<<31)))
52774c3cbe3SAl Viro 			break;
52874c3cbe3SAl Viro 
5298f7b0ba1SAl Viro 		untag_chunk(node);
53074c3cbe3SAl Viro 	}
53174c3cbe3SAl Viro 	if (!tree->root && !tree->goner) {
53274c3cbe3SAl Viro 		tree->goner = 1;
53374c3cbe3SAl Viro 		spin_unlock(&hash_lock);
53474c3cbe3SAl Viro 		mutex_lock(&audit_filter_mutex);
53574c3cbe3SAl Viro 		kill_rules(tree);
53674c3cbe3SAl Viro 		list_del_init(&tree->list);
53774c3cbe3SAl Viro 		mutex_unlock(&audit_filter_mutex);
53874c3cbe3SAl Viro 		prune_one(tree);
53974c3cbe3SAl Viro 	} else {
54074c3cbe3SAl Viro 		spin_unlock(&hash_lock);
54174c3cbe3SAl Viro 	}
54274c3cbe3SAl Viro }
54374c3cbe3SAl Viro 
544916d7576SAl Viro static void audit_schedule_prune(void);
545916d7576SAl Viro 
54674c3cbe3SAl Viro /* called with audit_filter_mutex */
54774c3cbe3SAl Viro int audit_remove_tree_rule(struct audit_krule *rule)
54874c3cbe3SAl Viro {
54974c3cbe3SAl Viro 	struct audit_tree *tree;
55074c3cbe3SAl Viro 	tree = rule->tree;
55174c3cbe3SAl Viro 	if (tree) {
55274c3cbe3SAl Viro 		spin_lock(&hash_lock);
55374c3cbe3SAl Viro 		list_del_init(&rule->rlist);
55474c3cbe3SAl Viro 		if (list_empty(&tree->rules) && !tree->goner) {
55574c3cbe3SAl Viro 			tree->root = NULL;
55674c3cbe3SAl Viro 			list_del_init(&tree->same_root);
55774c3cbe3SAl Viro 			tree->goner = 1;
55874c3cbe3SAl Viro 			list_move(&tree->list, &prune_list);
55974c3cbe3SAl Viro 			rule->tree = NULL;
56074c3cbe3SAl Viro 			spin_unlock(&hash_lock);
56174c3cbe3SAl Viro 			audit_schedule_prune();
56274c3cbe3SAl Viro 			return 1;
56374c3cbe3SAl Viro 		}
56474c3cbe3SAl Viro 		rule->tree = NULL;
56574c3cbe3SAl Viro 		spin_unlock(&hash_lock);
56674c3cbe3SAl Viro 		return 1;
56774c3cbe3SAl Viro 	}
56874c3cbe3SAl Viro 	return 0;
56974c3cbe3SAl Viro }
57074c3cbe3SAl Viro 
5711f707137SAl Viro static int compare_root(struct vfsmount *mnt, void *arg)
5721f707137SAl Viro {
5731f707137SAl Viro 	return mnt->mnt_root->d_inode == arg;
5741f707137SAl Viro }
5751f707137SAl Viro 
57674c3cbe3SAl Viro void audit_trim_trees(void)
57774c3cbe3SAl Viro {
57874c3cbe3SAl Viro 	struct list_head cursor;
57974c3cbe3SAl Viro 
58074c3cbe3SAl Viro 	mutex_lock(&audit_filter_mutex);
58174c3cbe3SAl Viro 	list_add(&cursor, &tree_list);
58274c3cbe3SAl Viro 	while (cursor.next != &tree_list) {
58374c3cbe3SAl Viro 		struct audit_tree *tree;
58498bc993fSAl Viro 		struct path path;
58574c3cbe3SAl Viro 		struct vfsmount *root_mnt;
58674c3cbe3SAl Viro 		struct node *node;
58774c3cbe3SAl Viro 		int err;
58874c3cbe3SAl Viro 
58974c3cbe3SAl Viro 		tree = container_of(cursor.next, struct audit_tree, list);
59074c3cbe3SAl Viro 		get_tree(tree);
59174c3cbe3SAl Viro 		list_del(&cursor);
59274c3cbe3SAl Viro 		list_add(&cursor, &tree->list);
59374c3cbe3SAl Viro 		mutex_unlock(&audit_filter_mutex);
59474c3cbe3SAl Viro 
59598bc993fSAl Viro 		err = kern_path(tree->pathname, 0, &path);
59674c3cbe3SAl Viro 		if (err)
59774c3cbe3SAl Viro 			goto skip_it;
59874c3cbe3SAl Viro 
599589ff870SAl Viro 		root_mnt = collect_mounts(&path);
60098bc993fSAl Viro 		path_put(&path);
60174c3cbe3SAl Viro 		if (!root_mnt)
60274c3cbe3SAl Viro 			goto skip_it;
60374c3cbe3SAl Viro 
60474c3cbe3SAl Viro 		spin_lock(&hash_lock);
60574c3cbe3SAl Viro 		list_for_each_entry(node, &tree->chunks, list) {
60628a3a7ebSEric Paris 			struct audit_chunk *chunk = find_chunk(node);
60728a3a7ebSEric Paris 			/* this could be NULL if the watch is dieing else where... */
6082823e04dSEric Paris 			struct inode *inode = chunk->mark.i.inode;
60974c3cbe3SAl Viro 			node->index |= 1U<<31;
6101f707137SAl Viro 			if (iterate_mounts(compare_root, inode, root_mnt))
61174c3cbe3SAl Viro 				node->index &= ~(1U<<31);
61274c3cbe3SAl Viro 		}
61374c3cbe3SAl Viro 		spin_unlock(&hash_lock);
61474c3cbe3SAl Viro 		trim_marked(tree);
61574c3cbe3SAl Viro 		put_tree(tree);
61674c3cbe3SAl Viro 		drop_collected_mounts(root_mnt);
61774c3cbe3SAl Viro skip_it:
61874c3cbe3SAl Viro 		mutex_lock(&audit_filter_mutex);
61974c3cbe3SAl Viro 	}
62074c3cbe3SAl Viro 	list_del(&cursor);
62174c3cbe3SAl Viro 	mutex_unlock(&audit_filter_mutex);
62274c3cbe3SAl Viro }
62374c3cbe3SAl Viro 
62474c3cbe3SAl Viro int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
62574c3cbe3SAl Viro {
62674c3cbe3SAl Viro 
62774c3cbe3SAl Viro 	if (pathname[0] != '/' ||
62874c3cbe3SAl Viro 	    rule->listnr != AUDIT_FILTER_EXIT ||
6295af75d8dSAl Viro 	    op != Audit_equal ||
63074c3cbe3SAl Viro 	    rule->inode_f || rule->watch || rule->tree)
63174c3cbe3SAl Viro 		return -EINVAL;
63274c3cbe3SAl Viro 	rule->tree = alloc_tree(pathname);
63374c3cbe3SAl Viro 	if (!rule->tree)
63474c3cbe3SAl Viro 		return -ENOMEM;
63574c3cbe3SAl Viro 	return 0;
63674c3cbe3SAl Viro }
63774c3cbe3SAl Viro 
63874c3cbe3SAl Viro void audit_put_tree(struct audit_tree *tree)
63974c3cbe3SAl Viro {
64074c3cbe3SAl Viro 	put_tree(tree);
64174c3cbe3SAl Viro }
64274c3cbe3SAl Viro 
6431f707137SAl Viro static int tag_mount(struct vfsmount *mnt, void *arg)
6441f707137SAl Viro {
6451f707137SAl Viro 	return tag_chunk(mnt->mnt_root->d_inode, arg);
6461f707137SAl Viro }
6471f707137SAl Viro 
64874c3cbe3SAl Viro /* called with audit_filter_mutex */
64974c3cbe3SAl Viro int audit_add_tree_rule(struct audit_krule *rule)
65074c3cbe3SAl Viro {
65174c3cbe3SAl Viro 	struct audit_tree *seed = rule->tree, *tree;
65298bc993fSAl Viro 	struct path path;
6531f707137SAl Viro 	struct vfsmount *mnt;
65474c3cbe3SAl Viro 	int err;
65574c3cbe3SAl Viro 
65674c3cbe3SAl Viro 	list_for_each_entry(tree, &tree_list, list) {
65774c3cbe3SAl Viro 		if (!strcmp(seed->pathname, tree->pathname)) {
65874c3cbe3SAl Viro 			put_tree(seed);
65974c3cbe3SAl Viro 			rule->tree = tree;
66074c3cbe3SAl Viro 			list_add(&rule->rlist, &tree->rules);
66174c3cbe3SAl Viro 			return 0;
66274c3cbe3SAl Viro 		}
66374c3cbe3SAl Viro 	}
66474c3cbe3SAl Viro 	tree = seed;
66574c3cbe3SAl Viro 	list_add(&tree->list, &tree_list);
66674c3cbe3SAl Viro 	list_add(&rule->rlist, &tree->rules);
66774c3cbe3SAl Viro 	/* do not set rule->tree yet */
66874c3cbe3SAl Viro 	mutex_unlock(&audit_filter_mutex);
66974c3cbe3SAl Viro 
67098bc993fSAl Viro 	err = kern_path(tree->pathname, 0, &path);
67174c3cbe3SAl Viro 	if (err)
67274c3cbe3SAl Viro 		goto Err;
673589ff870SAl Viro 	mnt = collect_mounts(&path);
67498bc993fSAl Viro 	path_put(&path);
67574c3cbe3SAl Viro 	if (!mnt) {
67674c3cbe3SAl Viro 		err = -ENOMEM;
67774c3cbe3SAl Viro 		goto Err;
67874c3cbe3SAl Viro 	}
67974c3cbe3SAl Viro 
68074c3cbe3SAl Viro 	get_tree(tree);
6811f707137SAl Viro 	err = iterate_mounts(tag_mount, tree, mnt);
68274c3cbe3SAl Viro 	drop_collected_mounts(mnt);
68374c3cbe3SAl Viro 
68474c3cbe3SAl Viro 	if (!err) {
68574c3cbe3SAl Viro 		struct node *node;
68674c3cbe3SAl Viro 		spin_lock(&hash_lock);
68774c3cbe3SAl Viro 		list_for_each_entry(node, &tree->chunks, list)
68874c3cbe3SAl Viro 			node->index &= ~(1U<<31);
68974c3cbe3SAl Viro 		spin_unlock(&hash_lock);
69074c3cbe3SAl Viro 	} else {
69174c3cbe3SAl Viro 		trim_marked(tree);
69274c3cbe3SAl Viro 		goto Err;
69374c3cbe3SAl Viro 	}
69474c3cbe3SAl Viro 
69574c3cbe3SAl Viro 	mutex_lock(&audit_filter_mutex);
69674c3cbe3SAl Viro 	if (list_empty(&rule->rlist)) {
69774c3cbe3SAl Viro 		put_tree(tree);
69874c3cbe3SAl Viro 		return -ENOENT;
69974c3cbe3SAl Viro 	}
70074c3cbe3SAl Viro 	rule->tree = tree;
70174c3cbe3SAl Viro 	put_tree(tree);
70274c3cbe3SAl Viro 
70374c3cbe3SAl Viro 	return 0;
70474c3cbe3SAl Viro Err:
70574c3cbe3SAl Viro 	mutex_lock(&audit_filter_mutex);
70674c3cbe3SAl Viro 	list_del_init(&tree->list);
70774c3cbe3SAl Viro 	list_del_init(&tree->rules);
70874c3cbe3SAl Viro 	put_tree(tree);
70974c3cbe3SAl Viro 	return err;
71074c3cbe3SAl Viro }
71174c3cbe3SAl Viro 
71274c3cbe3SAl Viro int audit_tag_tree(char *old, char *new)
71374c3cbe3SAl Viro {
71474c3cbe3SAl Viro 	struct list_head cursor, barrier;
71574c3cbe3SAl Viro 	int failed = 0;
7162096f759SAl Viro 	struct path path1, path2;
71774c3cbe3SAl Viro 	struct vfsmount *tagged;
71874c3cbe3SAl Viro 	int err;
71974c3cbe3SAl Viro 
7202096f759SAl Viro 	err = kern_path(new, 0, &path2);
72174c3cbe3SAl Viro 	if (err)
72274c3cbe3SAl Viro 		return err;
7232096f759SAl Viro 	tagged = collect_mounts(&path2);
7242096f759SAl Viro 	path_put(&path2);
72574c3cbe3SAl Viro 	if (!tagged)
72674c3cbe3SAl Viro 		return -ENOMEM;
72774c3cbe3SAl Viro 
7282096f759SAl Viro 	err = kern_path(old, 0, &path1);
72974c3cbe3SAl Viro 	if (err) {
73074c3cbe3SAl Viro 		drop_collected_mounts(tagged);
73174c3cbe3SAl Viro 		return err;
73274c3cbe3SAl Viro 	}
73374c3cbe3SAl Viro 
73474c3cbe3SAl Viro 	mutex_lock(&audit_filter_mutex);
73574c3cbe3SAl Viro 	list_add(&barrier, &tree_list);
73674c3cbe3SAl Viro 	list_add(&cursor, &barrier);
73774c3cbe3SAl Viro 
73874c3cbe3SAl Viro 	while (cursor.next != &tree_list) {
73974c3cbe3SAl Viro 		struct audit_tree *tree;
7402096f759SAl Viro 		int good_one = 0;
74174c3cbe3SAl Viro 
74274c3cbe3SAl Viro 		tree = container_of(cursor.next, struct audit_tree, list);
74374c3cbe3SAl Viro 		get_tree(tree);
74474c3cbe3SAl Viro 		list_del(&cursor);
74574c3cbe3SAl Viro 		list_add(&cursor, &tree->list);
74674c3cbe3SAl Viro 		mutex_unlock(&audit_filter_mutex);
74774c3cbe3SAl Viro 
7482096f759SAl Viro 		err = kern_path(tree->pathname, 0, &path2);
7492096f759SAl Viro 		if (!err) {
7502096f759SAl Viro 			good_one = path_is_under(&path1, &path2);
7512096f759SAl Viro 			path_put(&path2);
75274c3cbe3SAl Viro 		}
75374c3cbe3SAl Viro 
7542096f759SAl Viro 		if (!good_one) {
75574c3cbe3SAl Viro 			put_tree(tree);
75674c3cbe3SAl Viro 			mutex_lock(&audit_filter_mutex);
75774c3cbe3SAl Viro 			continue;
75874c3cbe3SAl Viro 		}
75974c3cbe3SAl Viro 
7601f707137SAl Viro 		failed = iterate_mounts(tag_mount, tree, tagged);
76174c3cbe3SAl Viro 		if (failed) {
76274c3cbe3SAl Viro 			put_tree(tree);
76374c3cbe3SAl Viro 			mutex_lock(&audit_filter_mutex);
76474c3cbe3SAl Viro 			break;
76574c3cbe3SAl Viro 		}
76674c3cbe3SAl Viro 
76774c3cbe3SAl Viro 		mutex_lock(&audit_filter_mutex);
76874c3cbe3SAl Viro 		spin_lock(&hash_lock);
76974c3cbe3SAl Viro 		if (!tree->goner) {
77074c3cbe3SAl Viro 			list_del(&tree->list);
77174c3cbe3SAl Viro 			list_add(&tree->list, &tree_list);
77274c3cbe3SAl Viro 		}
77374c3cbe3SAl Viro 		spin_unlock(&hash_lock);
77474c3cbe3SAl Viro 		put_tree(tree);
77574c3cbe3SAl Viro 	}
77674c3cbe3SAl Viro 
77774c3cbe3SAl Viro 	while (barrier.prev != &tree_list) {
77874c3cbe3SAl Viro 		struct audit_tree *tree;
77974c3cbe3SAl Viro 
78074c3cbe3SAl Viro 		tree = container_of(barrier.prev, struct audit_tree, list);
78174c3cbe3SAl Viro 		get_tree(tree);
78274c3cbe3SAl Viro 		list_del(&tree->list);
78374c3cbe3SAl Viro 		list_add(&tree->list, &barrier);
78474c3cbe3SAl Viro 		mutex_unlock(&audit_filter_mutex);
78574c3cbe3SAl Viro 
78674c3cbe3SAl Viro 		if (!failed) {
78774c3cbe3SAl Viro 			struct node *node;
78874c3cbe3SAl Viro 			spin_lock(&hash_lock);
78974c3cbe3SAl Viro 			list_for_each_entry(node, &tree->chunks, list)
79074c3cbe3SAl Viro 				node->index &= ~(1U<<31);
79174c3cbe3SAl Viro 			spin_unlock(&hash_lock);
79274c3cbe3SAl Viro 		} else {
79374c3cbe3SAl Viro 			trim_marked(tree);
79474c3cbe3SAl Viro 		}
79574c3cbe3SAl Viro 
79674c3cbe3SAl Viro 		put_tree(tree);
79774c3cbe3SAl Viro 		mutex_lock(&audit_filter_mutex);
79874c3cbe3SAl Viro 	}
79974c3cbe3SAl Viro 	list_del(&barrier);
80074c3cbe3SAl Viro 	list_del(&cursor);
80174c3cbe3SAl Viro 	mutex_unlock(&audit_filter_mutex);
8022096f759SAl Viro 	path_put(&path1);
80374c3cbe3SAl Viro 	drop_collected_mounts(tagged);
80474c3cbe3SAl Viro 	return failed;
80574c3cbe3SAl Viro }
80674c3cbe3SAl Viro 
80774c3cbe3SAl Viro /*
80874c3cbe3SAl Viro  * That gets run when evict_chunk() ends up needing to kill audit_tree.
809916d7576SAl Viro  * Runs from a separate thread.
81074c3cbe3SAl Viro  */
811916d7576SAl Viro static int prune_tree_thread(void *unused)
81274c3cbe3SAl Viro {
813916d7576SAl Viro 	mutex_lock(&audit_cmd_mutex);
81474c3cbe3SAl Viro 	mutex_lock(&audit_filter_mutex);
81574c3cbe3SAl Viro 
81674c3cbe3SAl Viro 	while (!list_empty(&prune_list)) {
81774c3cbe3SAl Viro 		struct audit_tree *victim;
81874c3cbe3SAl Viro 
81974c3cbe3SAl Viro 		victim = list_entry(prune_list.next, struct audit_tree, list);
82074c3cbe3SAl Viro 		list_del_init(&victim->list);
82174c3cbe3SAl Viro 
82274c3cbe3SAl Viro 		mutex_unlock(&audit_filter_mutex);
82374c3cbe3SAl Viro 
82474c3cbe3SAl Viro 		prune_one(victim);
82574c3cbe3SAl Viro 
82674c3cbe3SAl Viro 		mutex_lock(&audit_filter_mutex);
82774c3cbe3SAl Viro 	}
82874c3cbe3SAl Viro 
82974c3cbe3SAl Viro 	mutex_unlock(&audit_filter_mutex);
830916d7576SAl Viro 	mutex_unlock(&audit_cmd_mutex);
831916d7576SAl Viro 	return 0;
832916d7576SAl Viro }
833916d7576SAl Viro 
834916d7576SAl Viro static void audit_schedule_prune(void)
835916d7576SAl Viro {
836916d7576SAl Viro 	kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
837916d7576SAl Viro }
838916d7576SAl Viro 
839916d7576SAl Viro /*
840916d7576SAl Viro  * ... and that one is done if evict_chunk() decides to delay until the end
841916d7576SAl Viro  * of syscall.  Runs synchronously.
842916d7576SAl Viro  */
843916d7576SAl Viro void audit_kill_trees(struct list_head *list)
844916d7576SAl Viro {
845916d7576SAl Viro 	mutex_lock(&audit_cmd_mutex);
846916d7576SAl Viro 	mutex_lock(&audit_filter_mutex);
847916d7576SAl Viro 
848916d7576SAl Viro 	while (!list_empty(list)) {
849916d7576SAl Viro 		struct audit_tree *victim;
850916d7576SAl Viro 
851916d7576SAl Viro 		victim = list_entry(list->next, struct audit_tree, list);
852916d7576SAl Viro 		kill_rules(victim);
853916d7576SAl Viro 		list_del_init(&victim->list);
854916d7576SAl Viro 
855916d7576SAl Viro 		mutex_unlock(&audit_filter_mutex);
856916d7576SAl Viro 
857916d7576SAl Viro 		prune_one(victim);
858916d7576SAl Viro 
859916d7576SAl Viro 		mutex_lock(&audit_filter_mutex);
860916d7576SAl Viro 	}
861916d7576SAl Viro 
862916d7576SAl Viro 	mutex_unlock(&audit_filter_mutex);
863916d7576SAl Viro 	mutex_unlock(&audit_cmd_mutex);
86474c3cbe3SAl Viro }
86574c3cbe3SAl Viro 
86674c3cbe3SAl Viro /*
86774c3cbe3SAl Viro  *  Here comes the stuff asynchronous to auditctl operations
86874c3cbe3SAl Viro  */
86974c3cbe3SAl Viro 
87074c3cbe3SAl Viro static void evict_chunk(struct audit_chunk *chunk)
87174c3cbe3SAl Viro {
87274c3cbe3SAl Viro 	struct audit_tree *owner;
873916d7576SAl Viro 	struct list_head *postponed = audit_killed_trees();
874916d7576SAl Viro 	int need_prune = 0;
87574c3cbe3SAl Viro 	int n;
87674c3cbe3SAl Viro 
87774c3cbe3SAl Viro 	if (chunk->dead)
87874c3cbe3SAl Viro 		return;
87974c3cbe3SAl Viro 
88074c3cbe3SAl Viro 	chunk->dead = 1;
88174c3cbe3SAl Viro 	mutex_lock(&audit_filter_mutex);
88274c3cbe3SAl Viro 	spin_lock(&hash_lock);
88374c3cbe3SAl Viro 	while (!list_empty(&chunk->trees)) {
88474c3cbe3SAl Viro 		owner = list_entry(chunk->trees.next,
88574c3cbe3SAl Viro 				   struct audit_tree, same_root);
88674c3cbe3SAl Viro 		owner->goner = 1;
88774c3cbe3SAl Viro 		owner->root = NULL;
88874c3cbe3SAl Viro 		list_del_init(&owner->same_root);
88974c3cbe3SAl Viro 		spin_unlock(&hash_lock);
890916d7576SAl Viro 		if (!postponed) {
89174c3cbe3SAl Viro 			kill_rules(owner);
89274c3cbe3SAl Viro 			list_move(&owner->list, &prune_list);
893916d7576SAl Viro 			need_prune = 1;
894916d7576SAl Viro 		} else {
895916d7576SAl Viro 			list_move(&owner->list, postponed);
896916d7576SAl Viro 		}
89774c3cbe3SAl Viro 		spin_lock(&hash_lock);
89874c3cbe3SAl Viro 	}
89974c3cbe3SAl Viro 	list_del_rcu(&chunk->hash);
90074c3cbe3SAl Viro 	for (n = 0; n < chunk->count; n++)
90174c3cbe3SAl Viro 		list_del_init(&chunk->owners[n].list);
90274c3cbe3SAl Viro 	spin_unlock(&hash_lock);
903916d7576SAl Viro 	if (need_prune)
904916d7576SAl Viro 		audit_schedule_prune();
90574c3cbe3SAl Viro 	mutex_unlock(&audit_filter_mutex);
90674c3cbe3SAl Viro }
90774c3cbe3SAl Viro 
90828a3a7ebSEric Paris static int audit_tree_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
90974c3cbe3SAl Viro {
91028a3a7ebSEric Paris 	BUG();
91128a3a7ebSEric Paris 	return -EOPNOTSUPP;
91228a3a7ebSEric Paris }
91374c3cbe3SAl Viro 
914e61ce867SEric Paris static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group)
91528a3a7ebSEric Paris {
91628a3a7ebSEric Paris 	struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
91728a3a7ebSEric Paris 
91874c3cbe3SAl Viro 	evict_chunk(chunk);
91928a3a7ebSEric Paris 	fsnotify_put_mark(entry);
92074c3cbe3SAl Viro }
92174c3cbe3SAl Viro 
9227b0a04fbSEric Paris static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode,
9233a9fb89fSEric Paris 				  struct vfsmount *mnt, __u32 mask, void *data,
9243a9fb89fSEric Paris 				  int data_type)
92574c3cbe3SAl Viro {
92628a3a7ebSEric Paris 	return 0;
92774c3cbe3SAl Viro }
92874c3cbe3SAl Viro 
92928a3a7ebSEric Paris static const struct fsnotify_ops audit_tree_ops = {
93028a3a7ebSEric Paris 	.handle_event = audit_tree_handle_event,
93128a3a7ebSEric Paris 	.should_send_event = audit_tree_send_event,
93228a3a7ebSEric Paris 	.free_group_priv = NULL,
93328a3a7ebSEric Paris 	.free_event_priv = NULL,
93428a3a7ebSEric Paris 	.freeing_mark = audit_tree_freeing_mark,
93574c3cbe3SAl Viro };
93674c3cbe3SAl Viro 
93774c3cbe3SAl Viro static int __init audit_tree_init(void)
93874c3cbe3SAl Viro {
93974c3cbe3SAl Viro 	int i;
94074c3cbe3SAl Viro 
9410d2e2a1dSEric Paris 	audit_tree_group = fsnotify_alloc_group(&audit_tree_ops);
94228a3a7ebSEric Paris 	if (IS_ERR(audit_tree_group))
94328a3a7ebSEric Paris 		audit_panic("cannot initialize fsnotify group for rectree watches");
94474c3cbe3SAl Viro 
94574c3cbe3SAl Viro 	for (i = 0; i < HASH_SIZE; i++)
94674c3cbe3SAl Viro 		INIT_LIST_HEAD(&chunk_hash_heads[i]);
94774c3cbe3SAl Viro 
94874c3cbe3SAl Viro 	return 0;
94974c3cbe3SAl Viro }
95074c3cbe3SAl Viro __initcall(audit_tree_init);
951