1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
274c3cbe3SAl Viro #include "audit.h"
328a3a7ebSEric Paris #include <linux/fsnotify_backend.h>
474c3cbe3SAl Viro #include <linux/namei.h>
574c3cbe3SAl Viro #include <linux/mount.h>
6916d7576SAl Viro #include <linux/kthread.h>
79d2378f8SElena Reshetova #include <linux/refcount.h>
85a0e3ad6STejun Heo #include <linux/slab.h>
974c3cbe3SAl Viro
1074c3cbe3SAl Viro struct audit_tree;
1174c3cbe3SAl Viro struct audit_chunk;
1274c3cbe3SAl Viro
1374c3cbe3SAl Viro struct audit_tree {
149d2378f8SElena Reshetova refcount_t count;
1574c3cbe3SAl Viro int goner;
1674c3cbe3SAl Viro struct audit_chunk *root;
1774c3cbe3SAl Viro struct list_head chunks;
1874c3cbe3SAl Viro struct list_head rules;
1974c3cbe3SAl Viro struct list_head list;
2074c3cbe3SAl Viro struct list_head same_root;
2174c3cbe3SAl Viro struct rcu_head head;
2274c3cbe3SAl Viro char pathname[];
2374c3cbe3SAl Viro };
2474c3cbe3SAl Viro
2574c3cbe3SAl Viro struct audit_chunk {
2674c3cbe3SAl Viro struct list_head hash;
278d20d6e9SJan Kara unsigned long key;
285f516130SJan Kara struct fsnotify_mark *mark;
2974c3cbe3SAl Viro struct list_head trees; /* with root here */
3074c3cbe3SAl Viro int count;
318f7b0ba1SAl Viro atomic_long_t refs;
3274c3cbe3SAl Viro struct rcu_head head;
3357d4374bSChristophe Leroy struct audit_node {
3474c3cbe3SAl Viro struct list_head list;
3574c3cbe3SAl Viro struct audit_tree *owner;
3674c3cbe3SAl Viro unsigned index; /* index; upper bit indicates 'will prune' */
3774c3cbe3SAl Viro } owners[];
3874c3cbe3SAl Viro };
3974c3cbe3SAl Viro
405f516130SJan Kara struct audit_tree_mark {
415f516130SJan Kara struct fsnotify_mark mark;
425f516130SJan Kara struct audit_chunk *chunk;
435f516130SJan Kara };
445f516130SJan Kara
4574c3cbe3SAl Viro static LIST_HEAD(tree_list);
4674c3cbe3SAl Viro static LIST_HEAD(prune_list);
47f1aaf262SImre Palik static struct task_struct *prune_thread;
4874c3cbe3SAl Viro
4974c3cbe3SAl Viro /*
5083d23bc8SJan Kara * One struct chunk is attached to each inode of interest through
5183d23bc8SJan Kara * audit_tree_mark (fsnotify mark). We replace struct chunk on tagging /
5283d23bc8SJan Kara * untagging, the mark is stable as long as there is chunk attached. The
5383d23bc8SJan Kara * association between mark and chunk is protected by hash_lock and
5483d23bc8SJan Kara * audit_tree_group->mark_mutex. Thus as long as we hold
5583d23bc8SJan Kara * audit_tree_group->mark_mutex and check that the mark is alive by
5683d23bc8SJan Kara * FSNOTIFY_MARK_FLAG_ATTACHED flag check, we are sure the mark points to
5783d23bc8SJan Kara * the current chunk.
5883d23bc8SJan Kara *
5974c3cbe3SAl Viro * Rules have pointer to struct audit_tree.
6074c3cbe3SAl Viro * Rules have struct list_head rlist forming a list of rules over
6174c3cbe3SAl Viro * the same tree.
6274c3cbe3SAl Viro * References to struct chunk are collected at audit_inode{,_child}()
6374c3cbe3SAl Viro * time and used in AUDIT_TREE rule matching.
6474c3cbe3SAl Viro * These references are dropped at the same time we are calling
6574c3cbe3SAl Viro * audit_free_names(), etc.
6674c3cbe3SAl Viro *
6774c3cbe3SAl Viro * Cyclic lists galore:
6874c3cbe3SAl Viro * tree.chunks anchors chunk.owners[].list hash_lock
6974c3cbe3SAl Viro * tree.rules anchors rule.rlist audit_filter_mutex
7074c3cbe3SAl Viro * chunk.trees anchors tree.same_root hash_lock
7174c3cbe3SAl Viro * chunk.hash is a hash with middle bits of watch.inode as
7274c3cbe3SAl Viro * a hash function. RCU, hash_lock
7374c3cbe3SAl Viro *
7474c3cbe3SAl Viro * tree is refcounted; one reference for "some rules on rules_list refer to
7574c3cbe3SAl Viro * it", one for each chunk with pointer to it.
7674c3cbe3SAl Viro *
7783d23bc8SJan Kara * chunk is refcounted by embedded .refs. Mark associated with the chunk holds
7883d23bc8SJan Kara * one chunk reference. This reference is dropped either when a mark is going
7983d23bc8SJan Kara * to be freed (corresponding inode goes away) or when chunk attached to the
8083d23bc8SJan Kara * mark gets replaced. This reference must be dropped using
8183d23bc8SJan Kara * audit_mark_put_chunk() to make sure the reference is dropped only after RCU
8283d23bc8SJan Kara * grace period as it protects RCU readers of the hash table.
8374c3cbe3SAl Viro *
8474c3cbe3SAl Viro * node.index allows to get from node.list to containing chunk.
8574c3cbe3SAl Viro * MSB of that sucker is stolen to mark taggings that we might have to
8674c3cbe3SAl Viro * revert - several operations have very unpleasant cleanup logics and
8774c3cbe3SAl Viro * that makes a difference. Some.
8874c3cbe3SAl Viro */
8974c3cbe3SAl Viro
9028a3a7ebSEric Paris static struct fsnotify_group *audit_tree_group;
915f516130SJan Kara static struct kmem_cache *audit_tree_mark_cachep __read_mostly;
9274c3cbe3SAl Viro
alloc_tree(const char * s)9374c3cbe3SAl Viro static struct audit_tree *alloc_tree(const char *s)
9474c3cbe3SAl Viro {
9574c3cbe3SAl Viro struct audit_tree *tree;
9674c3cbe3SAl Viro
97bc6e60a4SXiu Jianfeng tree = kmalloc(struct_size(tree, pathname, strlen(s) + 1), GFP_KERNEL);
9874c3cbe3SAl Viro if (tree) {
999d2378f8SElena Reshetova refcount_set(&tree->count, 1);
10074c3cbe3SAl Viro tree->goner = 0;
10174c3cbe3SAl Viro INIT_LIST_HEAD(&tree->chunks);
10274c3cbe3SAl Viro INIT_LIST_HEAD(&tree->rules);
10374c3cbe3SAl Viro INIT_LIST_HEAD(&tree->list);
10474c3cbe3SAl Viro INIT_LIST_HEAD(&tree->same_root);
10574c3cbe3SAl Viro tree->root = NULL;
10674c3cbe3SAl Viro strcpy(tree->pathname, s);
10774c3cbe3SAl Viro }
10874c3cbe3SAl Viro return tree;
10974c3cbe3SAl Viro }
11074c3cbe3SAl Viro
get_tree(struct audit_tree * tree)11174c3cbe3SAl Viro static inline void get_tree(struct audit_tree *tree)
11274c3cbe3SAl Viro {
1139d2378f8SElena Reshetova refcount_inc(&tree->count);
11474c3cbe3SAl Viro }
11574c3cbe3SAl Viro
put_tree(struct audit_tree * tree)11674c3cbe3SAl Viro static inline void put_tree(struct audit_tree *tree)
11774c3cbe3SAl Viro {
1189d2378f8SElena Reshetova if (refcount_dec_and_test(&tree->count))
1193b097c46SLai Jiangshan kfree_rcu(tree, head);
12074c3cbe3SAl Viro }
12174c3cbe3SAl Viro
12274c3cbe3SAl Viro /* to avoid bringing the entire thing in audit.h */
audit_tree_path(struct audit_tree * tree)12374c3cbe3SAl Viro const char *audit_tree_path(struct audit_tree *tree)
12474c3cbe3SAl Viro {
12574c3cbe3SAl Viro return tree->pathname;
12674c3cbe3SAl Viro }
12774c3cbe3SAl Viro
free_chunk(struct audit_chunk * chunk)1288f7b0ba1SAl Viro static void free_chunk(struct audit_chunk *chunk)
12974c3cbe3SAl Viro {
13074c3cbe3SAl Viro int i;
13174c3cbe3SAl Viro
13274c3cbe3SAl Viro for (i = 0; i < chunk->count; i++) {
13374c3cbe3SAl Viro if (chunk->owners[i].owner)
13474c3cbe3SAl Viro put_tree(chunk->owners[i].owner);
13574c3cbe3SAl Viro }
13674c3cbe3SAl Viro kfree(chunk);
13774c3cbe3SAl Viro }
13874c3cbe3SAl Viro
audit_put_chunk(struct audit_chunk * chunk)13974c3cbe3SAl Viro void audit_put_chunk(struct audit_chunk *chunk)
14074c3cbe3SAl Viro {
1418f7b0ba1SAl Viro if (atomic_long_dec_and_test(&chunk->refs))
1428f7b0ba1SAl Viro free_chunk(chunk);
1438f7b0ba1SAl Viro }
1448f7b0ba1SAl Viro
__put_chunk(struct rcu_head * rcu)1458f7b0ba1SAl Viro static void __put_chunk(struct rcu_head *rcu)
1468f7b0ba1SAl Viro {
1478f7b0ba1SAl Viro struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
1488f7b0ba1SAl Viro audit_put_chunk(chunk);
14974c3cbe3SAl Viro }
15074c3cbe3SAl Viro
151a8375713SJan Kara /*
152a8375713SJan Kara * Drop reference to the chunk that was held by the mark. This is the reference
153a8375713SJan Kara * that gets dropped after we've removed the chunk from the hash table and we
154a8375713SJan Kara * use it to make sure chunk cannot be freed before RCU grace period expires.
155a8375713SJan Kara */
audit_mark_put_chunk(struct audit_chunk * chunk)156a8375713SJan Kara static void audit_mark_put_chunk(struct audit_chunk *chunk)
157a8375713SJan Kara {
158a8375713SJan Kara call_rcu(&chunk->head, __put_chunk);
159a8375713SJan Kara }
160a8375713SJan Kara
audit_mark(struct fsnotify_mark * mark)161f905c2fcSJan Kara static inline struct audit_tree_mark *audit_mark(struct fsnotify_mark *mark)
1625f516130SJan Kara {
163f905c2fcSJan Kara return container_of(mark, struct audit_tree_mark, mark);
1645f516130SJan Kara }
1655f516130SJan Kara
mark_chunk(struct fsnotify_mark * mark)1665f516130SJan Kara static struct audit_chunk *mark_chunk(struct fsnotify_mark *mark)
1675f516130SJan Kara {
1685f516130SJan Kara return audit_mark(mark)->chunk;
1695f516130SJan Kara }
1705f516130SJan Kara
audit_tree_destroy_watch(struct fsnotify_mark * mark)171f905c2fcSJan Kara static void audit_tree_destroy_watch(struct fsnotify_mark *mark)
17228a3a7ebSEric Paris {
173f905c2fcSJan Kara kmem_cache_free(audit_tree_mark_cachep, audit_mark(mark));
1745f516130SJan Kara }
1755f516130SJan Kara
alloc_mark(void)1765f516130SJan Kara static struct fsnotify_mark *alloc_mark(void)
1775f516130SJan Kara {
1785f516130SJan Kara struct audit_tree_mark *amark;
1795f516130SJan Kara
1805f516130SJan Kara amark = kmem_cache_zalloc(audit_tree_mark_cachep, GFP_KERNEL);
1815f516130SJan Kara if (!amark)
1825f516130SJan Kara return NULL;
1835f516130SJan Kara fsnotify_init_mark(&amark->mark, audit_tree_group);
1845f516130SJan Kara amark->mark.mask = FS_IN_IGNORED;
1855f516130SJan Kara return &amark->mark;
18628a3a7ebSEric Paris }
18728a3a7ebSEric Paris
alloc_chunk(int count)18828a3a7ebSEric Paris static struct audit_chunk *alloc_chunk(int count)
18928a3a7ebSEric Paris {
19028a3a7ebSEric Paris struct audit_chunk *chunk;
19128a3a7ebSEric Paris int i;
19228a3a7ebSEric Paris
193bbccc11bSGustavo A. R. Silva chunk = kzalloc(struct_size(chunk, owners, count), GFP_KERNEL);
19428a3a7ebSEric Paris if (!chunk)
19528a3a7ebSEric Paris return NULL;
19628a3a7ebSEric Paris
19728a3a7ebSEric Paris INIT_LIST_HEAD(&chunk->hash);
19828a3a7ebSEric Paris INIT_LIST_HEAD(&chunk->trees);
19928a3a7ebSEric Paris chunk->count = count;
20028a3a7ebSEric Paris atomic_long_set(&chunk->refs, 1);
20128a3a7ebSEric Paris for (i = 0; i < count; i++) {
20228a3a7ebSEric Paris INIT_LIST_HEAD(&chunk->owners[i].list);
20328a3a7ebSEric Paris chunk->owners[i].index = i;
20428a3a7ebSEric Paris }
20528a3a7ebSEric Paris return chunk;
20628a3a7ebSEric Paris }
20728a3a7ebSEric Paris
20874c3cbe3SAl Viro enum {HASH_SIZE = 128};
20974c3cbe3SAl Viro static struct list_head chunk_hash_heads[HASH_SIZE];
21074c3cbe3SAl Viro static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock);
21174c3cbe3SAl Viro
212f410ff65SJan Kara /* Function to return search key in our hash from inode. */
inode_to_key(const struct inode * inode)213f410ff65SJan Kara static unsigned long inode_to_key(const struct inode *inode)
21474c3cbe3SAl Viro {
21536f10f55SAmir Goldstein /* Use address pointed to by connector->obj as the key */
21636f10f55SAmir Goldstein return (unsigned long)&inode->i_fsnotify_marks;
217f410ff65SJan Kara }
218f410ff65SJan Kara
chunk_hash(unsigned long key)219f410ff65SJan Kara static inline struct list_head *chunk_hash(unsigned long key)
220f410ff65SJan Kara {
221f410ff65SJan Kara unsigned long n = key / L1_CACHE_BYTES;
22274c3cbe3SAl Viro return chunk_hash_heads + n % HASH_SIZE;
22374c3cbe3SAl Viro }
22474c3cbe3SAl Viro
225f905c2fcSJan Kara /* hash_lock & mark->group->mark_mutex is held by caller */
insert_hash(struct audit_chunk * chunk)22674c3cbe3SAl Viro static void insert_hash(struct audit_chunk *chunk)
22774c3cbe3SAl Viro {
22828a3a7ebSEric Paris struct list_head *list;
22928a3a7ebSEric Paris
2301635e572SJan Kara /*
2311635e572SJan Kara * Make sure chunk is fully initialized before making it visible in the
2321635e572SJan Kara * hash. Pairs with a data dependency barrier in READ_ONCE() in
2331635e572SJan Kara * audit_tree_lookup().
2341635e572SJan Kara */
2351635e572SJan Kara smp_wmb();
2368d20d6e9SJan Kara WARN_ON_ONCE(!chunk->key);
2378d20d6e9SJan Kara list = chunk_hash(chunk->key);
23874c3cbe3SAl Viro list_add_rcu(&chunk->hash, list);
23974c3cbe3SAl Viro }
24074c3cbe3SAl Viro
24174c3cbe3SAl Viro /* called under rcu_read_lock */
audit_tree_lookup(const struct inode * inode)24274c3cbe3SAl Viro struct audit_chunk *audit_tree_lookup(const struct inode *inode)
24374c3cbe3SAl Viro {
244f410ff65SJan Kara unsigned long key = inode_to_key(inode);
245f410ff65SJan Kara struct list_head *list = chunk_hash(key);
2466793a051SPaul E. McKenney struct audit_chunk *p;
24774c3cbe3SAl Viro
2486793a051SPaul E. McKenney list_for_each_entry_rcu(p, list, hash) {
2491635e572SJan Kara /*
2501635e572SJan Kara * We use a data dependency barrier in READ_ONCE() to make sure
2511635e572SJan Kara * the chunk we see is fully initialized.
2521635e572SJan Kara */
2531635e572SJan Kara if (READ_ONCE(p->key) == key) {
2548f7b0ba1SAl Viro atomic_long_inc(&p->refs);
25574c3cbe3SAl Viro return p;
25674c3cbe3SAl Viro }
25774c3cbe3SAl Viro }
25874c3cbe3SAl Viro return NULL;
25974c3cbe3SAl Viro }
26074c3cbe3SAl Viro
audit_tree_match(struct audit_chunk * chunk,struct audit_tree * tree)2616f1b5d7aSYaowei Bai bool audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
26274c3cbe3SAl Viro {
26374c3cbe3SAl Viro int n;
26474c3cbe3SAl Viro for (n = 0; n < chunk->count; n++)
26574c3cbe3SAl Viro if (chunk->owners[n].owner == tree)
2666f1b5d7aSYaowei Bai return true;
2676f1b5d7aSYaowei Bai return false;
26874c3cbe3SAl Viro }
26974c3cbe3SAl Viro
27074c3cbe3SAl Viro /* tagging and untagging inodes with trees */
27174c3cbe3SAl Viro
find_chunk(struct audit_node * p)27257d4374bSChristophe Leroy static struct audit_chunk *find_chunk(struct audit_node *p)
27374c3cbe3SAl Viro {
2748f7b0ba1SAl Viro int index = p->index & ~(1U<<31);
2758f7b0ba1SAl Viro p -= index;
2768f7b0ba1SAl Viro return container_of(p, struct audit_chunk, owners[0]);
2778f7b0ba1SAl Viro }
2788f7b0ba1SAl Viro
replace_mark_chunk(struct fsnotify_mark * mark,struct audit_chunk * chunk)279f905c2fcSJan Kara static void replace_mark_chunk(struct fsnotify_mark *mark,
28083d23bc8SJan Kara struct audit_chunk *chunk)
28183d23bc8SJan Kara {
28283d23bc8SJan Kara struct audit_chunk *old;
28383d23bc8SJan Kara
28483d23bc8SJan Kara assert_spin_locked(&hash_lock);
285f905c2fcSJan Kara old = mark_chunk(mark);
286f905c2fcSJan Kara audit_mark(mark)->chunk = chunk;
28783d23bc8SJan Kara if (chunk)
288f905c2fcSJan Kara chunk->mark = mark;
28983d23bc8SJan Kara if (old)
29083d23bc8SJan Kara old->mark = NULL;
29183d23bc8SJan Kara }
29283d23bc8SJan Kara
replace_chunk(struct audit_chunk * new,struct audit_chunk * old)293c22fcde7SJan Kara static void replace_chunk(struct audit_chunk *new, struct audit_chunk *old)
294d31b326dSJan Kara {
295d31b326dSJan Kara struct audit_tree *owner;
296d31b326dSJan Kara int i, j;
297d31b326dSJan Kara
298d31b326dSJan Kara new->key = old->key;
299d31b326dSJan Kara list_splice_init(&old->trees, &new->trees);
300d31b326dSJan Kara list_for_each_entry(owner, &new->trees, same_root)
301d31b326dSJan Kara owner->root = new;
302d31b326dSJan Kara for (i = j = 0; j < old->count; i++, j++) {
303c22fcde7SJan Kara if (!old->owners[j].owner) {
304d31b326dSJan Kara i--;
305d31b326dSJan Kara continue;
306d31b326dSJan Kara }
307d31b326dSJan Kara owner = old->owners[j].owner;
308d31b326dSJan Kara new->owners[i].owner = owner;
309d31b326dSJan Kara new->owners[i].index = old->owners[j].index - j + i;
310d31b326dSJan Kara if (!owner) /* result of earlier fallback */
311d31b326dSJan Kara continue;
312d31b326dSJan Kara get_tree(owner);
313d31b326dSJan Kara list_replace_init(&old->owners[j].list, &new->owners[i].list);
314d31b326dSJan Kara }
31583d23bc8SJan Kara replace_mark_chunk(old->mark, new);
316d31b326dSJan Kara /*
317d31b326dSJan Kara * Make sure chunk is fully initialized before making it visible in the
318d31b326dSJan Kara * hash. Pairs with a data dependency barrier in READ_ONCE() in
319d31b326dSJan Kara * audit_tree_lookup().
320d31b326dSJan Kara */
321d31b326dSJan Kara smp_wmb();
322d31b326dSJan Kara list_replace_rcu(&old->hash, &new->hash);
323d31b326dSJan Kara }
324d31b326dSJan Kara
remove_chunk_node(struct audit_chunk * chunk,struct audit_node * p)32557d4374bSChristophe Leroy static void remove_chunk_node(struct audit_chunk *chunk, struct audit_node *p)
32649a4ee7dSJan Kara {
32749a4ee7dSJan Kara struct audit_tree *owner = p->owner;
32849a4ee7dSJan Kara
32949a4ee7dSJan Kara if (owner->root == chunk) {
33049a4ee7dSJan Kara list_del_init(&owner->same_root);
33149a4ee7dSJan Kara owner->root = NULL;
33249a4ee7dSJan Kara }
33349a4ee7dSJan Kara list_del_init(&p->list);
33449a4ee7dSJan Kara p->owner = NULL;
33549a4ee7dSJan Kara put_tree(owner);
33649a4ee7dSJan Kara }
33749a4ee7dSJan Kara
chunk_count_trees(struct audit_chunk * chunk)338c22fcde7SJan Kara static int chunk_count_trees(struct audit_chunk *chunk)
339c22fcde7SJan Kara {
340c22fcde7SJan Kara int i;
341c22fcde7SJan Kara int ret = 0;
342c22fcde7SJan Kara
343c22fcde7SJan Kara for (i = 0; i < chunk->count; i++)
344c22fcde7SJan Kara if (chunk->owners[i].owner)
345c22fcde7SJan Kara ret++;
346c22fcde7SJan Kara return ret;
347c22fcde7SJan Kara }
348c22fcde7SJan Kara
untag_chunk(struct audit_chunk * chunk,struct fsnotify_mark * mark)349f905c2fcSJan Kara static void untag_chunk(struct audit_chunk *chunk, struct fsnotify_mark *mark)
3508f7b0ba1SAl Viro {
3518432c700SJan Kara struct audit_chunk *new;
352c22fcde7SJan Kara int size;
35374c3cbe3SAl Viro
354*960bdff2SAmir Goldstein fsnotify_group_lock(audit_tree_group);
3556b3f05d2SJan Kara /*
35683d23bc8SJan Kara * mark_mutex stabilizes chunk attached to the mark so we can check
35783d23bc8SJan Kara * whether it didn't change while we've dropped hash_lock.
3586b3f05d2SJan Kara */
359f905c2fcSJan Kara if (!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) ||
360f905c2fcSJan Kara mark_chunk(mark) != chunk)
3618432c700SJan Kara goto out_mutex;
36274c3cbe3SAl Viro
363c22fcde7SJan Kara size = chunk_count_trees(chunk);
36474c3cbe3SAl Viro if (!size) {
36574c3cbe3SAl Viro spin_lock(&hash_lock);
36674c3cbe3SAl Viro list_del_init(&chunk->trees);
36774c3cbe3SAl Viro list_del_rcu(&chunk->hash);
368f905c2fcSJan Kara replace_mark_chunk(mark, NULL);
36974c3cbe3SAl Viro spin_unlock(&hash_lock);
370f905c2fcSJan Kara fsnotify_detach_mark(mark);
371*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
37283d23bc8SJan Kara audit_mark_put_chunk(chunk);
373f905c2fcSJan Kara fsnotify_free_mark(mark);
3748432c700SJan Kara return;
37574c3cbe3SAl Viro }
37674c3cbe3SAl Viro
377c22fcde7SJan Kara new = alloc_chunk(size);
37874c3cbe3SAl Viro if (!new)
37949a4ee7dSJan Kara goto out_mutex;
380f7a998a9SAl Viro
38174c3cbe3SAl Viro spin_lock(&hash_lock);
3821635e572SJan Kara /*
383d31b326dSJan Kara * This has to go last when updating chunk as once replace_chunk() is
384d31b326dSJan Kara * called, new RCU readers can see the new chunk.
3851635e572SJan Kara */
386c22fcde7SJan Kara replace_chunk(new, chunk);
38774c3cbe3SAl Viro spin_unlock(&hash_lock);
388*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
38983d23bc8SJan Kara audit_mark_put_chunk(chunk);
3908432c700SJan Kara return;
39174c3cbe3SAl Viro
39249a4ee7dSJan Kara out_mutex:
393*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
39474c3cbe3SAl Viro }
39574c3cbe3SAl Viro
396a5789b07SJan Kara /* Call with group->mark_mutex held, releases it */
create_chunk(struct inode * inode,struct audit_tree * tree)39774c3cbe3SAl Viro static int create_chunk(struct inode *inode, struct audit_tree *tree)
39874c3cbe3SAl Viro {
399f905c2fcSJan Kara struct fsnotify_mark *mark;
40074c3cbe3SAl Viro struct audit_chunk *chunk = alloc_chunk(1);
401a5789b07SJan Kara
402a5789b07SJan Kara if (!chunk) {
403*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
40474c3cbe3SAl Viro return -ENOMEM;
405a5789b07SJan Kara }
40674c3cbe3SAl Viro
407f905c2fcSJan Kara mark = alloc_mark();
408f905c2fcSJan Kara if (!mark) {
409*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
41083d23bc8SJan Kara kfree(chunk);
41183d23bc8SJan Kara return -ENOMEM;
41283d23bc8SJan Kara }
41383d23bc8SJan Kara
414f905c2fcSJan Kara if (fsnotify_add_inode_mark_locked(mark, inode, 0)) {
415*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
416f905c2fcSJan Kara fsnotify_put_mark(mark);
41783d23bc8SJan Kara kfree(chunk);
41874c3cbe3SAl Viro return -ENOSPC;
41974c3cbe3SAl Viro }
42074c3cbe3SAl Viro
42174c3cbe3SAl Viro spin_lock(&hash_lock);
42274c3cbe3SAl Viro if (tree->goner) {
42374c3cbe3SAl Viro spin_unlock(&hash_lock);
424f905c2fcSJan Kara fsnotify_detach_mark(mark);
425*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
426f905c2fcSJan Kara fsnotify_free_mark(mark);
427f905c2fcSJan Kara fsnotify_put_mark(mark);
42883d23bc8SJan Kara kfree(chunk);
42974c3cbe3SAl Viro return 0;
43074c3cbe3SAl Viro }
431f905c2fcSJan Kara replace_mark_chunk(mark, chunk);
43274c3cbe3SAl Viro chunk->owners[0].index = (1U << 31);
43374c3cbe3SAl Viro chunk->owners[0].owner = tree;
43474c3cbe3SAl Viro get_tree(tree);
43574c3cbe3SAl Viro list_add(&chunk->owners[0].list, &tree->chunks);
43674c3cbe3SAl Viro if (!tree->root) {
43774c3cbe3SAl Viro tree->root = chunk;
43874c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees);
43974c3cbe3SAl Viro }
4408d20d6e9SJan Kara chunk->key = inode_to_key(inode);
4411635e572SJan Kara /*
4421635e572SJan Kara * Inserting into the hash table has to go last as once we do that RCU
4431635e572SJan Kara * readers can see the chunk.
4441635e572SJan Kara */
44574c3cbe3SAl Viro insert_hash(chunk);
44674c3cbe3SAl Viro spin_unlock(&hash_lock);
447*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
44883d23bc8SJan Kara /*
44983d23bc8SJan Kara * Drop our initial reference. When mark we point to is getting freed,
45083d23bc8SJan Kara * we get notification through ->freeing_mark callback and cleanup
45183d23bc8SJan Kara * chunk pointing to this mark.
45283d23bc8SJan Kara */
453f905c2fcSJan Kara fsnotify_put_mark(mark);
45474c3cbe3SAl Viro return 0;
45574c3cbe3SAl Viro }
45674c3cbe3SAl Viro
45774c3cbe3SAl Viro /* the first tagged inode becomes root of tree */
tag_chunk(struct inode * inode,struct audit_tree * tree)45874c3cbe3SAl Viro static int tag_chunk(struct inode *inode, struct audit_tree *tree)
45974c3cbe3SAl Viro {
460f905c2fcSJan Kara struct fsnotify_mark *mark;
46174c3cbe3SAl Viro struct audit_chunk *chunk, *old;
46257d4374bSChristophe Leroy struct audit_node *p;
46374c3cbe3SAl Viro int n;
46474c3cbe3SAl Viro
465*960bdff2SAmir Goldstein fsnotify_group_lock(audit_tree_group);
466f905c2fcSJan Kara mark = fsnotify_find_mark(&inode->i_fsnotify_marks, audit_tree_group);
467f905c2fcSJan Kara if (!mark)
46874c3cbe3SAl Viro return create_chunk(inode, tree);
46974c3cbe3SAl Viro
47083d23bc8SJan Kara /*
47183d23bc8SJan Kara * Found mark is guaranteed to be attached and mark_mutex protects mark
47283d23bc8SJan Kara * from getting detached and thus it makes sure there is chunk attached
47383d23bc8SJan Kara * to the mark.
47483d23bc8SJan Kara */
47574c3cbe3SAl Viro /* are we already there? */
47674c3cbe3SAl Viro spin_lock(&hash_lock);
477f905c2fcSJan Kara old = mark_chunk(mark);
47874c3cbe3SAl Viro for (n = 0; n < old->count; n++) {
47974c3cbe3SAl Viro if (old->owners[n].owner == tree) {
48074c3cbe3SAl Viro spin_unlock(&hash_lock);
481*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
482f905c2fcSJan Kara fsnotify_put_mark(mark);
48374c3cbe3SAl Viro return 0;
48474c3cbe3SAl Viro }
48574c3cbe3SAl Viro }
48674c3cbe3SAl Viro spin_unlock(&hash_lock);
48774c3cbe3SAl Viro
48874c3cbe3SAl Viro chunk = alloc_chunk(old->count + 1);
489b4c30aadSAl Viro if (!chunk) {
490*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
491f905c2fcSJan Kara fsnotify_put_mark(mark);
49274c3cbe3SAl Viro return -ENOMEM;
493b4c30aadSAl Viro }
49474c3cbe3SAl Viro
49574c3cbe3SAl Viro spin_lock(&hash_lock);
49674c3cbe3SAl Viro if (tree->goner) {
49774c3cbe3SAl Viro spin_unlock(&hash_lock);
498*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
499f905c2fcSJan Kara fsnotify_put_mark(mark);
50083d23bc8SJan Kara kfree(chunk);
50174c3cbe3SAl Viro return 0;
50274c3cbe3SAl Viro }
503d31b326dSJan Kara p = &chunk->owners[chunk->count - 1];
50474c3cbe3SAl Viro p->index = (chunk->count - 1) | (1U<<31);
50574c3cbe3SAl Viro p->owner = tree;
50674c3cbe3SAl Viro get_tree(tree);
50774c3cbe3SAl Viro list_add(&p->list, &tree->chunks);
50874c3cbe3SAl Viro if (!tree->root) {
50974c3cbe3SAl Viro tree->root = chunk;
51074c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees);
51174c3cbe3SAl Viro }
5121635e572SJan Kara /*
513d31b326dSJan Kara * This has to go last when updating chunk as once replace_chunk() is
514d31b326dSJan Kara * called, new RCU readers can see the new chunk.
5151635e572SJan Kara */
516c22fcde7SJan Kara replace_chunk(chunk, old);
51774c3cbe3SAl Viro spin_unlock(&hash_lock);
518*960bdff2SAmir Goldstein fsnotify_group_unlock(audit_tree_group);
519f905c2fcSJan Kara fsnotify_put_mark(mark); /* pair to fsnotify_find_mark */
52083d23bc8SJan Kara audit_mark_put_chunk(old);
52183d23bc8SJan Kara
52274c3cbe3SAl Viro return 0;
52374c3cbe3SAl Viro }
52474c3cbe3SAl Viro
audit_tree_log_remove_rule(struct audit_context * context,struct audit_krule * rule)5259e36a5d4SRichard Guy Briggs static void audit_tree_log_remove_rule(struct audit_context *context,
5269e36a5d4SRichard Guy Briggs struct audit_krule *rule)
52774c3cbe3SAl Viro {
52874c3cbe3SAl Viro struct audit_buffer *ab;
52974c3cbe3SAl Viro
53065a8766fSRichard Guy Briggs if (!audit_enabled)
53165a8766fSRichard Guy Briggs return;
5329e36a5d4SRichard Guy Briggs ab = audit_log_start(context, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
5330644ec0cSKees Cook if (unlikely(!ab))
5340644ec0cSKees Cook return;
535d0a3f18aSPaul Moore audit_log_format(ab, "op=remove_rule dir=");
53674c3cbe3SAl Viro audit_log_untrustedstring(ab, rule->tree->pathname);
5379d960985SEric Paris audit_log_key(ab, rule->filterkey);
53874c3cbe3SAl Viro audit_log_format(ab, " list=%d res=1", rule->listnr);
53974c3cbe3SAl Viro audit_log_end(ab);
5400644ec0cSKees Cook }
5410644ec0cSKees Cook
kill_rules(struct audit_context * context,struct audit_tree * tree)5429e36a5d4SRichard Guy Briggs static void kill_rules(struct audit_context *context, struct audit_tree *tree)
5430644ec0cSKees Cook {
5440644ec0cSKees Cook struct audit_krule *rule, *next;
5450644ec0cSKees Cook struct audit_entry *entry;
5460644ec0cSKees Cook
5470644ec0cSKees Cook list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
5480644ec0cSKees Cook entry = container_of(rule, struct audit_entry, rule);
5490644ec0cSKees Cook
5500644ec0cSKees Cook list_del_init(&rule->rlist);
5510644ec0cSKees Cook if (rule->tree) {
5520644ec0cSKees Cook /* not a half-baked one */
5539e36a5d4SRichard Guy Briggs audit_tree_log_remove_rule(context, rule);
55434d99af5SRichard Guy Briggs if (entry->rule.exe)
55534d99af5SRichard Guy Briggs audit_remove_mark(entry->rule.exe);
55674c3cbe3SAl Viro rule->tree = NULL;
55774c3cbe3SAl Viro list_del_rcu(&entry->list);
558e45aa212SAl Viro list_del(&entry->rule.list);
55974c3cbe3SAl Viro call_rcu(&entry->rcu, audit_free_rule_rcu);
56074c3cbe3SAl Viro }
56174c3cbe3SAl Viro }
56274c3cbe3SAl Viro }
56374c3cbe3SAl Viro
56474c3cbe3SAl Viro /*
5658432c700SJan Kara * Remove tree from chunks. If 'tagged' is set, remove tree only from tagged
5668432c700SJan Kara * chunks. The function expects tagged chunks are all at the beginning of the
5678432c700SJan Kara * chunks list.
56874c3cbe3SAl Viro */
prune_tree_chunks(struct audit_tree * victim,bool tagged)5698432c700SJan Kara static void prune_tree_chunks(struct audit_tree *victim, bool tagged)
57074c3cbe3SAl Viro {
57174c3cbe3SAl Viro spin_lock(&hash_lock);
57274c3cbe3SAl Viro while (!list_empty(&victim->chunks)) {
57357d4374bSChristophe Leroy struct audit_node *p;
5748432c700SJan Kara struct audit_chunk *chunk;
5758432c700SJan Kara struct fsnotify_mark *mark;
57674c3cbe3SAl Viro
57757d4374bSChristophe Leroy p = list_first_entry(&victim->chunks, struct audit_node, list);
5788432c700SJan Kara /* have we run out of marked? */
5798432c700SJan Kara if (tagged && !(p->index & (1U<<31)))
5808432c700SJan Kara break;
5818432c700SJan Kara chunk = find_chunk(p);
5828432c700SJan Kara mark = chunk->mark;
5838432c700SJan Kara remove_chunk_node(chunk, p);
58483d23bc8SJan Kara /* Racing with audit_tree_freeing_mark()? */
58583d23bc8SJan Kara if (!mark)
58683d23bc8SJan Kara continue;
5878432c700SJan Kara fsnotify_get_mark(mark);
5888432c700SJan Kara spin_unlock(&hash_lock);
58974c3cbe3SAl Viro
5908432c700SJan Kara untag_chunk(chunk, mark);
5918432c700SJan Kara fsnotify_put_mark(mark);
5928432c700SJan Kara
5938432c700SJan Kara spin_lock(&hash_lock);
59474c3cbe3SAl Viro }
59574c3cbe3SAl Viro spin_unlock(&hash_lock);
59674c3cbe3SAl Viro }
59774c3cbe3SAl Viro
5988432c700SJan Kara /*
5998432c700SJan Kara * finish killing struct audit_tree
6008432c700SJan Kara */
prune_one(struct audit_tree * victim)6018432c700SJan Kara static void prune_one(struct audit_tree *victim)
6028432c700SJan Kara {
6038432c700SJan Kara prune_tree_chunks(victim, false);
60467d69e9dSRichard Guy Briggs put_tree(victim);
6058432c700SJan Kara }
6068432c700SJan Kara
60774c3cbe3SAl Viro /* trim the uncommitted chunks from tree */
60874c3cbe3SAl Viro
trim_marked(struct audit_tree * tree)60974c3cbe3SAl Viro static void trim_marked(struct audit_tree *tree)
61074c3cbe3SAl Viro {
61174c3cbe3SAl Viro struct list_head *p, *q;
61274c3cbe3SAl Viro spin_lock(&hash_lock);
61374c3cbe3SAl Viro if (tree->goner) {
61474c3cbe3SAl Viro spin_unlock(&hash_lock);
61574c3cbe3SAl Viro return;
61674c3cbe3SAl Viro }
61774c3cbe3SAl Viro /* reorder */
61874c3cbe3SAl Viro for (p = tree->chunks.next; p != &tree->chunks; p = q) {
61957d4374bSChristophe Leroy struct audit_node *node = list_entry(p, struct audit_node, list);
62074c3cbe3SAl Viro q = p->next;
62174c3cbe3SAl Viro if (node->index & (1U<<31)) {
62274c3cbe3SAl Viro list_del_init(p);
62374c3cbe3SAl Viro list_add(p, &tree->chunks);
62474c3cbe3SAl Viro }
62574c3cbe3SAl Viro }
6268432c700SJan Kara spin_unlock(&hash_lock);
62774c3cbe3SAl Viro
6288432c700SJan Kara prune_tree_chunks(tree, true);
62974c3cbe3SAl Viro
6308432c700SJan Kara spin_lock(&hash_lock);
63174c3cbe3SAl Viro if (!tree->root && !tree->goner) {
63274c3cbe3SAl Viro tree->goner = 1;
63374c3cbe3SAl Viro spin_unlock(&hash_lock);
63474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
6359e36a5d4SRichard Guy Briggs kill_rules(audit_context(), tree);
63674c3cbe3SAl Viro list_del_init(&tree->list);
63774c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex);
63874c3cbe3SAl Viro prune_one(tree);
63974c3cbe3SAl Viro } else {
64074c3cbe3SAl Viro spin_unlock(&hash_lock);
64174c3cbe3SAl Viro }
64274c3cbe3SAl Viro }
64374c3cbe3SAl Viro
644916d7576SAl Viro static void audit_schedule_prune(void);
645916d7576SAl Viro
64674c3cbe3SAl Viro /* called with audit_filter_mutex */
audit_remove_tree_rule(struct audit_krule * rule)64774c3cbe3SAl Viro int audit_remove_tree_rule(struct audit_krule *rule)
64874c3cbe3SAl Viro {
64974c3cbe3SAl Viro struct audit_tree *tree;
65074c3cbe3SAl Viro tree = rule->tree;
65174c3cbe3SAl Viro if (tree) {
65274c3cbe3SAl Viro spin_lock(&hash_lock);
65374c3cbe3SAl Viro list_del_init(&rule->rlist);
65474c3cbe3SAl Viro if (list_empty(&tree->rules) && !tree->goner) {
65574c3cbe3SAl Viro tree->root = NULL;
65674c3cbe3SAl Viro list_del_init(&tree->same_root);
65774c3cbe3SAl Viro tree->goner = 1;
65874c3cbe3SAl Viro list_move(&tree->list, &prune_list);
65974c3cbe3SAl Viro rule->tree = NULL;
66074c3cbe3SAl Viro spin_unlock(&hash_lock);
66174c3cbe3SAl Viro audit_schedule_prune();
66274c3cbe3SAl Viro return 1;
66374c3cbe3SAl Viro }
66474c3cbe3SAl Viro rule->tree = NULL;
66574c3cbe3SAl Viro spin_unlock(&hash_lock);
66674c3cbe3SAl Viro return 1;
66774c3cbe3SAl Viro }
66874c3cbe3SAl Viro return 0;
66974c3cbe3SAl Viro }
67074c3cbe3SAl Viro
compare_root(struct vfsmount * mnt,void * arg)6711f707137SAl Viro static int compare_root(struct vfsmount *mnt, void *arg)
6721f707137SAl Viro {
673f410ff65SJan Kara return inode_to_key(d_backing_inode(mnt->mnt_root)) ==
674f410ff65SJan Kara (unsigned long)arg;
6751f707137SAl Viro }
6761f707137SAl Viro
audit_trim_trees(void)67774c3cbe3SAl Viro void audit_trim_trees(void)
67874c3cbe3SAl Viro {
67974c3cbe3SAl Viro struct list_head cursor;
68074c3cbe3SAl Viro
68174c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
68274c3cbe3SAl Viro list_add(&cursor, &tree_list);
68374c3cbe3SAl Viro while (cursor.next != &tree_list) {
68474c3cbe3SAl Viro struct audit_tree *tree;
68598bc993fSAl Viro struct path path;
68674c3cbe3SAl Viro struct vfsmount *root_mnt;
68757d4374bSChristophe Leroy struct audit_node *node;
68874c3cbe3SAl Viro int err;
68974c3cbe3SAl Viro
69074c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list);
69174c3cbe3SAl Viro get_tree(tree);
692dd8b865cSBaokun Li list_move(&cursor, &tree->list);
69374c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex);
69474c3cbe3SAl Viro
69598bc993fSAl Viro err = kern_path(tree->pathname, 0, &path);
69674c3cbe3SAl Viro if (err)
69774c3cbe3SAl Viro goto skip_it;
69874c3cbe3SAl Viro
699589ff870SAl Viro root_mnt = collect_mounts(&path);
70098bc993fSAl Viro path_put(&path);
701be34d1a3SDavid Howells if (IS_ERR(root_mnt))
70274c3cbe3SAl Viro goto skip_it;
70374c3cbe3SAl Viro
70474c3cbe3SAl Viro spin_lock(&hash_lock);
70574c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) {
70628a3a7ebSEric Paris struct audit_chunk *chunk = find_chunk(node);
70725985edcSLucas De Marchi /* this could be NULL if the watch is dying else where... */
70874c3cbe3SAl Viro node->index |= 1U<<31;
709f410ff65SJan Kara if (iterate_mounts(compare_root,
7108d20d6e9SJan Kara (void *)(chunk->key),
711f410ff65SJan Kara root_mnt))
71274c3cbe3SAl Viro node->index &= ~(1U<<31);
71374c3cbe3SAl Viro }
71474c3cbe3SAl Viro spin_unlock(&hash_lock);
71574c3cbe3SAl Viro trim_marked(tree);
71674c3cbe3SAl Viro drop_collected_mounts(root_mnt);
71774c3cbe3SAl Viro skip_it:
71812b2f117SChen Gang put_tree(tree);
71974c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
72074c3cbe3SAl Viro }
72174c3cbe3SAl Viro list_del(&cursor);
72274c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex);
72374c3cbe3SAl Viro }
72474c3cbe3SAl Viro
audit_make_tree(struct audit_krule * rule,char * pathname,u32 op)72574c3cbe3SAl Viro int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
72674c3cbe3SAl Viro {
72774c3cbe3SAl Viro
72874c3cbe3SAl Viro if (pathname[0] != '/' ||
72967daf270SPaul Moore (rule->listnr != AUDIT_FILTER_EXIT &&
73067daf270SPaul Moore rule->listnr != AUDIT_FILTER_URING_EXIT) ||
7315af75d8dSAl Viro op != Audit_equal ||
73274c3cbe3SAl Viro rule->inode_f || rule->watch || rule->tree)
73374c3cbe3SAl Viro return -EINVAL;
73474c3cbe3SAl Viro rule->tree = alloc_tree(pathname);
73574c3cbe3SAl Viro if (!rule->tree)
73674c3cbe3SAl Viro return -ENOMEM;
73774c3cbe3SAl Viro return 0;
73874c3cbe3SAl Viro }
73974c3cbe3SAl Viro
audit_put_tree(struct audit_tree * tree)74074c3cbe3SAl Viro void audit_put_tree(struct audit_tree *tree)
74174c3cbe3SAl Viro {
74274c3cbe3SAl Viro put_tree(tree);
74374c3cbe3SAl Viro }
74474c3cbe3SAl Viro
tag_mount(struct vfsmount * mnt,void * arg)7451f707137SAl Viro static int tag_mount(struct vfsmount *mnt, void *arg)
7461f707137SAl Viro {
7473b362157SDavid Howells return tag_chunk(d_backing_inode(mnt->mnt_root), arg);
7481f707137SAl Viro }
7491f707137SAl Viro
750f1aaf262SImre Palik /*
751f1aaf262SImre Palik * That gets run when evict_chunk() ends up needing to kill audit_tree.
752f1aaf262SImre Palik * Runs from a separate thread.
753f1aaf262SImre Palik */
prune_tree_thread(void * unused)754f1aaf262SImre Palik static int prune_tree_thread(void *unused)
755f1aaf262SImre Palik {
756f1aaf262SImre Palik for (;;) {
7570bf676d1SJiri Slaby if (list_empty(&prune_list)) {
758f1aaf262SImre Palik set_current_state(TASK_INTERRUPTIBLE);
759f1aaf262SImre Palik schedule();
7600bf676d1SJiri Slaby }
761f1aaf262SImre Palik
762ce423631SPaul Moore audit_ctl_lock();
763f1aaf262SImre Palik mutex_lock(&audit_filter_mutex);
764f1aaf262SImre Palik
765f1aaf262SImre Palik while (!list_empty(&prune_list)) {
766f1aaf262SImre Palik struct audit_tree *victim;
767f1aaf262SImre Palik
768f1aaf262SImre Palik victim = list_entry(prune_list.next,
769f1aaf262SImre Palik struct audit_tree, list);
770f1aaf262SImre Palik list_del_init(&victim->list);
771f1aaf262SImre Palik
772f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex);
773f1aaf262SImre Palik
774f1aaf262SImre Palik prune_one(victim);
775f1aaf262SImre Palik
776f1aaf262SImre Palik mutex_lock(&audit_filter_mutex);
777f1aaf262SImre Palik }
778f1aaf262SImre Palik
779f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex);
780ce423631SPaul Moore audit_ctl_unlock();
781f1aaf262SImre Palik }
782f1aaf262SImre Palik return 0;
783f1aaf262SImre Palik }
784f1aaf262SImre Palik
audit_launch_prune(void)785f1aaf262SImre Palik static int audit_launch_prune(void)
786f1aaf262SImre Palik {
787f1aaf262SImre Palik if (prune_thread)
788f1aaf262SImre Palik return 0;
7890bf676d1SJiri Slaby prune_thread = kthread_run(prune_tree_thread, NULL,
790f1aaf262SImre Palik "audit_prune_tree");
791f1aaf262SImre Palik if (IS_ERR(prune_thread)) {
792f1aaf262SImre Palik pr_err("cannot start thread audit_prune_tree");
793f1aaf262SImre Palik prune_thread = NULL;
794f1aaf262SImre Palik return -ENOMEM;
795f1aaf262SImre Palik }
7960bf676d1SJiri Slaby return 0;
797f1aaf262SImre Palik }
798f1aaf262SImre Palik
79974c3cbe3SAl Viro /* called with audit_filter_mutex */
audit_add_tree_rule(struct audit_krule * rule)80074c3cbe3SAl Viro int audit_add_tree_rule(struct audit_krule *rule)
80174c3cbe3SAl Viro {
80274c3cbe3SAl Viro struct audit_tree *seed = rule->tree, *tree;
80398bc993fSAl Viro struct path path;
8041f707137SAl Viro struct vfsmount *mnt;
80574c3cbe3SAl Viro int err;
80674c3cbe3SAl Viro
807736f3203SChen Gang rule->tree = NULL;
80874c3cbe3SAl Viro list_for_each_entry(tree, &tree_list, list) {
80974c3cbe3SAl Viro if (!strcmp(seed->pathname, tree->pathname)) {
81074c3cbe3SAl Viro put_tree(seed);
81174c3cbe3SAl Viro rule->tree = tree;
81274c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules);
81374c3cbe3SAl Viro return 0;
81474c3cbe3SAl Viro }
81574c3cbe3SAl Viro }
81674c3cbe3SAl Viro tree = seed;
81774c3cbe3SAl Viro list_add(&tree->list, &tree_list);
81874c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules);
81974c3cbe3SAl Viro /* do not set rule->tree yet */
82074c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex);
82174c3cbe3SAl Viro
822f1aaf262SImre Palik if (unlikely(!prune_thread)) {
823f1aaf262SImre Palik err = audit_launch_prune();
824f1aaf262SImre Palik if (err)
825f1aaf262SImre Palik goto Err;
826f1aaf262SImre Palik }
827f1aaf262SImre Palik
82898bc993fSAl Viro err = kern_path(tree->pathname, 0, &path);
82974c3cbe3SAl Viro if (err)
83074c3cbe3SAl Viro goto Err;
831589ff870SAl Viro mnt = collect_mounts(&path);
83298bc993fSAl Viro path_put(&path);
833be34d1a3SDavid Howells if (IS_ERR(mnt)) {
834be34d1a3SDavid Howells err = PTR_ERR(mnt);
83574c3cbe3SAl Viro goto Err;
83674c3cbe3SAl Viro }
83774c3cbe3SAl Viro
83874c3cbe3SAl Viro get_tree(tree);
8391f707137SAl Viro err = iterate_mounts(tag_mount, tree, mnt);
84074c3cbe3SAl Viro drop_collected_mounts(mnt);
84174c3cbe3SAl Viro
84274c3cbe3SAl Viro if (!err) {
84357d4374bSChristophe Leroy struct audit_node *node;
84474c3cbe3SAl Viro spin_lock(&hash_lock);
84574c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list)
84674c3cbe3SAl Viro node->index &= ~(1U<<31);
84774c3cbe3SAl Viro spin_unlock(&hash_lock);
84874c3cbe3SAl Viro } else {
84974c3cbe3SAl Viro trim_marked(tree);
85074c3cbe3SAl Viro goto Err;
85174c3cbe3SAl Viro }
85274c3cbe3SAl Viro
85374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
85474c3cbe3SAl Viro if (list_empty(&rule->rlist)) {
85574c3cbe3SAl Viro put_tree(tree);
85674c3cbe3SAl Viro return -ENOENT;
85774c3cbe3SAl Viro }
85874c3cbe3SAl Viro rule->tree = tree;
85974c3cbe3SAl Viro put_tree(tree);
86074c3cbe3SAl Viro
86174c3cbe3SAl Viro return 0;
86274c3cbe3SAl Viro Err:
86374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
86474c3cbe3SAl Viro list_del_init(&tree->list);
86574c3cbe3SAl Viro list_del_init(&tree->rules);
86674c3cbe3SAl Viro put_tree(tree);
86774c3cbe3SAl Viro return err;
86874c3cbe3SAl Viro }
86974c3cbe3SAl Viro
audit_tag_tree(char * old,char * new)87074c3cbe3SAl Viro int audit_tag_tree(char *old, char *new)
87174c3cbe3SAl Viro {
87274c3cbe3SAl Viro struct list_head cursor, barrier;
87374c3cbe3SAl Viro int failed = 0;
8742096f759SAl Viro struct path path1, path2;
87574c3cbe3SAl Viro struct vfsmount *tagged;
87674c3cbe3SAl Viro int err;
87774c3cbe3SAl Viro
8782096f759SAl Viro err = kern_path(new, 0, &path2);
87974c3cbe3SAl Viro if (err)
88074c3cbe3SAl Viro return err;
8812096f759SAl Viro tagged = collect_mounts(&path2);
8822096f759SAl Viro path_put(&path2);
883be34d1a3SDavid Howells if (IS_ERR(tagged))
884be34d1a3SDavid Howells return PTR_ERR(tagged);
88574c3cbe3SAl Viro
8862096f759SAl Viro err = kern_path(old, 0, &path1);
88774c3cbe3SAl Viro if (err) {
88874c3cbe3SAl Viro drop_collected_mounts(tagged);
88974c3cbe3SAl Viro return err;
89074c3cbe3SAl Viro }
89174c3cbe3SAl Viro
89274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
89374c3cbe3SAl Viro list_add(&barrier, &tree_list);
89474c3cbe3SAl Viro list_add(&cursor, &barrier);
89574c3cbe3SAl Viro
89674c3cbe3SAl Viro while (cursor.next != &tree_list) {
89774c3cbe3SAl Viro struct audit_tree *tree;
8982096f759SAl Viro int good_one = 0;
89974c3cbe3SAl Viro
90074c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list);
90174c3cbe3SAl Viro get_tree(tree);
902dd8b865cSBaokun Li list_move(&cursor, &tree->list);
90374c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex);
90474c3cbe3SAl Viro
9052096f759SAl Viro err = kern_path(tree->pathname, 0, &path2);
9062096f759SAl Viro if (!err) {
9072096f759SAl Viro good_one = path_is_under(&path1, &path2);
9082096f759SAl Viro path_put(&path2);
90974c3cbe3SAl Viro }
91074c3cbe3SAl Viro
9112096f759SAl Viro if (!good_one) {
91274c3cbe3SAl Viro put_tree(tree);
91374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
91474c3cbe3SAl Viro continue;
91574c3cbe3SAl Viro }
91674c3cbe3SAl Viro
9171f707137SAl Viro failed = iterate_mounts(tag_mount, tree, tagged);
91874c3cbe3SAl Viro if (failed) {
91974c3cbe3SAl Viro put_tree(tree);
92074c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
92174c3cbe3SAl Viro break;
92274c3cbe3SAl Viro }
92374c3cbe3SAl Viro
92474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
92574c3cbe3SAl Viro spin_lock(&hash_lock);
92674c3cbe3SAl Viro if (!tree->goner) {
927dd8b865cSBaokun Li list_move(&tree->list, &tree_list);
92874c3cbe3SAl Viro }
92974c3cbe3SAl Viro spin_unlock(&hash_lock);
93074c3cbe3SAl Viro put_tree(tree);
93174c3cbe3SAl Viro }
93274c3cbe3SAl Viro
93374c3cbe3SAl Viro while (barrier.prev != &tree_list) {
93474c3cbe3SAl Viro struct audit_tree *tree;
93574c3cbe3SAl Viro
93674c3cbe3SAl Viro tree = container_of(barrier.prev, struct audit_tree, list);
93774c3cbe3SAl Viro get_tree(tree);
938dd8b865cSBaokun Li list_move(&tree->list, &barrier);
93974c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex);
94074c3cbe3SAl Viro
94174c3cbe3SAl Viro if (!failed) {
94257d4374bSChristophe Leroy struct audit_node *node;
94374c3cbe3SAl Viro spin_lock(&hash_lock);
94474c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list)
94574c3cbe3SAl Viro node->index &= ~(1U<<31);
94674c3cbe3SAl Viro spin_unlock(&hash_lock);
94774c3cbe3SAl Viro } else {
94874c3cbe3SAl Viro trim_marked(tree);
94974c3cbe3SAl Viro }
95074c3cbe3SAl Viro
95174c3cbe3SAl Viro put_tree(tree);
95274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
95374c3cbe3SAl Viro }
95474c3cbe3SAl Viro list_del(&barrier);
95574c3cbe3SAl Viro list_del(&cursor);
95674c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex);
9572096f759SAl Viro path_put(&path1);
95874c3cbe3SAl Viro drop_collected_mounts(tagged);
95974c3cbe3SAl Viro return failed;
96074c3cbe3SAl Viro }
96174c3cbe3SAl Viro
962916d7576SAl Viro
audit_schedule_prune(void)963916d7576SAl Viro static void audit_schedule_prune(void)
964916d7576SAl Viro {
965f1aaf262SImre Palik wake_up_process(prune_thread);
966916d7576SAl Viro }
967916d7576SAl Viro
968916d7576SAl Viro /*
969916d7576SAl Viro * ... and that one is done if evict_chunk() decides to delay until the end
970916d7576SAl Viro * of syscall. Runs synchronously.
971916d7576SAl Viro */
audit_kill_trees(struct audit_context * context)9729e36a5d4SRichard Guy Briggs void audit_kill_trees(struct audit_context *context)
973916d7576SAl Viro {
9749e36a5d4SRichard Guy Briggs struct list_head *list = &context->killed_trees;
9759e36a5d4SRichard Guy Briggs
976ce423631SPaul Moore audit_ctl_lock();
977916d7576SAl Viro mutex_lock(&audit_filter_mutex);
978916d7576SAl Viro
979916d7576SAl Viro while (!list_empty(list)) {
980916d7576SAl Viro struct audit_tree *victim;
981916d7576SAl Viro
982916d7576SAl Viro victim = list_entry(list->next, struct audit_tree, list);
9839e36a5d4SRichard Guy Briggs kill_rules(context, victim);
984916d7576SAl Viro list_del_init(&victim->list);
985916d7576SAl Viro
986916d7576SAl Viro mutex_unlock(&audit_filter_mutex);
987916d7576SAl Viro
988916d7576SAl Viro prune_one(victim);
989916d7576SAl Viro
990916d7576SAl Viro mutex_lock(&audit_filter_mutex);
991916d7576SAl Viro }
992916d7576SAl Viro
993916d7576SAl Viro mutex_unlock(&audit_filter_mutex);
994ce423631SPaul Moore audit_ctl_unlock();
99574c3cbe3SAl Viro }
99674c3cbe3SAl Viro
99774c3cbe3SAl Viro /*
99874c3cbe3SAl Viro * Here comes the stuff asynchronous to auditctl operations
99974c3cbe3SAl Viro */
100074c3cbe3SAl Viro
evict_chunk(struct audit_chunk * chunk)100174c3cbe3SAl Viro static void evict_chunk(struct audit_chunk *chunk)
100274c3cbe3SAl Viro {
100374c3cbe3SAl Viro struct audit_tree *owner;
1004916d7576SAl Viro struct list_head *postponed = audit_killed_trees();
1005916d7576SAl Viro int need_prune = 0;
100674c3cbe3SAl Viro int n;
100774c3cbe3SAl Viro
100874c3cbe3SAl Viro mutex_lock(&audit_filter_mutex);
100974c3cbe3SAl Viro spin_lock(&hash_lock);
101074c3cbe3SAl Viro while (!list_empty(&chunk->trees)) {
101174c3cbe3SAl Viro owner = list_entry(chunk->trees.next,
101274c3cbe3SAl Viro struct audit_tree, same_root);
101374c3cbe3SAl Viro owner->goner = 1;
101474c3cbe3SAl Viro owner->root = NULL;
101574c3cbe3SAl Viro list_del_init(&owner->same_root);
101674c3cbe3SAl Viro spin_unlock(&hash_lock);
1017916d7576SAl Viro if (!postponed) {
10189e36a5d4SRichard Guy Briggs kill_rules(audit_context(), owner);
101974c3cbe3SAl Viro list_move(&owner->list, &prune_list);
1020916d7576SAl Viro need_prune = 1;
1021916d7576SAl Viro } else {
1022916d7576SAl Viro list_move(&owner->list, postponed);
1023916d7576SAl Viro }
102474c3cbe3SAl Viro spin_lock(&hash_lock);
102574c3cbe3SAl Viro }
102674c3cbe3SAl Viro list_del_rcu(&chunk->hash);
102774c3cbe3SAl Viro for (n = 0; n < chunk->count; n++)
102874c3cbe3SAl Viro list_del_init(&chunk->owners[n].list);
102974c3cbe3SAl Viro spin_unlock(&hash_lock);
1030f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex);
1031916d7576SAl Viro if (need_prune)
1032916d7576SAl Viro audit_schedule_prune();
103374c3cbe3SAl Viro }
103474c3cbe3SAl Viro
audit_tree_handle_event(struct fsnotify_mark * mark,u32 mask,struct inode * inode,struct inode * dir,const struct qstr * file_name,u32 cookie)1035b9a1b977SAmir Goldstein static int audit_tree_handle_event(struct fsnotify_mark *mark, u32 mask,
1036b9a1b977SAmir Goldstein struct inode *inode, struct inode *dir,
1037950cc0d2SAmir Goldstein const struct qstr *file_name, u32 cookie)
103874c3cbe3SAl Viro {
103983c4c4b0SJan Kara return 0;
104028a3a7ebSEric Paris }
104174c3cbe3SAl Viro
audit_tree_freeing_mark(struct fsnotify_mark * mark,struct fsnotify_group * group)1042f905c2fcSJan Kara static void audit_tree_freeing_mark(struct fsnotify_mark *mark,
1043f905c2fcSJan Kara struct fsnotify_group *group)
104428a3a7ebSEric Paris {
104583d23bc8SJan Kara struct audit_chunk *chunk;
104628a3a7ebSEric Paris
1047*960bdff2SAmir Goldstein fsnotify_group_lock(mark->group);
104883d23bc8SJan Kara spin_lock(&hash_lock);
1049f905c2fcSJan Kara chunk = mark_chunk(mark);
1050f905c2fcSJan Kara replace_mark_chunk(mark, NULL);
105183d23bc8SJan Kara spin_unlock(&hash_lock);
1052*960bdff2SAmir Goldstein fsnotify_group_unlock(mark->group);
105383d23bc8SJan Kara if (chunk) {
105474c3cbe3SAl Viro evict_chunk(chunk);
105583d23bc8SJan Kara audit_mark_put_chunk(chunk);
105683d23bc8SJan Kara }
1057b3e8692bSMiklos Szeredi
1058b3e8692bSMiklos Szeredi /*
1059b3e8692bSMiklos Szeredi * We are guaranteed to have at least one reference to the mark from
1060b3e8692bSMiklos Szeredi * either the inode or the caller of fsnotify_destroy_mark().
1061b3e8692bSMiklos Szeredi */
1062f905c2fcSJan Kara BUG_ON(refcount_read(&mark->refcnt) < 1);
106374c3cbe3SAl Viro }
106474c3cbe3SAl Viro
106528a3a7ebSEric Paris static const struct fsnotify_ops audit_tree_ops = {
1066b9a1b977SAmir Goldstein .handle_inode_event = audit_tree_handle_event,
106728a3a7ebSEric Paris .freeing_mark = audit_tree_freeing_mark,
1068054c636eSJan Kara .free_mark = audit_tree_destroy_watch,
106974c3cbe3SAl Viro };
107074c3cbe3SAl Viro
audit_tree_init(void)107174c3cbe3SAl Viro static int __init audit_tree_init(void)
107274c3cbe3SAl Viro {
107374c3cbe3SAl Viro int i;
107474c3cbe3SAl Viro
10755f516130SJan Kara audit_tree_mark_cachep = KMEM_CACHE(audit_tree_mark, SLAB_PANIC);
10765f516130SJan Kara
1077867a448dSAmir Goldstein audit_tree_group = fsnotify_alloc_group(&audit_tree_ops, 0);
107828a3a7ebSEric Paris if (IS_ERR(audit_tree_group))
107928a3a7ebSEric Paris audit_panic("cannot initialize fsnotify group for rectree watches");
108074c3cbe3SAl Viro
108174c3cbe3SAl Viro for (i = 0; i < HASH_SIZE; i++)
108274c3cbe3SAl Viro INIT_LIST_HEAD(&chunk_hash_heads[i]);
108374c3cbe3SAl Viro
108474c3cbe3SAl Viro return 0;
108574c3cbe3SAl Viro }
108674c3cbe3SAl Viro __initcall(audit_tree_init);
1087