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); 253d0775441SEric Paris fsnotify_destroy_mark(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); 2625444e298SEric Paris if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 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); 296d0775441SEric Paris fsnotify_destroy_mark(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; 3255444e298SEric Paris if (fsnotify_add_mark(entry, audit_tree_group, inode, NULL, 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); 336d0775441SEric Paris fsnotify_destroy_mark(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 3635444e298SEric Paris old_entry = fsnotify_find_inode_mark(audit_tree_group, inode); 36428a3a7ebSEric Paris if (!old_entry) 36574c3cbe3SAl Viro return create_chunk(inode, tree); 36674c3cbe3SAl Viro 36728a3a7ebSEric Paris old = container_of(old_entry, struct audit_chunk, mark); 36874c3cbe3SAl Viro 36974c3cbe3SAl Viro /* are we already there? */ 37074c3cbe3SAl Viro spin_lock(&hash_lock); 37174c3cbe3SAl Viro for (n = 0; n < old->count; n++) { 37274c3cbe3SAl Viro if (old->owners[n].owner == tree) { 37374c3cbe3SAl Viro spin_unlock(&hash_lock); 37428a3a7ebSEric Paris fsnotify_put_mark(old_entry); 37574c3cbe3SAl Viro return 0; 37674c3cbe3SAl Viro } 37774c3cbe3SAl Viro } 37874c3cbe3SAl Viro spin_unlock(&hash_lock); 37974c3cbe3SAl Viro 38074c3cbe3SAl Viro chunk = alloc_chunk(old->count + 1); 381b4c30aadSAl Viro if (!chunk) { 38228a3a7ebSEric Paris fsnotify_put_mark(old_entry); 38374c3cbe3SAl Viro return -ENOMEM; 384b4c30aadSAl Viro } 38574c3cbe3SAl Viro 38628a3a7ebSEric Paris chunk_entry = &chunk->mark; 38728a3a7ebSEric Paris 38828a3a7ebSEric Paris spin_lock(&old_entry->lock); 3892823e04dSEric Paris if (!old_entry->i.inode) { 39028a3a7ebSEric Paris /* old_entry is being shot, lets just lie */ 39128a3a7ebSEric Paris spin_unlock(&old_entry->lock); 39228a3a7ebSEric Paris fsnotify_put_mark(old_entry); 39374c3cbe3SAl Viro free_chunk(chunk); 39428a3a7ebSEric Paris return -ENOENT; 39528a3a7ebSEric Paris } 39628a3a7ebSEric Paris 39728a3a7ebSEric Paris fsnotify_duplicate_mark(chunk_entry, old_entry); 3985444e298SEric Paris if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, NULL, 1)) { 39928a3a7ebSEric Paris spin_unlock(&old_entry->lock); 40028a3a7ebSEric Paris free_chunk(chunk); 40128a3a7ebSEric Paris fsnotify_put_mark(old_entry); 40274c3cbe3SAl Viro return -ENOSPC; 40374c3cbe3SAl Viro } 40428a3a7ebSEric Paris 40528a3a7ebSEric Paris /* even though we hold old_entry->lock, this is safe since chunk_entry->lock could NEVER have been grabbed before */ 40628a3a7ebSEric Paris spin_lock(&chunk_entry->lock); 40774c3cbe3SAl Viro spin_lock(&hash_lock); 40828a3a7ebSEric Paris 40928a3a7ebSEric Paris /* we now hold old_entry->lock, chunk_entry->lock, and hash_lock */ 41074c3cbe3SAl Viro if (tree->goner) { 41174c3cbe3SAl Viro spin_unlock(&hash_lock); 41274c3cbe3SAl Viro chunk->dead = 1; 41328a3a7ebSEric Paris spin_unlock(&chunk_entry->lock); 41428a3a7ebSEric Paris spin_unlock(&old_entry->lock); 41528a3a7ebSEric Paris 416d0775441SEric Paris fsnotify_destroy_mark(chunk_entry); 41728a3a7ebSEric Paris 41828a3a7ebSEric Paris fsnotify_put_mark(chunk_entry); 41928a3a7ebSEric Paris fsnotify_put_mark(old_entry); 42074c3cbe3SAl Viro return 0; 42174c3cbe3SAl Viro } 42274c3cbe3SAl Viro list_replace_init(&old->trees, &chunk->trees); 42374c3cbe3SAl Viro for (n = 0, p = chunk->owners; n < old->count; n++, p++) { 42474c3cbe3SAl Viro struct audit_tree *s = old->owners[n].owner; 42574c3cbe3SAl Viro p->owner = s; 42674c3cbe3SAl Viro p->index = old->owners[n].index; 42774c3cbe3SAl Viro if (!s) /* result of fallback in untag */ 42874c3cbe3SAl Viro continue; 42974c3cbe3SAl Viro get_tree(s); 43074c3cbe3SAl Viro list_replace_init(&old->owners[n].list, &p->list); 43174c3cbe3SAl Viro } 43274c3cbe3SAl Viro p->index = (chunk->count - 1) | (1U<<31); 43374c3cbe3SAl Viro p->owner = tree; 43474c3cbe3SAl Viro get_tree(tree); 43574c3cbe3SAl Viro list_add(&p->list, &tree->chunks); 43674c3cbe3SAl Viro list_replace_rcu(&old->hash, &chunk->hash); 43774c3cbe3SAl Viro list_for_each_entry(owner, &chunk->trees, same_root) 43874c3cbe3SAl Viro owner->root = chunk; 43974c3cbe3SAl Viro old->dead = 1; 44074c3cbe3SAl Viro if (!tree->root) { 44174c3cbe3SAl Viro tree->root = chunk; 44274c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees); 44374c3cbe3SAl Viro } 44474c3cbe3SAl Viro spin_unlock(&hash_lock); 44528a3a7ebSEric Paris spin_unlock(&chunk_entry->lock); 44628a3a7ebSEric Paris spin_unlock(&old_entry->lock); 447d0775441SEric Paris fsnotify_destroy_mark(old_entry); 44828a3a7ebSEric Paris fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ 44928a3a7ebSEric Paris fsnotify_put_mark(old_entry); /* and kill it */ 45074c3cbe3SAl Viro return 0; 45174c3cbe3SAl Viro } 45274c3cbe3SAl Viro 45374c3cbe3SAl Viro static void kill_rules(struct audit_tree *tree) 45474c3cbe3SAl Viro { 45574c3cbe3SAl Viro struct audit_krule *rule, *next; 45674c3cbe3SAl Viro struct audit_entry *entry; 45774c3cbe3SAl Viro struct audit_buffer *ab; 45874c3cbe3SAl Viro 45974c3cbe3SAl Viro list_for_each_entry_safe(rule, next, &tree->rules, rlist) { 46074c3cbe3SAl Viro entry = container_of(rule, struct audit_entry, rule); 46174c3cbe3SAl Viro 46274c3cbe3SAl Viro list_del_init(&rule->rlist); 46374c3cbe3SAl Viro if (rule->tree) { 46474c3cbe3SAl Viro /* not a half-baked one */ 46574c3cbe3SAl Viro ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); 4669d960985SEric Paris audit_log_format(ab, "op="); 4679d960985SEric Paris audit_log_string(ab, "remove rule"); 4689d960985SEric Paris audit_log_format(ab, " dir="); 46974c3cbe3SAl Viro audit_log_untrustedstring(ab, rule->tree->pathname); 4709d960985SEric Paris audit_log_key(ab, rule->filterkey); 47174c3cbe3SAl Viro audit_log_format(ab, " list=%d res=1", rule->listnr); 47274c3cbe3SAl Viro audit_log_end(ab); 47374c3cbe3SAl Viro rule->tree = NULL; 47474c3cbe3SAl Viro list_del_rcu(&entry->list); 475e45aa212SAl Viro list_del(&entry->rule.list); 47674c3cbe3SAl Viro call_rcu(&entry->rcu, audit_free_rule_rcu); 47774c3cbe3SAl Viro } 47874c3cbe3SAl Viro } 47974c3cbe3SAl Viro } 48074c3cbe3SAl Viro 48174c3cbe3SAl Viro /* 48274c3cbe3SAl Viro * finish killing struct audit_tree 48374c3cbe3SAl Viro */ 48474c3cbe3SAl Viro static void prune_one(struct audit_tree *victim) 48574c3cbe3SAl Viro { 48674c3cbe3SAl Viro spin_lock(&hash_lock); 48774c3cbe3SAl Viro while (!list_empty(&victim->chunks)) { 48874c3cbe3SAl Viro struct node *p; 48974c3cbe3SAl Viro 49074c3cbe3SAl Viro p = list_entry(victim->chunks.next, struct node, list); 49174c3cbe3SAl Viro 4928f7b0ba1SAl Viro untag_chunk(p); 49374c3cbe3SAl Viro } 49474c3cbe3SAl Viro spin_unlock(&hash_lock); 49574c3cbe3SAl Viro put_tree(victim); 49674c3cbe3SAl Viro } 49774c3cbe3SAl Viro 49874c3cbe3SAl Viro /* trim the uncommitted chunks from tree */ 49974c3cbe3SAl Viro 50074c3cbe3SAl Viro static void trim_marked(struct audit_tree *tree) 50174c3cbe3SAl Viro { 50274c3cbe3SAl Viro struct list_head *p, *q; 50374c3cbe3SAl Viro spin_lock(&hash_lock); 50474c3cbe3SAl Viro if (tree->goner) { 50574c3cbe3SAl Viro spin_unlock(&hash_lock); 50674c3cbe3SAl Viro return; 50774c3cbe3SAl Viro } 50874c3cbe3SAl Viro /* reorder */ 50974c3cbe3SAl Viro for (p = tree->chunks.next; p != &tree->chunks; p = q) { 51074c3cbe3SAl Viro struct node *node = list_entry(p, struct node, list); 51174c3cbe3SAl Viro q = p->next; 51274c3cbe3SAl Viro if (node->index & (1U<<31)) { 51374c3cbe3SAl Viro list_del_init(p); 51474c3cbe3SAl Viro list_add(p, &tree->chunks); 51574c3cbe3SAl Viro } 51674c3cbe3SAl Viro } 51774c3cbe3SAl Viro 51874c3cbe3SAl Viro while (!list_empty(&tree->chunks)) { 51974c3cbe3SAl Viro struct node *node; 52074c3cbe3SAl Viro 52174c3cbe3SAl Viro node = list_entry(tree->chunks.next, struct node, list); 52274c3cbe3SAl Viro 52374c3cbe3SAl Viro /* have we run out of marked? */ 52474c3cbe3SAl Viro if (!(node->index & (1U<<31))) 52574c3cbe3SAl Viro break; 52674c3cbe3SAl Viro 5278f7b0ba1SAl Viro untag_chunk(node); 52874c3cbe3SAl Viro } 52974c3cbe3SAl Viro if (!tree->root && !tree->goner) { 53074c3cbe3SAl Viro tree->goner = 1; 53174c3cbe3SAl Viro spin_unlock(&hash_lock); 53274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 53374c3cbe3SAl Viro kill_rules(tree); 53474c3cbe3SAl Viro list_del_init(&tree->list); 53574c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 53674c3cbe3SAl Viro prune_one(tree); 53774c3cbe3SAl Viro } else { 53874c3cbe3SAl Viro spin_unlock(&hash_lock); 53974c3cbe3SAl Viro } 54074c3cbe3SAl Viro } 54174c3cbe3SAl Viro 542916d7576SAl Viro static void audit_schedule_prune(void); 543916d7576SAl Viro 54474c3cbe3SAl Viro /* called with audit_filter_mutex */ 54574c3cbe3SAl Viro int audit_remove_tree_rule(struct audit_krule *rule) 54674c3cbe3SAl Viro { 54774c3cbe3SAl Viro struct audit_tree *tree; 54874c3cbe3SAl Viro tree = rule->tree; 54974c3cbe3SAl Viro if (tree) { 55074c3cbe3SAl Viro spin_lock(&hash_lock); 55174c3cbe3SAl Viro list_del_init(&rule->rlist); 55274c3cbe3SAl Viro if (list_empty(&tree->rules) && !tree->goner) { 55374c3cbe3SAl Viro tree->root = NULL; 55474c3cbe3SAl Viro list_del_init(&tree->same_root); 55574c3cbe3SAl Viro tree->goner = 1; 55674c3cbe3SAl Viro list_move(&tree->list, &prune_list); 55774c3cbe3SAl Viro rule->tree = NULL; 55874c3cbe3SAl Viro spin_unlock(&hash_lock); 55974c3cbe3SAl Viro audit_schedule_prune(); 56074c3cbe3SAl Viro return 1; 56174c3cbe3SAl Viro } 56274c3cbe3SAl Viro rule->tree = NULL; 56374c3cbe3SAl Viro spin_unlock(&hash_lock); 56474c3cbe3SAl Viro return 1; 56574c3cbe3SAl Viro } 56674c3cbe3SAl Viro return 0; 56774c3cbe3SAl Viro } 56874c3cbe3SAl Viro 5691f707137SAl Viro static int compare_root(struct vfsmount *mnt, void *arg) 5701f707137SAl Viro { 5711f707137SAl Viro return mnt->mnt_root->d_inode == arg; 5721f707137SAl Viro } 5731f707137SAl Viro 57474c3cbe3SAl Viro void audit_trim_trees(void) 57574c3cbe3SAl Viro { 57674c3cbe3SAl Viro struct list_head cursor; 57774c3cbe3SAl Viro 57874c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 57974c3cbe3SAl Viro list_add(&cursor, &tree_list); 58074c3cbe3SAl Viro while (cursor.next != &tree_list) { 58174c3cbe3SAl Viro struct audit_tree *tree; 58298bc993fSAl Viro struct path path; 58374c3cbe3SAl Viro struct vfsmount *root_mnt; 58474c3cbe3SAl Viro struct node *node; 58574c3cbe3SAl Viro int err; 58674c3cbe3SAl Viro 58774c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 58874c3cbe3SAl Viro get_tree(tree); 58974c3cbe3SAl Viro list_del(&cursor); 59074c3cbe3SAl Viro list_add(&cursor, &tree->list); 59174c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 59274c3cbe3SAl Viro 59398bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 59474c3cbe3SAl Viro if (err) 59574c3cbe3SAl Viro goto skip_it; 59674c3cbe3SAl Viro 597589ff870SAl Viro root_mnt = collect_mounts(&path); 59898bc993fSAl Viro path_put(&path); 59974c3cbe3SAl Viro if (!root_mnt) 60074c3cbe3SAl Viro goto skip_it; 60174c3cbe3SAl Viro 60274c3cbe3SAl Viro spin_lock(&hash_lock); 60374c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) { 60428a3a7ebSEric Paris struct audit_chunk *chunk = find_chunk(node); 60528a3a7ebSEric Paris /* this could be NULL if the watch is dieing else where... */ 6062823e04dSEric Paris struct inode *inode = chunk->mark.i.inode; 60774c3cbe3SAl Viro node->index |= 1U<<31; 6081f707137SAl Viro if (iterate_mounts(compare_root, inode, root_mnt)) 60974c3cbe3SAl Viro node->index &= ~(1U<<31); 61074c3cbe3SAl Viro } 61174c3cbe3SAl Viro spin_unlock(&hash_lock); 61274c3cbe3SAl Viro trim_marked(tree); 61374c3cbe3SAl Viro put_tree(tree); 61474c3cbe3SAl Viro drop_collected_mounts(root_mnt); 61574c3cbe3SAl Viro skip_it: 61674c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 61774c3cbe3SAl Viro } 61874c3cbe3SAl Viro list_del(&cursor); 61974c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 62074c3cbe3SAl Viro } 62174c3cbe3SAl Viro 62274c3cbe3SAl Viro int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) 62374c3cbe3SAl Viro { 62474c3cbe3SAl Viro 62574c3cbe3SAl Viro if (pathname[0] != '/' || 62674c3cbe3SAl Viro rule->listnr != AUDIT_FILTER_EXIT || 6275af75d8dSAl Viro op != Audit_equal || 62874c3cbe3SAl Viro rule->inode_f || rule->watch || rule->tree) 62974c3cbe3SAl Viro return -EINVAL; 63074c3cbe3SAl Viro rule->tree = alloc_tree(pathname); 63174c3cbe3SAl Viro if (!rule->tree) 63274c3cbe3SAl Viro return -ENOMEM; 63374c3cbe3SAl Viro return 0; 63474c3cbe3SAl Viro } 63574c3cbe3SAl Viro 63674c3cbe3SAl Viro void audit_put_tree(struct audit_tree *tree) 63774c3cbe3SAl Viro { 63874c3cbe3SAl Viro put_tree(tree); 63974c3cbe3SAl Viro } 64074c3cbe3SAl Viro 6411f707137SAl Viro static int tag_mount(struct vfsmount *mnt, void *arg) 6421f707137SAl Viro { 6431f707137SAl Viro return tag_chunk(mnt->mnt_root->d_inode, arg); 6441f707137SAl Viro } 6451f707137SAl Viro 64674c3cbe3SAl Viro /* called with audit_filter_mutex */ 64774c3cbe3SAl Viro int audit_add_tree_rule(struct audit_krule *rule) 64874c3cbe3SAl Viro { 64974c3cbe3SAl Viro struct audit_tree *seed = rule->tree, *tree; 65098bc993fSAl Viro struct path path; 6511f707137SAl Viro struct vfsmount *mnt; 65274c3cbe3SAl Viro int err; 65374c3cbe3SAl Viro 65474c3cbe3SAl Viro list_for_each_entry(tree, &tree_list, list) { 65574c3cbe3SAl Viro if (!strcmp(seed->pathname, tree->pathname)) { 65674c3cbe3SAl Viro put_tree(seed); 65774c3cbe3SAl Viro rule->tree = tree; 65874c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 65974c3cbe3SAl Viro return 0; 66074c3cbe3SAl Viro } 66174c3cbe3SAl Viro } 66274c3cbe3SAl Viro tree = seed; 66374c3cbe3SAl Viro list_add(&tree->list, &tree_list); 66474c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 66574c3cbe3SAl Viro /* do not set rule->tree yet */ 66674c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 66774c3cbe3SAl Viro 66898bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 66974c3cbe3SAl Viro if (err) 67074c3cbe3SAl Viro goto Err; 671589ff870SAl Viro mnt = collect_mounts(&path); 67298bc993fSAl Viro path_put(&path); 67374c3cbe3SAl Viro if (!mnt) { 67474c3cbe3SAl Viro err = -ENOMEM; 67574c3cbe3SAl Viro goto Err; 67674c3cbe3SAl Viro } 67774c3cbe3SAl Viro 67874c3cbe3SAl Viro get_tree(tree); 6791f707137SAl Viro err = iterate_mounts(tag_mount, tree, mnt); 68074c3cbe3SAl Viro drop_collected_mounts(mnt); 68174c3cbe3SAl Viro 68274c3cbe3SAl Viro if (!err) { 68374c3cbe3SAl Viro struct node *node; 68474c3cbe3SAl Viro spin_lock(&hash_lock); 68574c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 68674c3cbe3SAl Viro node->index &= ~(1U<<31); 68774c3cbe3SAl Viro spin_unlock(&hash_lock); 68874c3cbe3SAl Viro } else { 68974c3cbe3SAl Viro trim_marked(tree); 69074c3cbe3SAl Viro goto Err; 69174c3cbe3SAl Viro } 69274c3cbe3SAl Viro 69374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 69474c3cbe3SAl Viro if (list_empty(&rule->rlist)) { 69574c3cbe3SAl Viro put_tree(tree); 69674c3cbe3SAl Viro return -ENOENT; 69774c3cbe3SAl Viro } 69874c3cbe3SAl Viro rule->tree = tree; 69974c3cbe3SAl Viro put_tree(tree); 70074c3cbe3SAl Viro 70174c3cbe3SAl Viro return 0; 70274c3cbe3SAl Viro Err: 70374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 70474c3cbe3SAl Viro list_del_init(&tree->list); 70574c3cbe3SAl Viro list_del_init(&tree->rules); 70674c3cbe3SAl Viro put_tree(tree); 70774c3cbe3SAl Viro return err; 70874c3cbe3SAl Viro } 70974c3cbe3SAl Viro 71074c3cbe3SAl Viro int audit_tag_tree(char *old, char *new) 71174c3cbe3SAl Viro { 71274c3cbe3SAl Viro struct list_head cursor, barrier; 71374c3cbe3SAl Viro int failed = 0; 7142096f759SAl Viro struct path path1, path2; 71574c3cbe3SAl Viro struct vfsmount *tagged; 71674c3cbe3SAl Viro int err; 71774c3cbe3SAl Viro 7182096f759SAl Viro err = kern_path(new, 0, &path2); 71974c3cbe3SAl Viro if (err) 72074c3cbe3SAl Viro return err; 7212096f759SAl Viro tagged = collect_mounts(&path2); 7222096f759SAl Viro path_put(&path2); 72374c3cbe3SAl Viro if (!tagged) 72474c3cbe3SAl Viro return -ENOMEM; 72574c3cbe3SAl Viro 7262096f759SAl Viro err = kern_path(old, 0, &path1); 72774c3cbe3SAl Viro if (err) { 72874c3cbe3SAl Viro drop_collected_mounts(tagged); 72974c3cbe3SAl Viro return err; 73074c3cbe3SAl Viro } 73174c3cbe3SAl Viro 73274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 73374c3cbe3SAl Viro list_add(&barrier, &tree_list); 73474c3cbe3SAl Viro list_add(&cursor, &barrier); 73574c3cbe3SAl Viro 73674c3cbe3SAl Viro while (cursor.next != &tree_list) { 73774c3cbe3SAl Viro struct audit_tree *tree; 7382096f759SAl Viro int good_one = 0; 73974c3cbe3SAl Viro 74074c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 74174c3cbe3SAl Viro get_tree(tree); 74274c3cbe3SAl Viro list_del(&cursor); 74374c3cbe3SAl Viro list_add(&cursor, &tree->list); 74474c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 74574c3cbe3SAl Viro 7462096f759SAl Viro err = kern_path(tree->pathname, 0, &path2); 7472096f759SAl Viro if (!err) { 7482096f759SAl Viro good_one = path_is_under(&path1, &path2); 7492096f759SAl Viro path_put(&path2); 75074c3cbe3SAl Viro } 75174c3cbe3SAl Viro 7522096f759SAl Viro if (!good_one) { 75374c3cbe3SAl Viro put_tree(tree); 75474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 75574c3cbe3SAl Viro continue; 75674c3cbe3SAl Viro } 75774c3cbe3SAl Viro 7581f707137SAl Viro failed = iterate_mounts(tag_mount, tree, tagged); 75974c3cbe3SAl Viro if (failed) { 76074c3cbe3SAl Viro put_tree(tree); 76174c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 76274c3cbe3SAl Viro break; 76374c3cbe3SAl Viro } 76474c3cbe3SAl Viro 76574c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 76674c3cbe3SAl Viro spin_lock(&hash_lock); 76774c3cbe3SAl Viro if (!tree->goner) { 76874c3cbe3SAl Viro list_del(&tree->list); 76974c3cbe3SAl Viro list_add(&tree->list, &tree_list); 77074c3cbe3SAl Viro } 77174c3cbe3SAl Viro spin_unlock(&hash_lock); 77274c3cbe3SAl Viro put_tree(tree); 77374c3cbe3SAl Viro } 77474c3cbe3SAl Viro 77574c3cbe3SAl Viro while (barrier.prev != &tree_list) { 77674c3cbe3SAl Viro struct audit_tree *tree; 77774c3cbe3SAl Viro 77874c3cbe3SAl Viro tree = container_of(barrier.prev, struct audit_tree, list); 77974c3cbe3SAl Viro get_tree(tree); 78074c3cbe3SAl Viro list_del(&tree->list); 78174c3cbe3SAl Viro list_add(&tree->list, &barrier); 78274c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 78374c3cbe3SAl Viro 78474c3cbe3SAl Viro if (!failed) { 78574c3cbe3SAl Viro struct node *node; 78674c3cbe3SAl Viro spin_lock(&hash_lock); 78774c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 78874c3cbe3SAl Viro node->index &= ~(1U<<31); 78974c3cbe3SAl Viro spin_unlock(&hash_lock); 79074c3cbe3SAl Viro } else { 79174c3cbe3SAl Viro trim_marked(tree); 79274c3cbe3SAl Viro } 79374c3cbe3SAl Viro 79474c3cbe3SAl Viro put_tree(tree); 79574c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 79674c3cbe3SAl Viro } 79774c3cbe3SAl Viro list_del(&barrier); 79874c3cbe3SAl Viro list_del(&cursor); 79974c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 8002096f759SAl Viro path_put(&path1); 80174c3cbe3SAl Viro drop_collected_mounts(tagged); 80274c3cbe3SAl Viro return failed; 80374c3cbe3SAl Viro } 80474c3cbe3SAl Viro 80574c3cbe3SAl Viro /* 80674c3cbe3SAl Viro * That gets run when evict_chunk() ends up needing to kill audit_tree. 807916d7576SAl Viro * Runs from a separate thread. 80874c3cbe3SAl Viro */ 809916d7576SAl Viro static int prune_tree_thread(void *unused) 81074c3cbe3SAl Viro { 811916d7576SAl Viro mutex_lock(&audit_cmd_mutex); 81274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 81374c3cbe3SAl Viro 81474c3cbe3SAl Viro while (!list_empty(&prune_list)) { 81574c3cbe3SAl Viro struct audit_tree *victim; 81674c3cbe3SAl Viro 81774c3cbe3SAl Viro victim = list_entry(prune_list.next, struct audit_tree, list); 81874c3cbe3SAl Viro list_del_init(&victim->list); 81974c3cbe3SAl Viro 82074c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 82174c3cbe3SAl Viro 82274c3cbe3SAl Viro prune_one(victim); 82374c3cbe3SAl Viro 82474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 82574c3cbe3SAl Viro } 82674c3cbe3SAl Viro 82774c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 828916d7576SAl Viro mutex_unlock(&audit_cmd_mutex); 829916d7576SAl Viro return 0; 830916d7576SAl Viro } 831916d7576SAl Viro 832916d7576SAl Viro static void audit_schedule_prune(void) 833916d7576SAl Viro { 834916d7576SAl Viro kthread_run(prune_tree_thread, NULL, "audit_prune_tree"); 835916d7576SAl Viro } 836916d7576SAl Viro 837916d7576SAl Viro /* 838916d7576SAl Viro * ... and that one is done if evict_chunk() decides to delay until the end 839916d7576SAl Viro * of syscall. Runs synchronously. 840916d7576SAl Viro */ 841916d7576SAl Viro void audit_kill_trees(struct list_head *list) 842916d7576SAl Viro { 843916d7576SAl Viro mutex_lock(&audit_cmd_mutex); 844916d7576SAl Viro mutex_lock(&audit_filter_mutex); 845916d7576SAl Viro 846916d7576SAl Viro while (!list_empty(list)) { 847916d7576SAl Viro struct audit_tree *victim; 848916d7576SAl Viro 849916d7576SAl Viro victim = list_entry(list->next, struct audit_tree, list); 850916d7576SAl Viro kill_rules(victim); 851916d7576SAl Viro list_del_init(&victim->list); 852916d7576SAl Viro 853916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 854916d7576SAl Viro 855916d7576SAl Viro prune_one(victim); 856916d7576SAl Viro 857916d7576SAl Viro mutex_lock(&audit_filter_mutex); 858916d7576SAl Viro } 859916d7576SAl Viro 860916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 861916d7576SAl Viro mutex_unlock(&audit_cmd_mutex); 86274c3cbe3SAl Viro } 86374c3cbe3SAl Viro 86474c3cbe3SAl Viro /* 86574c3cbe3SAl Viro * Here comes the stuff asynchronous to auditctl operations 86674c3cbe3SAl Viro */ 86774c3cbe3SAl Viro 86874c3cbe3SAl Viro static void evict_chunk(struct audit_chunk *chunk) 86974c3cbe3SAl Viro { 87074c3cbe3SAl Viro struct audit_tree *owner; 871916d7576SAl Viro struct list_head *postponed = audit_killed_trees(); 872916d7576SAl Viro int need_prune = 0; 87374c3cbe3SAl Viro int n; 87474c3cbe3SAl Viro 87574c3cbe3SAl Viro if (chunk->dead) 87674c3cbe3SAl Viro return; 87774c3cbe3SAl Viro 87874c3cbe3SAl Viro chunk->dead = 1; 87974c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 88074c3cbe3SAl Viro spin_lock(&hash_lock); 88174c3cbe3SAl Viro while (!list_empty(&chunk->trees)) { 88274c3cbe3SAl Viro owner = list_entry(chunk->trees.next, 88374c3cbe3SAl Viro struct audit_tree, same_root); 88474c3cbe3SAl Viro owner->goner = 1; 88574c3cbe3SAl Viro owner->root = NULL; 88674c3cbe3SAl Viro list_del_init(&owner->same_root); 88774c3cbe3SAl Viro spin_unlock(&hash_lock); 888916d7576SAl Viro if (!postponed) { 88974c3cbe3SAl Viro kill_rules(owner); 89074c3cbe3SAl Viro list_move(&owner->list, &prune_list); 891916d7576SAl Viro need_prune = 1; 892916d7576SAl Viro } else { 893916d7576SAl Viro list_move(&owner->list, postponed); 894916d7576SAl Viro } 89574c3cbe3SAl Viro spin_lock(&hash_lock); 89674c3cbe3SAl Viro } 89774c3cbe3SAl Viro list_del_rcu(&chunk->hash); 89874c3cbe3SAl Viro for (n = 0; n < chunk->count; n++) 89974c3cbe3SAl Viro list_del_init(&chunk->owners[n].list); 90074c3cbe3SAl Viro spin_unlock(&hash_lock); 901916d7576SAl Viro if (need_prune) 902916d7576SAl Viro audit_schedule_prune(); 90374c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 90474c3cbe3SAl Viro } 90574c3cbe3SAl Viro 9063a9b16b4SEric Paris static int audit_tree_handle_event(struct fsnotify_group *group, 907ce8f76fbSEric Paris struct fsnotify_mark *inode_mark, 908ce8f76fbSEric Paris struct fsnotify_mark *vfsmonut_mark, 9093a9b16b4SEric Paris struct fsnotify_event *event) 91074c3cbe3SAl Viro { 91128a3a7ebSEric Paris BUG(); 91228a3a7ebSEric Paris return -EOPNOTSUPP; 91328a3a7ebSEric Paris } 91474c3cbe3SAl Viro 915e61ce867SEric Paris static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group) 91628a3a7ebSEric Paris { 91728a3a7ebSEric Paris struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark); 91828a3a7ebSEric Paris 91974c3cbe3SAl Viro evict_chunk(chunk); 92028a3a7ebSEric Paris fsnotify_put_mark(entry); 92174c3cbe3SAl Viro } 92274c3cbe3SAl Viro 9237b0a04fbSEric Paris static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode, 924ce8f76fbSEric Paris struct vfsmount *mnt, struct fsnotify_mark *inode_mark, 925ce8f76fbSEric Paris struct fsnotify_mark *vfsmount_mark, 9263a9b16b4SEric Paris __u32 mask, void *data, int data_type) 92774c3cbe3SAl Viro { 9282612abb5SEric Paris return false; 92974c3cbe3SAl Viro } 93074c3cbe3SAl Viro 93128a3a7ebSEric Paris static const struct fsnotify_ops audit_tree_ops = { 93228a3a7ebSEric Paris .handle_event = audit_tree_handle_event, 93328a3a7ebSEric Paris .should_send_event = audit_tree_send_event, 93428a3a7ebSEric Paris .free_group_priv = NULL, 93528a3a7ebSEric Paris .free_event_priv = NULL, 93628a3a7ebSEric Paris .freeing_mark = audit_tree_freeing_mark, 93774c3cbe3SAl Viro }; 93874c3cbe3SAl Viro 93974c3cbe3SAl Viro static int __init audit_tree_init(void) 94074c3cbe3SAl Viro { 94174c3cbe3SAl Viro int i; 94274c3cbe3SAl Viro 9430d2e2a1dSEric Paris audit_tree_group = fsnotify_alloc_group(&audit_tree_ops); 94428a3a7ebSEric Paris if (IS_ERR(audit_tree_group)) 94528a3a7ebSEric Paris audit_panic("cannot initialize fsnotify group for rectree watches"); 94674c3cbe3SAl Viro 94774c3cbe3SAl Viro for (i = 0; i < HASH_SIZE; i++) 94874c3cbe3SAl Viro INIT_LIST_HEAD(&chunk_hash_heads[i]); 94974c3cbe3SAl Viro 95074c3cbe3SAl Viro return 0; 95174c3cbe3SAl Viro } 95274c3cbe3SAl Viro __initcall(audit_tree_init); 953