174c3cbe3SAl Viro #include "audit.h" 274c3cbe3SAl Viro #include <linux/inotify.h> 374c3cbe3SAl Viro #include <linux/namei.h> 474c3cbe3SAl Viro #include <linux/mount.h> 5916d7576SAl Viro #include <linux/kthread.h> 674c3cbe3SAl Viro 774c3cbe3SAl Viro struct audit_tree; 874c3cbe3SAl Viro struct audit_chunk; 974c3cbe3SAl Viro 1074c3cbe3SAl Viro struct audit_tree { 1174c3cbe3SAl Viro atomic_t count; 1274c3cbe3SAl Viro int goner; 1374c3cbe3SAl Viro struct audit_chunk *root; 1474c3cbe3SAl Viro struct list_head chunks; 1574c3cbe3SAl Viro struct list_head rules; 1674c3cbe3SAl Viro struct list_head list; 1774c3cbe3SAl Viro struct list_head same_root; 1874c3cbe3SAl Viro struct rcu_head head; 1974c3cbe3SAl Viro char pathname[]; 2074c3cbe3SAl Viro }; 2174c3cbe3SAl Viro 2274c3cbe3SAl Viro struct audit_chunk { 2374c3cbe3SAl Viro struct list_head hash; 2474c3cbe3SAl Viro struct inotify_watch watch; 2574c3cbe3SAl Viro struct list_head trees; /* with root here */ 2674c3cbe3SAl Viro int dead; 2774c3cbe3SAl Viro int count; 288f7b0ba1SAl Viro atomic_long_t refs; 2974c3cbe3SAl Viro struct rcu_head head; 3074c3cbe3SAl Viro struct node { 3174c3cbe3SAl Viro struct list_head list; 3274c3cbe3SAl Viro struct audit_tree *owner; 3374c3cbe3SAl Viro unsigned index; /* index; upper bit indicates 'will prune' */ 3474c3cbe3SAl Viro } owners[]; 3574c3cbe3SAl Viro }; 3674c3cbe3SAl Viro 3774c3cbe3SAl Viro static LIST_HEAD(tree_list); 3874c3cbe3SAl Viro static LIST_HEAD(prune_list); 3974c3cbe3SAl Viro 4074c3cbe3SAl Viro /* 4174c3cbe3SAl Viro * One struct chunk is attached to each inode of interest. 4274c3cbe3SAl Viro * We replace struct chunk on tagging/untagging. 4374c3cbe3SAl Viro * Rules have pointer to struct audit_tree. 4474c3cbe3SAl Viro * Rules have struct list_head rlist forming a list of rules over 4574c3cbe3SAl Viro * the same tree. 4674c3cbe3SAl Viro * References to struct chunk are collected at audit_inode{,_child}() 4774c3cbe3SAl Viro * time and used in AUDIT_TREE rule matching. 4874c3cbe3SAl Viro * These references are dropped at the same time we are calling 4974c3cbe3SAl Viro * audit_free_names(), etc. 5074c3cbe3SAl Viro * 5174c3cbe3SAl Viro * Cyclic lists galore: 5274c3cbe3SAl Viro * tree.chunks anchors chunk.owners[].list hash_lock 5374c3cbe3SAl Viro * tree.rules anchors rule.rlist audit_filter_mutex 5474c3cbe3SAl Viro * chunk.trees anchors tree.same_root hash_lock 5574c3cbe3SAl Viro * chunk.hash is a hash with middle bits of watch.inode as 5674c3cbe3SAl Viro * a hash function. RCU, hash_lock 5774c3cbe3SAl Viro * 5874c3cbe3SAl Viro * tree is refcounted; one reference for "some rules on rules_list refer to 5974c3cbe3SAl Viro * it", one for each chunk with pointer to it. 6074c3cbe3SAl Viro * 618f7b0ba1SAl Viro * chunk is refcounted by embedded inotify_watch + .refs (non-zero refcount 628f7b0ba1SAl Viro * of watch contributes 1 to .refs). 6374c3cbe3SAl Viro * 6474c3cbe3SAl Viro * node.index allows to get from node.list to containing chunk. 6574c3cbe3SAl Viro * MSB of that sucker is stolen to mark taggings that we might have to 6674c3cbe3SAl Viro * revert - several operations have very unpleasant cleanup logics and 6774c3cbe3SAl Viro * that makes a difference. Some. 6874c3cbe3SAl Viro */ 6974c3cbe3SAl Viro 7074c3cbe3SAl Viro static struct inotify_handle *rtree_ih; 7174c3cbe3SAl Viro 7274c3cbe3SAl Viro static struct audit_tree *alloc_tree(const char *s) 7374c3cbe3SAl Viro { 7474c3cbe3SAl Viro struct audit_tree *tree; 7574c3cbe3SAl Viro 7674c3cbe3SAl Viro tree = kmalloc(sizeof(struct audit_tree) + strlen(s) + 1, GFP_KERNEL); 7774c3cbe3SAl Viro if (tree) { 7874c3cbe3SAl Viro atomic_set(&tree->count, 1); 7974c3cbe3SAl Viro tree->goner = 0; 8074c3cbe3SAl Viro INIT_LIST_HEAD(&tree->chunks); 8174c3cbe3SAl Viro INIT_LIST_HEAD(&tree->rules); 8274c3cbe3SAl Viro INIT_LIST_HEAD(&tree->list); 8374c3cbe3SAl Viro INIT_LIST_HEAD(&tree->same_root); 8474c3cbe3SAl Viro tree->root = NULL; 8574c3cbe3SAl Viro strcpy(tree->pathname, s); 8674c3cbe3SAl Viro } 8774c3cbe3SAl Viro return tree; 8874c3cbe3SAl Viro } 8974c3cbe3SAl Viro 9074c3cbe3SAl Viro static inline void get_tree(struct audit_tree *tree) 9174c3cbe3SAl Viro { 9274c3cbe3SAl Viro atomic_inc(&tree->count); 9374c3cbe3SAl Viro } 9474c3cbe3SAl Viro 9574c3cbe3SAl Viro static void __put_tree(struct rcu_head *rcu) 9674c3cbe3SAl Viro { 9774c3cbe3SAl Viro struct audit_tree *tree = container_of(rcu, struct audit_tree, head); 9874c3cbe3SAl Viro kfree(tree); 9974c3cbe3SAl Viro } 10074c3cbe3SAl Viro 10174c3cbe3SAl Viro static inline void put_tree(struct audit_tree *tree) 10274c3cbe3SAl Viro { 10374c3cbe3SAl Viro if (atomic_dec_and_test(&tree->count)) 10474c3cbe3SAl Viro call_rcu(&tree->head, __put_tree); 10574c3cbe3SAl Viro } 10674c3cbe3SAl Viro 10774c3cbe3SAl Viro /* to avoid bringing the entire thing in audit.h */ 10874c3cbe3SAl Viro const char *audit_tree_path(struct audit_tree *tree) 10974c3cbe3SAl Viro { 11074c3cbe3SAl Viro return tree->pathname; 11174c3cbe3SAl Viro } 11274c3cbe3SAl Viro 11374c3cbe3SAl Viro static struct audit_chunk *alloc_chunk(int count) 11474c3cbe3SAl Viro { 11574c3cbe3SAl Viro struct audit_chunk *chunk; 11674c3cbe3SAl Viro size_t size; 11774c3cbe3SAl Viro int i; 11874c3cbe3SAl Viro 11974c3cbe3SAl Viro size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node); 12074c3cbe3SAl Viro chunk = kzalloc(size, GFP_KERNEL); 12174c3cbe3SAl Viro if (!chunk) 12274c3cbe3SAl Viro return NULL; 12374c3cbe3SAl Viro 12474c3cbe3SAl Viro INIT_LIST_HEAD(&chunk->hash); 12574c3cbe3SAl Viro INIT_LIST_HEAD(&chunk->trees); 12674c3cbe3SAl Viro chunk->count = count; 1278f7b0ba1SAl Viro atomic_long_set(&chunk->refs, 1); 12874c3cbe3SAl Viro for (i = 0; i < count; i++) { 12974c3cbe3SAl Viro INIT_LIST_HEAD(&chunk->owners[i].list); 13074c3cbe3SAl Viro chunk->owners[i].index = i; 13174c3cbe3SAl Viro } 13274c3cbe3SAl Viro inotify_init_watch(&chunk->watch); 13374c3cbe3SAl Viro return chunk; 13474c3cbe3SAl Viro } 13574c3cbe3SAl Viro 1368f7b0ba1SAl Viro static void free_chunk(struct audit_chunk *chunk) 13774c3cbe3SAl Viro { 13874c3cbe3SAl Viro int i; 13974c3cbe3SAl Viro 14074c3cbe3SAl Viro for (i = 0; i < chunk->count; i++) { 14174c3cbe3SAl Viro if (chunk->owners[i].owner) 14274c3cbe3SAl Viro put_tree(chunk->owners[i].owner); 14374c3cbe3SAl Viro } 14474c3cbe3SAl Viro kfree(chunk); 14574c3cbe3SAl Viro } 14674c3cbe3SAl Viro 14774c3cbe3SAl Viro void audit_put_chunk(struct audit_chunk *chunk) 14874c3cbe3SAl Viro { 1498f7b0ba1SAl Viro if (atomic_long_dec_and_test(&chunk->refs)) 1508f7b0ba1SAl Viro free_chunk(chunk); 1518f7b0ba1SAl Viro } 1528f7b0ba1SAl Viro 1538f7b0ba1SAl Viro static void __put_chunk(struct rcu_head *rcu) 1548f7b0ba1SAl Viro { 1558f7b0ba1SAl Viro struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head); 1568f7b0ba1SAl Viro audit_put_chunk(chunk); 15774c3cbe3SAl Viro } 15874c3cbe3SAl Viro 15974c3cbe3SAl Viro enum {HASH_SIZE = 128}; 16074c3cbe3SAl Viro static struct list_head chunk_hash_heads[HASH_SIZE]; 16174c3cbe3SAl Viro static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock); 16274c3cbe3SAl Viro 16374c3cbe3SAl Viro static inline struct list_head *chunk_hash(const struct inode *inode) 16474c3cbe3SAl Viro { 16574c3cbe3SAl Viro unsigned long n = (unsigned long)inode / L1_CACHE_BYTES; 16674c3cbe3SAl Viro return chunk_hash_heads + n % HASH_SIZE; 16774c3cbe3SAl Viro } 16874c3cbe3SAl Viro 16974c3cbe3SAl Viro /* hash_lock is held by caller */ 17074c3cbe3SAl Viro static void insert_hash(struct audit_chunk *chunk) 17174c3cbe3SAl Viro { 17274c3cbe3SAl Viro struct list_head *list = chunk_hash(chunk->watch.inode); 17374c3cbe3SAl Viro list_add_rcu(&chunk->hash, list); 17474c3cbe3SAl Viro } 17574c3cbe3SAl Viro 17674c3cbe3SAl Viro /* called under rcu_read_lock */ 17774c3cbe3SAl Viro struct audit_chunk *audit_tree_lookup(const struct inode *inode) 17874c3cbe3SAl Viro { 17974c3cbe3SAl Viro struct list_head *list = chunk_hash(inode); 1806793a051SPaul E. McKenney struct audit_chunk *p; 18174c3cbe3SAl Viro 1826793a051SPaul E. McKenney list_for_each_entry_rcu(p, list, hash) { 18374c3cbe3SAl Viro if (p->watch.inode == inode) { 1848f7b0ba1SAl Viro atomic_long_inc(&p->refs); 18574c3cbe3SAl Viro return p; 18674c3cbe3SAl Viro } 18774c3cbe3SAl Viro } 18874c3cbe3SAl Viro return NULL; 18974c3cbe3SAl Viro } 19074c3cbe3SAl Viro 19174c3cbe3SAl Viro int audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree) 19274c3cbe3SAl Viro { 19374c3cbe3SAl Viro int n; 19474c3cbe3SAl Viro for (n = 0; n < chunk->count; n++) 19574c3cbe3SAl Viro if (chunk->owners[n].owner == tree) 19674c3cbe3SAl Viro return 1; 19774c3cbe3SAl Viro return 0; 19874c3cbe3SAl Viro } 19974c3cbe3SAl Viro 20074c3cbe3SAl Viro /* tagging and untagging inodes with trees */ 20174c3cbe3SAl Viro 2028f7b0ba1SAl Viro static struct audit_chunk *find_chunk(struct node *p) 20374c3cbe3SAl Viro { 2048f7b0ba1SAl Viro int index = p->index & ~(1U<<31); 2058f7b0ba1SAl Viro p -= index; 2068f7b0ba1SAl Viro return container_of(p, struct audit_chunk, owners[0]); 2078f7b0ba1SAl Viro } 2088f7b0ba1SAl Viro 2098f7b0ba1SAl Viro static void untag_chunk(struct node *p) 2108f7b0ba1SAl Viro { 2118f7b0ba1SAl Viro struct audit_chunk *chunk = find_chunk(p); 21274c3cbe3SAl Viro struct audit_chunk *new; 21374c3cbe3SAl Viro struct audit_tree *owner; 21474c3cbe3SAl Viro int size = chunk->count - 1; 21574c3cbe3SAl Viro int i, j; 21674c3cbe3SAl Viro 2178f7b0ba1SAl Viro if (!pin_inotify_watch(&chunk->watch)) { 2188f7b0ba1SAl Viro /* 2198f7b0ba1SAl Viro * Filesystem is shutting down; all watches are getting 2208f7b0ba1SAl Viro * evicted, just take it off the node list for this 2218f7b0ba1SAl Viro * tree and let the eviction logics take care of the 2228f7b0ba1SAl Viro * rest. 2238f7b0ba1SAl Viro */ 2248f7b0ba1SAl Viro owner = p->owner; 2258f7b0ba1SAl Viro if (owner->root == chunk) { 2268f7b0ba1SAl Viro list_del_init(&owner->same_root); 2278f7b0ba1SAl Viro owner->root = NULL; 2288f7b0ba1SAl Viro } 2298f7b0ba1SAl Viro list_del_init(&p->list); 2308f7b0ba1SAl Viro p->owner = NULL; 2318f7b0ba1SAl Viro put_tree(owner); 2328f7b0ba1SAl Viro return; 2338f7b0ba1SAl Viro } 2348f7b0ba1SAl Viro 2358f7b0ba1SAl Viro spin_unlock(&hash_lock); 2368f7b0ba1SAl Viro 2378f7b0ba1SAl Viro /* 2388f7b0ba1SAl Viro * pin_inotify_watch() succeeded, so the watch won't go away 2398f7b0ba1SAl Viro * from under us. 2408f7b0ba1SAl Viro */ 24174c3cbe3SAl Viro mutex_lock(&chunk->watch.inode->inotify_mutex); 24274c3cbe3SAl Viro if (chunk->dead) { 24374c3cbe3SAl Viro mutex_unlock(&chunk->watch.inode->inotify_mutex); 2448f7b0ba1SAl Viro goto out; 24574c3cbe3SAl Viro } 24674c3cbe3SAl Viro 24774c3cbe3SAl Viro owner = p->owner; 24874c3cbe3SAl Viro 24974c3cbe3SAl Viro if (!size) { 25074c3cbe3SAl Viro chunk->dead = 1; 25174c3cbe3SAl Viro spin_lock(&hash_lock); 25274c3cbe3SAl Viro list_del_init(&chunk->trees); 25374c3cbe3SAl Viro if (owner->root == chunk) 25474c3cbe3SAl Viro owner->root = NULL; 25574c3cbe3SAl Viro list_del_init(&p->list); 25674c3cbe3SAl Viro list_del_rcu(&chunk->hash); 25774c3cbe3SAl Viro spin_unlock(&hash_lock); 25874c3cbe3SAl Viro inotify_evict_watch(&chunk->watch); 25974c3cbe3SAl Viro mutex_unlock(&chunk->watch.inode->inotify_mutex); 26074c3cbe3SAl Viro put_inotify_watch(&chunk->watch); 2618f7b0ba1SAl Viro goto out; 26274c3cbe3SAl Viro } 26374c3cbe3SAl Viro 26474c3cbe3SAl Viro new = alloc_chunk(size); 26574c3cbe3SAl Viro if (!new) 26674c3cbe3SAl Viro goto Fallback; 26774c3cbe3SAl Viro if (inotify_clone_watch(&chunk->watch, &new->watch) < 0) { 26874c3cbe3SAl Viro free_chunk(new); 26974c3cbe3SAl Viro goto Fallback; 27074c3cbe3SAl Viro } 27174c3cbe3SAl Viro 27274c3cbe3SAl Viro chunk->dead = 1; 27374c3cbe3SAl Viro spin_lock(&hash_lock); 27474c3cbe3SAl Viro list_replace_init(&chunk->trees, &new->trees); 27574c3cbe3SAl Viro if (owner->root == chunk) { 27674c3cbe3SAl Viro list_del_init(&owner->same_root); 27774c3cbe3SAl Viro owner->root = NULL; 27874c3cbe3SAl Viro } 27974c3cbe3SAl Viro 2806f5d5114SAl Viro for (i = j = 0; j <= size; i++, j++) { 28174c3cbe3SAl Viro struct audit_tree *s; 28274c3cbe3SAl Viro if (&chunk->owners[j] == p) { 28374c3cbe3SAl Viro list_del_init(&p->list); 28474c3cbe3SAl Viro i--; 28574c3cbe3SAl Viro continue; 28674c3cbe3SAl Viro } 28774c3cbe3SAl Viro s = chunk->owners[j].owner; 28874c3cbe3SAl Viro new->owners[i].owner = s; 28974c3cbe3SAl Viro new->owners[i].index = chunk->owners[j].index - j + i; 29074c3cbe3SAl Viro if (!s) /* result of earlier fallback */ 29174c3cbe3SAl Viro continue; 29274c3cbe3SAl Viro get_tree(s); 2936f5d5114SAl Viro list_replace_init(&chunk->owners[j].list, &new->owners[i].list); 29474c3cbe3SAl Viro } 29574c3cbe3SAl Viro 29674c3cbe3SAl Viro list_replace_rcu(&chunk->hash, &new->hash); 29774c3cbe3SAl Viro list_for_each_entry(owner, &new->trees, same_root) 29874c3cbe3SAl Viro owner->root = new; 29974c3cbe3SAl Viro spin_unlock(&hash_lock); 30074c3cbe3SAl Viro inotify_evict_watch(&chunk->watch); 30174c3cbe3SAl Viro mutex_unlock(&chunk->watch.inode->inotify_mutex); 30274c3cbe3SAl Viro put_inotify_watch(&chunk->watch); 3038f7b0ba1SAl Viro goto out; 30474c3cbe3SAl Viro 30574c3cbe3SAl Viro Fallback: 30674c3cbe3SAl Viro // do the best we can 30774c3cbe3SAl Viro spin_lock(&hash_lock); 30874c3cbe3SAl Viro if (owner->root == chunk) { 30974c3cbe3SAl Viro list_del_init(&owner->same_root); 31074c3cbe3SAl Viro owner->root = NULL; 31174c3cbe3SAl Viro } 31274c3cbe3SAl Viro list_del_init(&p->list); 31374c3cbe3SAl Viro p->owner = NULL; 31474c3cbe3SAl Viro put_tree(owner); 31574c3cbe3SAl Viro spin_unlock(&hash_lock); 31674c3cbe3SAl Viro mutex_unlock(&chunk->watch.inode->inotify_mutex); 3178f7b0ba1SAl Viro out: 3188f7b0ba1SAl Viro unpin_inotify_watch(&chunk->watch); 3198f7b0ba1SAl Viro spin_lock(&hash_lock); 32074c3cbe3SAl Viro } 32174c3cbe3SAl Viro 32274c3cbe3SAl Viro static int create_chunk(struct inode *inode, struct audit_tree *tree) 32374c3cbe3SAl Viro { 32474c3cbe3SAl Viro struct audit_chunk *chunk = alloc_chunk(1); 32574c3cbe3SAl Viro if (!chunk) 32674c3cbe3SAl Viro return -ENOMEM; 32774c3cbe3SAl Viro 32874c3cbe3SAl Viro if (inotify_add_watch(rtree_ih, &chunk->watch, inode, IN_IGNORED | IN_DELETE_SELF) < 0) { 32974c3cbe3SAl Viro free_chunk(chunk); 33074c3cbe3SAl Viro return -ENOSPC; 33174c3cbe3SAl Viro } 33274c3cbe3SAl Viro 33374c3cbe3SAl Viro mutex_lock(&inode->inotify_mutex); 33474c3cbe3SAl Viro spin_lock(&hash_lock); 33574c3cbe3SAl Viro if (tree->goner) { 33674c3cbe3SAl Viro spin_unlock(&hash_lock); 33774c3cbe3SAl Viro chunk->dead = 1; 33874c3cbe3SAl Viro inotify_evict_watch(&chunk->watch); 33974c3cbe3SAl Viro mutex_unlock(&inode->inotify_mutex); 34074c3cbe3SAl Viro put_inotify_watch(&chunk->watch); 34174c3cbe3SAl Viro return 0; 34274c3cbe3SAl Viro } 34374c3cbe3SAl Viro chunk->owners[0].index = (1U << 31); 34474c3cbe3SAl Viro chunk->owners[0].owner = tree; 34574c3cbe3SAl Viro get_tree(tree); 34674c3cbe3SAl Viro list_add(&chunk->owners[0].list, &tree->chunks); 34774c3cbe3SAl Viro if (!tree->root) { 34874c3cbe3SAl Viro tree->root = chunk; 34974c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees); 35074c3cbe3SAl Viro } 35174c3cbe3SAl Viro insert_hash(chunk); 35274c3cbe3SAl Viro spin_unlock(&hash_lock); 35374c3cbe3SAl Viro mutex_unlock(&inode->inotify_mutex); 35474c3cbe3SAl Viro return 0; 35574c3cbe3SAl Viro } 35674c3cbe3SAl Viro 35774c3cbe3SAl Viro /* the first tagged inode becomes root of tree */ 35874c3cbe3SAl Viro static int tag_chunk(struct inode *inode, struct audit_tree *tree) 35974c3cbe3SAl Viro { 36074c3cbe3SAl Viro struct inotify_watch *watch; 36174c3cbe3SAl Viro struct audit_tree *owner; 36274c3cbe3SAl Viro struct audit_chunk *chunk, *old; 36374c3cbe3SAl Viro struct node *p; 36474c3cbe3SAl Viro int n; 36574c3cbe3SAl Viro 36674c3cbe3SAl Viro if (inotify_find_watch(rtree_ih, inode, &watch) < 0) 36774c3cbe3SAl Viro return create_chunk(inode, tree); 36874c3cbe3SAl Viro 36974c3cbe3SAl Viro old = container_of(watch, struct audit_chunk, watch); 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); 376b4c30aadSAl Viro put_inotify_watch(&old->watch); 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) { 384b4c30aadSAl Viro put_inotify_watch(&old->watch); 38574c3cbe3SAl Viro return -ENOMEM; 386b4c30aadSAl Viro } 38774c3cbe3SAl Viro 38874c3cbe3SAl Viro mutex_lock(&inode->inotify_mutex); 38974c3cbe3SAl Viro if (inotify_clone_watch(&old->watch, &chunk->watch) < 0) { 39074c3cbe3SAl Viro mutex_unlock(&inode->inotify_mutex); 391318b6d3dSEric Paris put_inotify_watch(&old->watch); 39274c3cbe3SAl Viro free_chunk(chunk); 39374c3cbe3SAl Viro return -ENOSPC; 39474c3cbe3SAl Viro } 39574c3cbe3SAl Viro spin_lock(&hash_lock); 39674c3cbe3SAl Viro if (tree->goner) { 39774c3cbe3SAl Viro spin_unlock(&hash_lock); 39874c3cbe3SAl Viro chunk->dead = 1; 39974c3cbe3SAl Viro inotify_evict_watch(&chunk->watch); 40074c3cbe3SAl Viro mutex_unlock(&inode->inotify_mutex); 401318b6d3dSEric Paris put_inotify_watch(&old->watch); 40274c3cbe3SAl Viro put_inotify_watch(&chunk->watch); 40374c3cbe3SAl Viro return 0; 40474c3cbe3SAl Viro } 40574c3cbe3SAl Viro list_replace_init(&old->trees, &chunk->trees); 40674c3cbe3SAl Viro for (n = 0, p = chunk->owners; n < old->count; n++, p++) { 40774c3cbe3SAl Viro struct audit_tree *s = old->owners[n].owner; 40874c3cbe3SAl Viro p->owner = s; 40974c3cbe3SAl Viro p->index = old->owners[n].index; 41074c3cbe3SAl Viro if (!s) /* result of fallback in untag */ 41174c3cbe3SAl Viro continue; 41274c3cbe3SAl Viro get_tree(s); 41374c3cbe3SAl Viro list_replace_init(&old->owners[n].list, &p->list); 41474c3cbe3SAl Viro } 41574c3cbe3SAl Viro p->index = (chunk->count - 1) | (1U<<31); 41674c3cbe3SAl Viro p->owner = tree; 41774c3cbe3SAl Viro get_tree(tree); 41874c3cbe3SAl Viro list_add(&p->list, &tree->chunks); 41974c3cbe3SAl Viro list_replace_rcu(&old->hash, &chunk->hash); 42074c3cbe3SAl Viro list_for_each_entry(owner, &chunk->trees, same_root) 42174c3cbe3SAl Viro owner->root = chunk; 42274c3cbe3SAl Viro old->dead = 1; 42374c3cbe3SAl Viro if (!tree->root) { 42474c3cbe3SAl Viro tree->root = chunk; 42574c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees); 42674c3cbe3SAl Viro } 42774c3cbe3SAl Viro spin_unlock(&hash_lock); 42874c3cbe3SAl Viro inotify_evict_watch(&old->watch); 42974c3cbe3SAl Viro mutex_unlock(&inode->inotify_mutex); 430b4c30aadSAl Viro put_inotify_watch(&old->watch); /* pair to inotify_find_watch */ 431b4c30aadSAl Viro put_inotify_watch(&old->watch); /* and kill it */ 43274c3cbe3SAl Viro return 0; 43374c3cbe3SAl Viro } 43474c3cbe3SAl Viro 43574c3cbe3SAl Viro static void kill_rules(struct audit_tree *tree) 43674c3cbe3SAl Viro { 43774c3cbe3SAl Viro struct audit_krule *rule, *next; 43874c3cbe3SAl Viro struct audit_entry *entry; 43974c3cbe3SAl Viro struct audit_buffer *ab; 44074c3cbe3SAl Viro 44174c3cbe3SAl Viro list_for_each_entry_safe(rule, next, &tree->rules, rlist) { 44274c3cbe3SAl Viro entry = container_of(rule, struct audit_entry, rule); 44374c3cbe3SAl Viro 44474c3cbe3SAl Viro list_del_init(&rule->rlist); 44574c3cbe3SAl Viro if (rule->tree) { 44674c3cbe3SAl Viro /* not a half-baked one */ 44774c3cbe3SAl Viro ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); 4489d960985SEric Paris audit_log_format(ab, "op="); 4499d960985SEric Paris audit_log_string(ab, "remove rule"); 4509d960985SEric Paris audit_log_format(ab, " dir="); 45174c3cbe3SAl Viro audit_log_untrustedstring(ab, rule->tree->pathname); 4529d960985SEric Paris audit_log_key(ab, rule->filterkey); 45374c3cbe3SAl Viro audit_log_format(ab, " list=%d res=1", rule->listnr); 45474c3cbe3SAl Viro audit_log_end(ab); 45574c3cbe3SAl Viro rule->tree = NULL; 45674c3cbe3SAl Viro list_del_rcu(&entry->list); 457e45aa212SAl Viro list_del(&entry->rule.list); 45874c3cbe3SAl Viro call_rcu(&entry->rcu, audit_free_rule_rcu); 45974c3cbe3SAl Viro } 46074c3cbe3SAl Viro } 46174c3cbe3SAl Viro } 46274c3cbe3SAl Viro 46374c3cbe3SAl Viro /* 46474c3cbe3SAl Viro * finish killing struct audit_tree 46574c3cbe3SAl Viro */ 46674c3cbe3SAl Viro static void prune_one(struct audit_tree *victim) 46774c3cbe3SAl Viro { 46874c3cbe3SAl Viro spin_lock(&hash_lock); 46974c3cbe3SAl Viro while (!list_empty(&victim->chunks)) { 47074c3cbe3SAl Viro struct node *p; 47174c3cbe3SAl Viro 47274c3cbe3SAl Viro p = list_entry(victim->chunks.next, struct node, list); 47374c3cbe3SAl Viro 4748f7b0ba1SAl Viro untag_chunk(p); 47574c3cbe3SAl Viro } 47674c3cbe3SAl Viro spin_unlock(&hash_lock); 47774c3cbe3SAl Viro put_tree(victim); 47874c3cbe3SAl Viro } 47974c3cbe3SAl Viro 48074c3cbe3SAl Viro /* trim the uncommitted chunks from tree */ 48174c3cbe3SAl Viro 48274c3cbe3SAl Viro static void trim_marked(struct audit_tree *tree) 48374c3cbe3SAl Viro { 48474c3cbe3SAl Viro struct list_head *p, *q; 48574c3cbe3SAl Viro spin_lock(&hash_lock); 48674c3cbe3SAl Viro if (tree->goner) { 48774c3cbe3SAl Viro spin_unlock(&hash_lock); 48874c3cbe3SAl Viro return; 48974c3cbe3SAl Viro } 49074c3cbe3SAl Viro /* reorder */ 49174c3cbe3SAl Viro for (p = tree->chunks.next; p != &tree->chunks; p = q) { 49274c3cbe3SAl Viro struct node *node = list_entry(p, struct node, list); 49374c3cbe3SAl Viro q = p->next; 49474c3cbe3SAl Viro if (node->index & (1U<<31)) { 49574c3cbe3SAl Viro list_del_init(p); 49674c3cbe3SAl Viro list_add(p, &tree->chunks); 49774c3cbe3SAl Viro } 49874c3cbe3SAl Viro } 49974c3cbe3SAl Viro 50074c3cbe3SAl Viro while (!list_empty(&tree->chunks)) { 50174c3cbe3SAl Viro struct node *node; 50274c3cbe3SAl Viro 50374c3cbe3SAl Viro node = list_entry(tree->chunks.next, struct node, list); 50474c3cbe3SAl Viro 50574c3cbe3SAl Viro /* have we run out of marked? */ 50674c3cbe3SAl Viro if (!(node->index & (1U<<31))) 50774c3cbe3SAl Viro break; 50874c3cbe3SAl Viro 5098f7b0ba1SAl Viro untag_chunk(node); 51074c3cbe3SAl Viro } 51174c3cbe3SAl Viro if (!tree->root && !tree->goner) { 51274c3cbe3SAl Viro tree->goner = 1; 51374c3cbe3SAl Viro spin_unlock(&hash_lock); 51474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 51574c3cbe3SAl Viro kill_rules(tree); 51674c3cbe3SAl Viro list_del_init(&tree->list); 51774c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 51874c3cbe3SAl Viro prune_one(tree); 51974c3cbe3SAl Viro } else { 52074c3cbe3SAl Viro spin_unlock(&hash_lock); 52174c3cbe3SAl Viro } 52274c3cbe3SAl Viro } 52374c3cbe3SAl Viro 524916d7576SAl Viro static void audit_schedule_prune(void); 525916d7576SAl Viro 52674c3cbe3SAl Viro /* called with audit_filter_mutex */ 52774c3cbe3SAl Viro int audit_remove_tree_rule(struct audit_krule *rule) 52874c3cbe3SAl Viro { 52974c3cbe3SAl Viro struct audit_tree *tree; 53074c3cbe3SAl Viro tree = rule->tree; 53174c3cbe3SAl Viro if (tree) { 53274c3cbe3SAl Viro spin_lock(&hash_lock); 53374c3cbe3SAl Viro list_del_init(&rule->rlist); 53474c3cbe3SAl Viro if (list_empty(&tree->rules) && !tree->goner) { 53574c3cbe3SAl Viro tree->root = NULL; 53674c3cbe3SAl Viro list_del_init(&tree->same_root); 53774c3cbe3SAl Viro tree->goner = 1; 53874c3cbe3SAl Viro list_move(&tree->list, &prune_list); 53974c3cbe3SAl Viro rule->tree = NULL; 54074c3cbe3SAl Viro spin_unlock(&hash_lock); 54174c3cbe3SAl Viro audit_schedule_prune(); 54274c3cbe3SAl Viro return 1; 54374c3cbe3SAl Viro } 54474c3cbe3SAl Viro rule->tree = NULL; 54574c3cbe3SAl Viro spin_unlock(&hash_lock); 54674c3cbe3SAl Viro return 1; 54774c3cbe3SAl Viro } 54874c3cbe3SAl Viro return 0; 54974c3cbe3SAl Viro } 55074c3cbe3SAl Viro 55174c3cbe3SAl Viro void audit_trim_trees(void) 55274c3cbe3SAl Viro { 55374c3cbe3SAl Viro struct list_head cursor; 55474c3cbe3SAl Viro 55574c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 55674c3cbe3SAl Viro list_add(&cursor, &tree_list); 55774c3cbe3SAl Viro while (cursor.next != &tree_list) { 55874c3cbe3SAl Viro struct audit_tree *tree; 55998bc993fSAl Viro struct path path; 56074c3cbe3SAl Viro struct vfsmount *root_mnt; 56174c3cbe3SAl Viro struct node *node; 56274c3cbe3SAl Viro struct list_head list; 56374c3cbe3SAl Viro int err; 56474c3cbe3SAl Viro 56574c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 56674c3cbe3SAl Viro get_tree(tree); 56774c3cbe3SAl Viro list_del(&cursor); 56874c3cbe3SAl Viro list_add(&cursor, &tree->list); 56974c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 57074c3cbe3SAl Viro 57198bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 57274c3cbe3SAl Viro if (err) 57374c3cbe3SAl Viro goto skip_it; 57474c3cbe3SAl Viro 575589ff870SAl Viro root_mnt = collect_mounts(&path); 57698bc993fSAl Viro path_put(&path); 57774c3cbe3SAl Viro if (!root_mnt) 57874c3cbe3SAl Viro goto skip_it; 57974c3cbe3SAl Viro 58074c3cbe3SAl Viro list_add_tail(&list, &root_mnt->mnt_list); 58174c3cbe3SAl Viro spin_lock(&hash_lock); 58274c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) { 58374c3cbe3SAl Viro struct audit_chunk *chunk = find_chunk(node); 58474c3cbe3SAl Viro struct inode *inode = chunk->watch.inode; 58574c3cbe3SAl Viro struct vfsmount *mnt; 58674c3cbe3SAl Viro node->index |= 1U<<31; 58774c3cbe3SAl Viro list_for_each_entry(mnt, &list, mnt_list) { 58874c3cbe3SAl Viro if (mnt->mnt_root->d_inode == inode) { 58974c3cbe3SAl Viro node->index &= ~(1U<<31); 59074c3cbe3SAl Viro break; 59174c3cbe3SAl Viro } 59274c3cbe3SAl Viro } 59374c3cbe3SAl Viro } 59474c3cbe3SAl Viro spin_unlock(&hash_lock); 59574c3cbe3SAl Viro trim_marked(tree); 59674c3cbe3SAl Viro put_tree(tree); 59774c3cbe3SAl Viro list_del_init(&list); 59874c3cbe3SAl Viro drop_collected_mounts(root_mnt); 59974c3cbe3SAl Viro skip_it: 60074c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 60174c3cbe3SAl Viro } 60274c3cbe3SAl Viro list_del(&cursor); 60374c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 60474c3cbe3SAl Viro } 60574c3cbe3SAl Viro 60674c3cbe3SAl Viro static int is_under(struct vfsmount *mnt, struct dentry *dentry, 60798bc993fSAl Viro struct path *path) 60874c3cbe3SAl Viro { 60998bc993fSAl Viro if (mnt != path->mnt) { 61074c3cbe3SAl Viro for (;;) { 61174c3cbe3SAl Viro if (mnt->mnt_parent == mnt) 61274c3cbe3SAl Viro return 0; 61398bc993fSAl Viro if (mnt->mnt_parent == path->mnt) 61474c3cbe3SAl Viro break; 61574c3cbe3SAl Viro mnt = mnt->mnt_parent; 61674c3cbe3SAl Viro } 61774c3cbe3SAl Viro dentry = mnt->mnt_mountpoint; 61874c3cbe3SAl Viro } 61998bc993fSAl Viro return is_subdir(dentry, path->dentry); 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 64174c3cbe3SAl Viro /* called with audit_filter_mutex */ 64274c3cbe3SAl Viro int audit_add_tree_rule(struct audit_krule *rule) 64374c3cbe3SAl Viro { 64474c3cbe3SAl Viro struct audit_tree *seed = rule->tree, *tree; 64598bc993fSAl Viro struct path path; 64674c3cbe3SAl Viro struct vfsmount *mnt, *p; 64774c3cbe3SAl Viro struct list_head list; 64874c3cbe3SAl Viro int err; 64974c3cbe3SAl Viro 65074c3cbe3SAl Viro list_for_each_entry(tree, &tree_list, list) { 65174c3cbe3SAl Viro if (!strcmp(seed->pathname, tree->pathname)) { 65274c3cbe3SAl Viro put_tree(seed); 65374c3cbe3SAl Viro rule->tree = tree; 65474c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 65574c3cbe3SAl Viro return 0; 65674c3cbe3SAl Viro } 65774c3cbe3SAl Viro } 65874c3cbe3SAl Viro tree = seed; 65974c3cbe3SAl Viro list_add(&tree->list, &tree_list); 66074c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 66174c3cbe3SAl Viro /* do not set rule->tree yet */ 66274c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 66374c3cbe3SAl Viro 66498bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 66574c3cbe3SAl Viro if (err) 66674c3cbe3SAl Viro goto Err; 667589ff870SAl Viro mnt = collect_mounts(&path); 66898bc993fSAl Viro path_put(&path); 66974c3cbe3SAl Viro if (!mnt) { 67074c3cbe3SAl Viro err = -ENOMEM; 67174c3cbe3SAl Viro goto Err; 67274c3cbe3SAl Viro } 67374c3cbe3SAl Viro list_add_tail(&list, &mnt->mnt_list); 67474c3cbe3SAl Viro 67574c3cbe3SAl Viro get_tree(tree); 67674c3cbe3SAl Viro list_for_each_entry(p, &list, mnt_list) { 67774c3cbe3SAl Viro err = tag_chunk(p->mnt_root->d_inode, tree); 67874c3cbe3SAl Viro if (err) 67974c3cbe3SAl Viro break; 68074c3cbe3SAl Viro } 68174c3cbe3SAl Viro 68274c3cbe3SAl Viro list_del(&list); 68374c3cbe3SAl Viro drop_collected_mounts(mnt); 68474c3cbe3SAl Viro 68574c3cbe3SAl Viro if (!err) { 68674c3cbe3SAl Viro struct node *node; 68774c3cbe3SAl Viro spin_lock(&hash_lock); 68874c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 68974c3cbe3SAl Viro node->index &= ~(1U<<31); 69074c3cbe3SAl Viro spin_unlock(&hash_lock); 69174c3cbe3SAl Viro } else { 69274c3cbe3SAl Viro trim_marked(tree); 69374c3cbe3SAl Viro goto Err; 69474c3cbe3SAl Viro } 69574c3cbe3SAl Viro 69674c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 69774c3cbe3SAl Viro if (list_empty(&rule->rlist)) { 69874c3cbe3SAl Viro put_tree(tree); 69974c3cbe3SAl Viro return -ENOENT; 70074c3cbe3SAl Viro } 70174c3cbe3SAl Viro rule->tree = tree; 70274c3cbe3SAl Viro put_tree(tree); 70374c3cbe3SAl Viro 70474c3cbe3SAl Viro return 0; 70574c3cbe3SAl Viro Err: 70674c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 70774c3cbe3SAl Viro list_del_init(&tree->list); 70874c3cbe3SAl Viro list_del_init(&tree->rules); 70974c3cbe3SAl Viro put_tree(tree); 71074c3cbe3SAl Viro return err; 71174c3cbe3SAl Viro } 71274c3cbe3SAl Viro 71374c3cbe3SAl Viro int audit_tag_tree(char *old, char *new) 71474c3cbe3SAl Viro { 71574c3cbe3SAl Viro struct list_head cursor, barrier; 71674c3cbe3SAl Viro int failed = 0; 71798bc993fSAl Viro struct path path; 71874c3cbe3SAl Viro struct vfsmount *tagged; 71974c3cbe3SAl Viro struct list_head list; 72074c3cbe3SAl Viro struct vfsmount *mnt; 72174c3cbe3SAl Viro struct dentry *dentry; 72274c3cbe3SAl Viro int err; 72374c3cbe3SAl Viro 72498bc993fSAl Viro err = kern_path(new, 0, &path); 72574c3cbe3SAl Viro if (err) 72674c3cbe3SAl Viro return err; 727589ff870SAl Viro tagged = collect_mounts(&path); 72898bc993fSAl Viro path_put(&path); 72974c3cbe3SAl Viro if (!tagged) 73074c3cbe3SAl Viro return -ENOMEM; 73174c3cbe3SAl Viro 73298bc993fSAl Viro err = kern_path(old, 0, &path); 73374c3cbe3SAl Viro if (err) { 73474c3cbe3SAl Viro drop_collected_mounts(tagged); 73574c3cbe3SAl Viro return err; 73674c3cbe3SAl Viro } 73798bc993fSAl Viro mnt = mntget(path.mnt); 73898bc993fSAl Viro dentry = dget(path.dentry); 73998bc993fSAl Viro path_put(&path); 74074c3cbe3SAl Viro 74174c3cbe3SAl Viro list_add_tail(&list, &tagged->mnt_list); 74274c3cbe3SAl Viro 74374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 74474c3cbe3SAl Viro list_add(&barrier, &tree_list); 74574c3cbe3SAl Viro list_add(&cursor, &barrier); 74674c3cbe3SAl Viro 74774c3cbe3SAl Viro while (cursor.next != &tree_list) { 74874c3cbe3SAl Viro struct audit_tree *tree; 74974c3cbe3SAl Viro struct vfsmount *p; 75074c3cbe3SAl Viro 75174c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 75274c3cbe3SAl Viro get_tree(tree); 75374c3cbe3SAl Viro list_del(&cursor); 75474c3cbe3SAl Viro list_add(&cursor, &tree->list); 75574c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 75674c3cbe3SAl Viro 75798bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 75874c3cbe3SAl Viro if (err) { 75974c3cbe3SAl Viro put_tree(tree); 76074c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 76174c3cbe3SAl Viro continue; 76274c3cbe3SAl Viro } 76374c3cbe3SAl Viro 76474c3cbe3SAl Viro spin_lock(&vfsmount_lock); 76598bc993fSAl Viro if (!is_under(mnt, dentry, &path)) { 76674c3cbe3SAl Viro spin_unlock(&vfsmount_lock); 76798bc993fSAl Viro path_put(&path); 76874c3cbe3SAl Viro put_tree(tree); 76974c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 77074c3cbe3SAl Viro continue; 77174c3cbe3SAl Viro } 77274c3cbe3SAl Viro spin_unlock(&vfsmount_lock); 77398bc993fSAl Viro path_put(&path); 77474c3cbe3SAl Viro 77574c3cbe3SAl Viro list_for_each_entry(p, &list, mnt_list) { 77674c3cbe3SAl Viro failed = tag_chunk(p->mnt_root->d_inode, tree); 77774c3cbe3SAl Viro if (failed) 77874c3cbe3SAl Viro break; 77974c3cbe3SAl Viro } 78074c3cbe3SAl Viro 78174c3cbe3SAl Viro if (failed) { 78274c3cbe3SAl Viro put_tree(tree); 78374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 78474c3cbe3SAl Viro break; 78574c3cbe3SAl Viro } 78674c3cbe3SAl Viro 78774c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 78874c3cbe3SAl Viro spin_lock(&hash_lock); 78974c3cbe3SAl Viro if (!tree->goner) { 79074c3cbe3SAl Viro list_del(&tree->list); 79174c3cbe3SAl Viro list_add(&tree->list, &tree_list); 79274c3cbe3SAl Viro } 79374c3cbe3SAl Viro spin_unlock(&hash_lock); 79474c3cbe3SAl Viro put_tree(tree); 79574c3cbe3SAl Viro } 79674c3cbe3SAl Viro 79774c3cbe3SAl Viro while (barrier.prev != &tree_list) { 79874c3cbe3SAl Viro struct audit_tree *tree; 79974c3cbe3SAl Viro 80074c3cbe3SAl Viro tree = container_of(barrier.prev, struct audit_tree, list); 80174c3cbe3SAl Viro get_tree(tree); 80274c3cbe3SAl Viro list_del(&tree->list); 80374c3cbe3SAl Viro list_add(&tree->list, &barrier); 80474c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 80574c3cbe3SAl Viro 80674c3cbe3SAl Viro if (!failed) { 80774c3cbe3SAl Viro struct node *node; 80874c3cbe3SAl Viro spin_lock(&hash_lock); 80974c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 81074c3cbe3SAl Viro node->index &= ~(1U<<31); 81174c3cbe3SAl Viro spin_unlock(&hash_lock); 81274c3cbe3SAl Viro } else { 81374c3cbe3SAl Viro trim_marked(tree); 81474c3cbe3SAl Viro } 81574c3cbe3SAl Viro 81674c3cbe3SAl Viro put_tree(tree); 81774c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 81874c3cbe3SAl Viro } 81974c3cbe3SAl Viro list_del(&barrier); 82074c3cbe3SAl Viro list_del(&cursor); 82174c3cbe3SAl Viro list_del(&list); 82274c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 82374c3cbe3SAl Viro dput(dentry); 82474c3cbe3SAl Viro mntput(mnt); 82574c3cbe3SAl Viro drop_collected_mounts(tagged); 82674c3cbe3SAl Viro return failed; 82774c3cbe3SAl Viro } 82874c3cbe3SAl Viro 82974c3cbe3SAl Viro /* 83074c3cbe3SAl Viro * That gets run when evict_chunk() ends up needing to kill audit_tree. 831916d7576SAl Viro * Runs from a separate thread. 83274c3cbe3SAl Viro */ 833916d7576SAl Viro static int prune_tree_thread(void *unused) 83474c3cbe3SAl Viro { 835916d7576SAl Viro mutex_lock(&audit_cmd_mutex); 83674c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 83774c3cbe3SAl Viro 83874c3cbe3SAl Viro while (!list_empty(&prune_list)) { 83974c3cbe3SAl Viro struct audit_tree *victim; 84074c3cbe3SAl Viro 84174c3cbe3SAl Viro victim = list_entry(prune_list.next, struct audit_tree, list); 84274c3cbe3SAl Viro list_del_init(&victim->list); 84374c3cbe3SAl Viro 84474c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 84574c3cbe3SAl Viro 84674c3cbe3SAl Viro prune_one(victim); 84774c3cbe3SAl Viro 84874c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 84974c3cbe3SAl Viro } 85074c3cbe3SAl Viro 85174c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 852916d7576SAl Viro mutex_unlock(&audit_cmd_mutex); 853916d7576SAl Viro return 0; 854916d7576SAl Viro } 855916d7576SAl Viro 856916d7576SAl Viro static void audit_schedule_prune(void) 857916d7576SAl Viro { 858916d7576SAl Viro kthread_run(prune_tree_thread, NULL, "audit_prune_tree"); 859916d7576SAl Viro } 860916d7576SAl Viro 861916d7576SAl Viro /* 862916d7576SAl Viro * ... and that one is done if evict_chunk() decides to delay until the end 863916d7576SAl Viro * of syscall. Runs synchronously. 864916d7576SAl Viro */ 865916d7576SAl Viro void audit_kill_trees(struct list_head *list) 866916d7576SAl Viro { 867916d7576SAl Viro mutex_lock(&audit_cmd_mutex); 868916d7576SAl Viro mutex_lock(&audit_filter_mutex); 869916d7576SAl Viro 870916d7576SAl Viro while (!list_empty(list)) { 871916d7576SAl Viro struct audit_tree *victim; 872916d7576SAl Viro 873916d7576SAl Viro victim = list_entry(list->next, struct audit_tree, list); 874916d7576SAl Viro kill_rules(victim); 875916d7576SAl Viro list_del_init(&victim->list); 876916d7576SAl Viro 877916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 878916d7576SAl Viro 879916d7576SAl Viro prune_one(victim); 880916d7576SAl Viro 881916d7576SAl Viro mutex_lock(&audit_filter_mutex); 882916d7576SAl Viro } 883916d7576SAl Viro 884916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 885916d7576SAl Viro mutex_unlock(&audit_cmd_mutex); 88674c3cbe3SAl Viro } 88774c3cbe3SAl Viro 88874c3cbe3SAl Viro /* 88974c3cbe3SAl Viro * Here comes the stuff asynchronous to auditctl operations 89074c3cbe3SAl Viro */ 89174c3cbe3SAl Viro 89274c3cbe3SAl Viro /* inode->inotify_mutex is locked */ 89374c3cbe3SAl Viro static void evict_chunk(struct audit_chunk *chunk) 89474c3cbe3SAl Viro { 89574c3cbe3SAl Viro struct audit_tree *owner; 896916d7576SAl Viro struct list_head *postponed = audit_killed_trees(); 897916d7576SAl Viro int need_prune = 0; 89874c3cbe3SAl Viro int n; 89974c3cbe3SAl Viro 90074c3cbe3SAl Viro if (chunk->dead) 90174c3cbe3SAl Viro return; 90274c3cbe3SAl Viro 90374c3cbe3SAl Viro chunk->dead = 1; 90474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 90574c3cbe3SAl Viro spin_lock(&hash_lock); 90674c3cbe3SAl Viro while (!list_empty(&chunk->trees)) { 90774c3cbe3SAl Viro owner = list_entry(chunk->trees.next, 90874c3cbe3SAl Viro struct audit_tree, same_root); 90974c3cbe3SAl Viro owner->goner = 1; 91074c3cbe3SAl Viro owner->root = NULL; 91174c3cbe3SAl Viro list_del_init(&owner->same_root); 91274c3cbe3SAl Viro spin_unlock(&hash_lock); 913916d7576SAl Viro if (!postponed) { 91474c3cbe3SAl Viro kill_rules(owner); 91574c3cbe3SAl Viro list_move(&owner->list, &prune_list); 916916d7576SAl Viro need_prune = 1; 917916d7576SAl Viro } else { 918916d7576SAl Viro list_move(&owner->list, postponed); 919916d7576SAl Viro } 92074c3cbe3SAl Viro spin_lock(&hash_lock); 92174c3cbe3SAl Viro } 92274c3cbe3SAl Viro list_del_rcu(&chunk->hash); 92374c3cbe3SAl Viro for (n = 0; n < chunk->count; n++) 92474c3cbe3SAl Viro list_del_init(&chunk->owners[n].list); 92574c3cbe3SAl Viro spin_unlock(&hash_lock); 926916d7576SAl Viro if (need_prune) 927916d7576SAl Viro audit_schedule_prune(); 92874c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 92974c3cbe3SAl Viro } 93074c3cbe3SAl Viro 93174c3cbe3SAl Viro static void handle_event(struct inotify_watch *watch, u32 wd, u32 mask, 93274c3cbe3SAl Viro u32 cookie, const char *dname, struct inode *inode) 93374c3cbe3SAl Viro { 93474c3cbe3SAl Viro struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch); 93574c3cbe3SAl Viro 93674c3cbe3SAl Viro if (mask & IN_IGNORED) { 93774c3cbe3SAl Viro evict_chunk(chunk); 93874c3cbe3SAl Viro put_inotify_watch(watch); 93974c3cbe3SAl Viro } 94074c3cbe3SAl Viro } 94174c3cbe3SAl Viro 94274c3cbe3SAl Viro static void destroy_watch(struct inotify_watch *watch) 94374c3cbe3SAl Viro { 94474c3cbe3SAl Viro struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch); 9458f7b0ba1SAl Viro call_rcu(&chunk->head, __put_chunk); 94674c3cbe3SAl Viro } 94774c3cbe3SAl Viro 94874c3cbe3SAl Viro static const struct inotify_operations rtree_inotify_ops = { 94974c3cbe3SAl Viro .handle_event = handle_event, 95074c3cbe3SAl Viro .destroy_watch = destroy_watch, 95174c3cbe3SAl Viro }; 95274c3cbe3SAl Viro 95374c3cbe3SAl Viro static int __init audit_tree_init(void) 95474c3cbe3SAl Viro { 95574c3cbe3SAl Viro int i; 95674c3cbe3SAl Viro 95774c3cbe3SAl Viro rtree_ih = inotify_init(&rtree_inotify_ops); 95874c3cbe3SAl Viro if (IS_ERR(rtree_ih)) 95974c3cbe3SAl Viro audit_panic("cannot initialize inotify handle for rectree watches"); 96074c3cbe3SAl Viro 96174c3cbe3SAl Viro for (i = 0; i < HASH_SIZE; i++) 96274c3cbe3SAl Viro INIT_LIST_HEAD(&chunk_hash_heads[i]); 96374c3cbe3SAl Viro 96474c3cbe3SAl Viro return 0; 96574c3cbe3SAl Viro } 96674c3cbe3SAl Viro __initcall(audit_tree_init); 967