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> 69d2378f8SElena Reshetova #include <linux/refcount.h> 75a0e3ad6STejun Heo #include <linux/slab.h> 874c3cbe3SAl Viro 974c3cbe3SAl Viro struct audit_tree; 1074c3cbe3SAl Viro struct audit_chunk; 1174c3cbe3SAl Viro 1274c3cbe3SAl Viro struct audit_tree { 139d2378f8SElena Reshetova refcount_t count; 1474c3cbe3SAl Viro int goner; 1574c3cbe3SAl Viro struct audit_chunk *root; 1674c3cbe3SAl Viro struct list_head chunks; 1774c3cbe3SAl Viro struct list_head rules; 1874c3cbe3SAl Viro struct list_head list; 1974c3cbe3SAl Viro struct list_head same_root; 2074c3cbe3SAl Viro struct rcu_head head; 2174c3cbe3SAl Viro char pathname[]; 2274c3cbe3SAl Viro }; 2374c3cbe3SAl Viro 2474c3cbe3SAl Viro struct audit_chunk { 2574c3cbe3SAl Viro struct list_head hash; 26e61ce867SEric Paris struct fsnotify_mark mark; 2774c3cbe3SAl Viro struct list_head trees; /* with root here */ 2874c3cbe3SAl Viro int dead; 2974c3cbe3SAl Viro int count; 308f7b0ba1SAl Viro atomic_long_t refs; 3174c3cbe3SAl Viro struct rcu_head head; 3274c3cbe3SAl Viro struct node { 3374c3cbe3SAl Viro struct list_head list; 3474c3cbe3SAl Viro struct audit_tree *owner; 3574c3cbe3SAl Viro unsigned index; /* index; upper bit indicates 'will prune' */ 3674c3cbe3SAl Viro } owners[]; 3774c3cbe3SAl Viro }; 3874c3cbe3SAl Viro 3974c3cbe3SAl Viro static LIST_HEAD(tree_list); 4074c3cbe3SAl Viro static LIST_HEAD(prune_list); 41f1aaf262SImre Palik static struct task_struct *prune_thread; 4274c3cbe3SAl Viro 4374c3cbe3SAl Viro /* 4474c3cbe3SAl Viro * One struct chunk is attached to each inode of interest. 4574c3cbe3SAl Viro * We replace struct chunk on tagging/untagging. 4674c3cbe3SAl Viro * Rules have pointer to struct audit_tree. 4774c3cbe3SAl Viro * Rules have struct list_head rlist forming a list of rules over 4874c3cbe3SAl Viro * the same tree. 4974c3cbe3SAl Viro * References to struct chunk are collected at audit_inode{,_child}() 5074c3cbe3SAl Viro * time and used in AUDIT_TREE rule matching. 5174c3cbe3SAl Viro * These references are dropped at the same time we are calling 5274c3cbe3SAl Viro * audit_free_names(), etc. 5374c3cbe3SAl Viro * 5474c3cbe3SAl Viro * Cyclic lists galore: 5574c3cbe3SAl Viro * tree.chunks anchors chunk.owners[].list hash_lock 5674c3cbe3SAl Viro * tree.rules anchors rule.rlist audit_filter_mutex 5774c3cbe3SAl Viro * chunk.trees anchors tree.same_root hash_lock 5874c3cbe3SAl Viro * chunk.hash is a hash with middle bits of watch.inode as 5974c3cbe3SAl Viro * a hash function. RCU, hash_lock 6074c3cbe3SAl Viro * 6174c3cbe3SAl Viro * tree is refcounted; one reference for "some rules on rules_list refer to 6274c3cbe3SAl Viro * it", one for each chunk with pointer to it. 6374c3cbe3SAl Viro * 6428a3a7ebSEric Paris * chunk is refcounted by embedded fsnotify_mark + .refs (non-zero refcount 658f7b0ba1SAl Viro * of watch contributes 1 to .refs). 6674c3cbe3SAl Viro * 6774c3cbe3SAl Viro * node.index allows to get from node.list to containing chunk. 6874c3cbe3SAl Viro * MSB of that sucker is stolen to mark taggings that we might have to 6974c3cbe3SAl Viro * revert - several operations have very unpleasant cleanup logics and 7074c3cbe3SAl Viro * that makes a difference. Some. 7174c3cbe3SAl Viro */ 7274c3cbe3SAl Viro 7328a3a7ebSEric Paris static struct fsnotify_group *audit_tree_group; 7474c3cbe3SAl Viro 7574c3cbe3SAl Viro static struct audit_tree *alloc_tree(const char *s) 7674c3cbe3SAl Viro { 7774c3cbe3SAl Viro struct audit_tree *tree; 7874c3cbe3SAl Viro 7974c3cbe3SAl Viro tree = kmalloc(sizeof(struct audit_tree) + strlen(s) + 1, GFP_KERNEL); 8074c3cbe3SAl Viro if (tree) { 819d2378f8SElena Reshetova refcount_set(&tree->count, 1); 8274c3cbe3SAl Viro tree->goner = 0; 8374c3cbe3SAl Viro INIT_LIST_HEAD(&tree->chunks); 8474c3cbe3SAl Viro INIT_LIST_HEAD(&tree->rules); 8574c3cbe3SAl Viro INIT_LIST_HEAD(&tree->list); 8674c3cbe3SAl Viro INIT_LIST_HEAD(&tree->same_root); 8774c3cbe3SAl Viro tree->root = NULL; 8874c3cbe3SAl Viro strcpy(tree->pathname, s); 8974c3cbe3SAl Viro } 9074c3cbe3SAl Viro return tree; 9174c3cbe3SAl Viro } 9274c3cbe3SAl Viro 9374c3cbe3SAl Viro static inline void get_tree(struct audit_tree *tree) 9474c3cbe3SAl Viro { 959d2378f8SElena Reshetova refcount_inc(&tree->count); 9674c3cbe3SAl Viro } 9774c3cbe3SAl Viro 9874c3cbe3SAl Viro static inline void put_tree(struct audit_tree *tree) 9974c3cbe3SAl Viro { 1009d2378f8SElena Reshetova if (refcount_dec_and_test(&tree->count)) 1013b097c46SLai Jiangshan kfree_rcu(tree, head); 10274c3cbe3SAl Viro } 10374c3cbe3SAl Viro 10474c3cbe3SAl Viro /* to avoid bringing the entire thing in audit.h */ 10574c3cbe3SAl Viro const char *audit_tree_path(struct audit_tree *tree) 10674c3cbe3SAl Viro { 10774c3cbe3SAl Viro return tree->pathname; 10874c3cbe3SAl Viro } 10974c3cbe3SAl Viro 1108f7b0ba1SAl Viro static void free_chunk(struct audit_chunk *chunk) 11174c3cbe3SAl Viro { 11274c3cbe3SAl Viro int i; 11374c3cbe3SAl Viro 11474c3cbe3SAl Viro for (i = 0; i < chunk->count; i++) { 11574c3cbe3SAl Viro if (chunk->owners[i].owner) 11674c3cbe3SAl Viro put_tree(chunk->owners[i].owner); 11774c3cbe3SAl Viro } 11874c3cbe3SAl Viro kfree(chunk); 11974c3cbe3SAl Viro } 12074c3cbe3SAl Viro 12174c3cbe3SAl Viro void audit_put_chunk(struct audit_chunk *chunk) 12274c3cbe3SAl Viro { 1238f7b0ba1SAl Viro if (atomic_long_dec_and_test(&chunk->refs)) 1248f7b0ba1SAl Viro free_chunk(chunk); 1258f7b0ba1SAl Viro } 1268f7b0ba1SAl Viro 1278f7b0ba1SAl Viro static void __put_chunk(struct rcu_head *rcu) 1288f7b0ba1SAl Viro { 1298f7b0ba1SAl Viro struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head); 1308f7b0ba1SAl Viro audit_put_chunk(chunk); 13174c3cbe3SAl Viro } 13274c3cbe3SAl Viro 133e61ce867SEric Paris static void audit_tree_destroy_watch(struct fsnotify_mark *entry) 13428a3a7ebSEric Paris { 13528a3a7ebSEric Paris struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark); 13628a3a7ebSEric Paris call_rcu(&chunk->head, __put_chunk); 13728a3a7ebSEric Paris } 13828a3a7ebSEric Paris 13928a3a7ebSEric Paris static struct audit_chunk *alloc_chunk(int count) 14028a3a7ebSEric Paris { 14128a3a7ebSEric Paris struct audit_chunk *chunk; 14228a3a7ebSEric Paris size_t size; 14328a3a7ebSEric Paris int i; 14428a3a7ebSEric Paris 14528a3a7ebSEric Paris size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node); 14628a3a7ebSEric Paris chunk = kzalloc(size, GFP_KERNEL); 14728a3a7ebSEric Paris if (!chunk) 14828a3a7ebSEric Paris return NULL; 14928a3a7ebSEric Paris 15028a3a7ebSEric Paris INIT_LIST_HEAD(&chunk->hash); 15128a3a7ebSEric Paris INIT_LIST_HEAD(&chunk->trees); 15228a3a7ebSEric Paris chunk->count = count; 15328a3a7ebSEric Paris atomic_long_set(&chunk->refs, 1); 15428a3a7ebSEric Paris for (i = 0; i < count; i++) { 15528a3a7ebSEric Paris INIT_LIST_HEAD(&chunk->owners[i].list); 15628a3a7ebSEric Paris chunk->owners[i].index = i; 15728a3a7ebSEric Paris } 158054c636eSJan Kara fsnotify_init_mark(&chunk->mark, audit_tree_group); 159799b6014SMiklos Szeredi chunk->mark.mask = FS_IN_IGNORED; 16028a3a7ebSEric Paris return chunk; 16128a3a7ebSEric Paris } 16228a3a7ebSEric Paris 16374c3cbe3SAl Viro enum {HASH_SIZE = 128}; 16474c3cbe3SAl Viro static struct list_head chunk_hash_heads[HASH_SIZE]; 16574c3cbe3SAl Viro static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock); 16674c3cbe3SAl Viro 167f410ff65SJan Kara /* Function to return search key in our hash from inode. */ 168f410ff65SJan Kara static unsigned long inode_to_key(const struct inode *inode) 16974c3cbe3SAl Viro { 170f410ff65SJan Kara return (unsigned long)inode; 171f410ff65SJan Kara } 172f410ff65SJan Kara 173f410ff65SJan Kara /* 174f410ff65SJan Kara * Function to return search key in our hash from chunk. Key 0 is special and 175f410ff65SJan Kara * should never be present in the hash. 176f410ff65SJan Kara */ 177f410ff65SJan Kara static unsigned long chunk_to_key(struct audit_chunk *chunk) 178f410ff65SJan Kara { 1796b3f05d2SJan Kara /* 1806b3f05d2SJan Kara * We have a reference to the mark so it should be attached to a 1816b3f05d2SJan Kara * connector. 1826b3f05d2SJan Kara */ 1836b3f05d2SJan Kara if (WARN_ON_ONCE(!chunk->mark.connector)) 1846b3f05d2SJan Kara return 0; 1856b3f05d2SJan Kara return (unsigned long)chunk->mark.connector->inode; 186f410ff65SJan Kara } 187f410ff65SJan Kara 188f410ff65SJan Kara static inline struct list_head *chunk_hash(unsigned long key) 189f410ff65SJan Kara { 190f410ff65SJan Kara unsigned long n = key / L1_CACHE_BYTES; 19174c3cbe3SAl Viro return chunk_hash_heads + n % HASH_SIZE; 19274c3cbe3SAl Viro } 19374c3cbe3SAl Viro 19428a3a7ebSEric Paris /* hash_lock & entry->lock is held by caller */ 19574c3cbe3SAl Viro static void insert_hash(struct audit_chunk *chunk) 19674c3cbe3SAl Viro { 1976b3f05d2SJan Kara unsigned long key = chunk_to_key(chunk); 19828a3a7ebSEric Paris struct list_head *list; 19928a3a7ebSEric Paris 20043471d15SJan Kara if (!(chunk->mark.flags & FSNOTIFY_MARK_FLAG_ATTACHED)) 20128a3a7ebSEric Paris return; 202f410ff65SJan Kara list = chunk_hash(key); 20374c3cbe3SAl Viro list_add_rcu(&chunk->hash, list); 20474c3cbe3SAl Viro } 20574c3cbe3SAl Viro 20674c3cbe3SAl Viro /* called under rcu_read_lock */ 20774c3cbe3SAl Viro struct audit_chunk *audit_tree_lookup(const struct inode *inode) 20874c3cbe3SAl Viro { 209f410ff65SJan Kara unsigned long key = inode_to_key(inode); 210f410ff65SJan Kara struct list_head *list = chunk_hash(key); 2116793a051SPaul E. McKenney struct audit_chunk *p; 21274c3cbe3SAl Viro 2136793a051SPaul E. McKenney list_for_each_entry_rcu(p, list, hash) { 214f410ff65SJan Kara if (chunk_to_key(p) == key) { 2158f7b0ba1SAl Viro atomic_long_inc(&p->refs); 21674c3cbe3SAl Viro return p; 21774c3cbe3SAl Viro } 21874c3cbe3SAl Viro } 21974c3cbe3SAl Viro return NULL; 22074c3cbe3SAl Viro } 22174c3cbe3SAl Viro 2226f1b5d7aSYaowei Bai bool audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree) 22374c3cbe3SAl Viro { 22474c3cbe3SAl Viro int n; 22574c3cbe3SAl Viro for (n = 0; n < chunk->count; n++) 22674c3cbe3SAl Viro if (chunk->owners[n].owner == tree) 2276f1b5d7aSYaowei Bai return true; 2286f1b5d7aSYaowei Bai return false; 22974c3cbe3SAl Viro } 23074c3cbe3SAl Viro 23174c3cbe3SAl Viro /* tagging and untagging inodes with trees */ 23274c3cbe3SAl Viro 2338f7b0ba1SAl Viro static struct audit_chunk *find_chunk(struct node *p) 23474c3cbe3SAl Viro { 2358f7b0ba1SAl Viro int index = p->index & ~(1U<<31); 2368f7b0ba1SAl Viro p -= index; 2378f7b0ba1SAl Viro return container_of(p, struct audit_chunk, owners[0]); 2388f7b0ba1SAl Viro } 2398f7b0ba1SAl Viro 2408f7b0ba1SAl Viro static void untag_chunk(struct node *p) 2418f7b0ba1SAl Viro { 2428f7b0ba1SAl Viro struct audit_chunk *chunk = find_chunk(p); 243e61ce867SEric Paris struct fsnotify_mark *entry = &chunk->mark; 244f7a998a9SAl Viro struct audit_chunk *new = NULL; 24574c3cbe3SAl Viro struct audit_tree *owner; 24674c3cbe3SAl Viro int size = chunk->count - 1; 24774c3cbe3SAl Viro int i, j; 24874c3cbe3SAl Viro 24928a3a7ebSEric Paris fsnotify_get_mark(entry); 2508f7b0ba1SAl Viro 2518f7b0ba1SAl Viro spin_unlock(&hash_lock); 2528f7b0ba1SAl Viro 253f7a998a9SAl Viro if (size) 254f7a998a9SAl Viro new = alloc_chunk(size); 255f7a998a9SAl Viro 256be29d20fSJan Kara mutex_lock(&entry->group->mark_mutex); 25728a3a7ebSEric Paris spin_lock(&entry->lock); 2586b3f05d2SJan Kara /* 2596b3f05d2SJan Kara * mark_mutex protects mark from getting detached and thus also from 2606b3f05d2SJan Kara * mark->connector->inode getting NULL. 2616b3f05d2SJan Kara */ 26243471d15SJan Kara if (chunk->dead || !(entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) { 26328a3a7ebSEric Paris spin_unlock(&entry->lock); 264be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 265f7a998a9SAl Viro if (new) 2667b129323SJan Kara fsnotify_put_mark(&new->mark); 2678f7b0ba1SAl Viro goto out; 26874c3cbe3SAl Viro } 26974c3cbe3SAl Viro 27074c3cbe3SAl Viro owner = p->owner; 27174c3cbe3SAl Viro 27274c3cbe3SAl Viro if (!size) { 27374c3cbe3SAl Viro chunk->dead = 1; 27474c3cbe3SAl Viro spin_lock(&hash_lock); 27574c3cbe3SAl Viro list_del_init(&chunk->trees); 27674c3cbe3SAl Viro if (owner->root == chunk) 27774c3cbe3SAl Viro owner->root = NULL; 27874c3cbe3SAl Viro list_del_init(&p->list); 27974c3cbe3SAl Viro list_del_rcu(&chunk->hash); 28074c3cbe3SAl Viro spin_unlock(&hash_lock); 28128a3a7ebSEric Paris spin_unlock(&entry->lock); 282be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 283e2a29943SLino Sanfilippo fsnotify_destroy_mark(entry, audit_tree_group); 2848f7b0ba1SAl Viro goto out; 28574c3cbe3SAl Viro } 28674c3cbe3SAl Viro 28774c3cbe3SAl Viro if (!new) 28874c3cbe3SAl Viro goto Fallback; 289f7a998a9SAl Viro 2907b129323SJan Kara if (fsnotify_add_mark_locked(&new->mark, entry->connector->inode, 291be29d20fSJan Kara NULL, 1)) { 2920fe33aaeSMiklos Szeredi fsnotify_put_mark(&new->mark); 29374c3cbe3SAl Viro goto Fallback; 29474c3cbe3SAl Viro } 29574c3cbe3SAl Viro 29674c3cbe3SAl Viro chunk->dead = 1; 29774c3cbe3SAl Viro spin_lock(&hash_lock); 29874c3cbe3SAl Viro list_replace_init(&chunk->trees, &new->trees); 29974c3cbe3SAl Viro if (owner->root == chunk) { 30074c3cbe3SAl Viro list_del_init(&owner->same_root); 30174c3cbe3SAl Viro owner->root = NULL; 30274c3cbe3SAl Viro } 30374c3cbe3SAl Viro 3046f5d5114SAl Viro for (i = j = 0; j <= size; i++, j++) { 30574c3cbe3SAl Viro struct audit_tree *s; 30674c3cbe3SAl Viro if (&chunk->owners[j] == p) { 30774c3cbe3SAl Viro list_del_init(&p->list); 30874c3cbe3SAl Viro i--; 30974c3cbe3SAl Viro continue; 31074c3cbe3SAl Viro } 31174c3cbe3SAl Viro s = chunk->owners[j].owner; 31274c3cbe3SAl Viro new->owners[i].owner = s; 31374c3cbe3SAl Viro new->owners[i].index = chunk->owners[j].index - j + i; 31474c3cbe3SAl Viro if (!s) /* result of earlier fallback */ 31574c3cbe3SAl Viro continue; 31674c3cbe3SAl Viro get_tree(s); 3176f5d5114SAl Viro list_replace_init(&chunk->owners[j].list, &new->owners[i].list); 31874c3cbe3SAl Viro } 31974c3cbe3SAl Viro 32074c3cbe3SAl Viro list_replace_rcu(&chunk->hash, &new->hash); 32174c3cbe3SAl Viro list_for_each_entry(owner, &new->trees, same_root) 32274c3cbe3SAl Viro owner->root = new; 32374c3cbe3SAl Viro spin_unlock(&hash_lock); 32428a3a7ebSEric Paris spin_unlock(&entry->lock); 325be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 326e2a29943SLino Sanfilippo fsnotify_destroy_mark(entry, audit_tree_group); 327b3e8692bSMiklos Szeredi fsnotify_put_mark(&new->mark); /* drop initial reference */ 3288f7b0ba1SAl Viro goto out; 32974c3cbe3SAl Viro 33074c3cbe3SAl Viro Fallback: 33174c3cbe3SAl Viro // do the best we can 33274c3cbe3SAl Viro spin_lock(&hash_lock); 33374c3cbe3SAl Viro if (owner->root == chunk) { 33474c3cbe3SAl Viro list_del_init(&owner->same_root); 33574c3cbe3SAl Viro owner->root = NULL; 33674c3cbe3SAl Viro } 33774c3cbe3SAl Viro list_del_init(&p->list); 33874c3cbe3SAl Viro p->owner = NULL; 33974c3cbe3SAl Viro put_tree(owner); 34074c3cbe3SAl Viro spin_unlock(&hash_lock); 34128a3a7ebSEric Paris spin_unlock(&entry->lock); 342be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 3438f7b0ba1SAl Viro out: 34428a3a7ebSEric Paris fsnotify_put_mark(entry); 3458f7b0ba1SAl Viro spin_lock(&hash_lock); 34674c3cbe3SAl Viro } 34774c3cbe3SAl Viro 34874c3cbe3SAl Viro static int create_chunk(struct inode *inode, struct audit_tree *tree) 34974c3cbe3SAl Viro { 350e61ce867SEric Paris struct fsnotify_mark *entry; 35174c3cbe3SAl Viro struct audit_chunk *chunk = alloc_chunk(1); 35274c3cbe3SAl Viro if (!chunk) 35374c3cbe3SAl Viro return -ENOMEM; 35474c3cbe3SAl Viro 35528a3a7ebSEric Paris entry = &chunk->mark; 3567b129323SJan Kara if (fsnotify_add_mark(entry, inode, NULL, 0)) { 3570fe33aaeSMiklos Szeredi fsnotify_put_mark(entry); 35874c3cbe3SAl Viro return -ENOSPC; 35974c3cbe3SAl Viro } 36074c3cbe3SAl Viro 36128a3a7ebSEric Paris spin_lock(&entry->lock); 36274c3cbe3SAl Viro spin_lock(&hash_lock); 36374c3cbe3SAl Viro if (tree->goner) { 36474c3cbe3SAl Viro spin_unlock(&hash_lock); 36574c3cbe3SAl Viro chunk->dead = 1; 36628a3a7ebSEric Paris spin_unlock(&entry->lock); 367e2a29943SLino Sanfilippo fsnotify_destroy_mark(entry, audit_tree_group); 36828a3a7ebSEric Paris fsnotify_put_mark(entry); 36974c3cbe3SAl Viro return 0; 37074c3cbe3SAl Viro } 37174c3cbe3SAl Viro chunk->owners[0].index = (1U << 31); 37274c3cbe3SAl Viro chunk->owners[0].owner = tree; 37374c3cbe3SAl Viro get_tree(tree); 37474c3cbe3SAl Viro list_add(&chunk->owners[0].list, &tree->chunks); 37574c3cbe3SAl Viro if (!tree->root) { 37674c3cbe3SAl Viro tree->root = chunk; 37774c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees); 37874c3cbe3SAl Viro } 37974c3cbe3SAl Viro insert_hash(chunk); 38074c3cbe3SAl Viro spin_unlock(&hash_lock); 38128a3a7ebSEric Paris spin_unlock(&entry->lock); 382b3e8692bSMiklos Szeredi fsnotify_put_mark(entry); /* drop initial reference */ 38374c3cbe3SAl Viro return 0; 38474c3cbe3SAl Viro } 38574c3cbe3SAl Viro 38674c3cbe3SAl Viro /* the first tagged inode becomes root of tree */ 38774c3cbe3SAl Viro static int tag_chunk(struct inode *inode, struct audit_tree *tree) 38874c3cbe3SAl Viro { 389e61ce867SEric Paris struct fsnotify_mark *old_entry, *chunk_entry; 39074c3cbe3SAl Viro struct audit_tree *owner; 39174c3cbe3SAl Viro struct audit_chunk *chunk, *old; 39274c3cbe3SAl Viro struct node *p; 39374c3cbe3SAl Viro int n; 39474c3cbe3SAl Viro 395b1362edfSJan Kara old_entry = fsnotify_find_mark(&inode->i_fsnotify_marks, 396b1362edfSJan Kara audit_tree_group); 39728a3a7ebSEric Paris if (!old_entry) 39874c3cbe3SAl Viro return create_chunk(inode, tree); 39974c3cbe3SAl Viro 40028a3a7ebSEric Paris old = container_of(old_entry, struct audit_chunk, mark); 40174c3cbe3SAl Viro 40274c3cbe3SAl Viro /* are we already there? */ 40374c3cbe3SAl Viro spin_lock(&hash_lock); 40474c3cbe3SAl Viro for (n = 0; n < old->count; n++) { 40574c3cbe3SAl Viro if (old->owners[n].owner == tree) { 40674c3cbe3SAl Viro spin_unlock(&hash_lock); 40728a3a7ebSEric Paris fsnotify_put_mark(old_entry); 40874c3cbe3SAl Viro return 0; 40974c3cbe3SAl Viro } 41074c3cbe3SAl Viro } 41174c3cbe3SAl Viro spin_unlock(&hash_lock); 41274c3cbe3SAl Viro 41374c3cbe3SAl Viro chunk = alloc_chunk(old->count + 1); 414b4c30aadSAl Viro if (!chunk) { 41528a3a7ebSEric Paris fsnotify_put_mark(old_entry); 41674c3cbe3SAl Viro return -ENOMEM; 417b4c30aadSAl Viro } 41874c3cbe3SAl Viro 41928a3a7ebSEric Paris chunk_entry = &chunk->mark; 42028a3a7ebSEric Paris 421be29d20fSJan Kara mutex_lock(&old_entry->group->mark_mutex); 42228a3a7ebSEric Paris spin_lock(&old_entry->lock); 4236b3f05d2SJan Kara /* 4246b3f05d2SJan Kara * mark_mutex protects mark from getting detached and thus also from 4256b3f05d2SJan Kara * mark->connector->inode getting NULL. 4266b3f05d2SJan Kara */ 42743471d15SJan Kara if (!(old_entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) { 42828a3a7ebSEric Paris /* old_entry is being shot, lets just lie */ 42928a3a7ebSEric Paris spin_unlock(&old_entry->lock); 430be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 43128a3a7ebSEric Paris fsnotify_put_mark(old_entry); 4327b129323SJan Kara fsnotify_put_mark(&chunk->mark); 43328a3a7ebSEric Paris return -ENOENT; 43428a3a7ebSEric Paris } 43528a3a7ebSEric Paris 4367b129323SJan Kara if (fsnotify_add_mark_locked(chunk_entry, 43786ffe245SJan Kara old_entry->connector->inode, NULL, 1)) { 43828a3a7ebSEric Paris spin_unlock(&old_entry->lock); 439be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 4400fe33aaeSMiklos Szeredi fsnotify_put_mark(chunk_entry); 44128a3a7ebSEric Paris fsnotify_put_mark(old_entry); 44274c3cbe3SAl Viro return -ENOSPC; 44374c3cbe3SAl Viro } 44428a3a7ebSEric Paris 44528a3a7ebSEric Paris /* even though we hold old_entry->lock, this is safe since chunk_entry->lock could NEVER have been grabbed before */ 44628a3a7ebSEric Paris spin_lock(&chunk_entry->lock); 44774c3cbe3SAl Viro spin_lock(&hash_lock); 44828a3a7ebSEric Paris 44928a3a7ebSEric Paris /* we now hold old_entry->lock, chunk_entry->lock, and hash_lock */ 45074c3cbe3SAl Viro if (tree->goner) { 45174c3cbe3SAl Viro spin_unlock(&hash_lock); 45274c3cbe3SAl Viro chunk->dead = 1; 45328a3a7ebSEric Paris spin_unlock(&chunk_entry->lock); 45428a3a7ebSEric Paris spin_unlock(&old_entry->lock); 455be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 45628a3a7ebSEric Paris 457e2a29943SLino Sanfilippo fsnotify_destroy_mark(chunk_entry, audit_tree_group); 45828a3a7ebSEric Paris 45928a3a7ebSEric Paris fsnotify_put_mark(chunk_entry); 46028a3a7ebSEric Paris fsnotify_put_mark(old_entry); 46174c3cbe3SAl Viro return 0; 46274c3cbe3SAl Viro } 46374c3cbe3SAl Viro list_replace_init(&old->trees, &chunk->trees); 46474c3cbe3SAl Viro for (n = 0, p = chunk->owners; n < old->count; n++, p++) { 46574c3cbe3SAl Viro struct audit_tree *s = old->owners[n].owner; 46674c3cbe3SAl Viro p->owner = s; 46774c3cbe3SAl Viro p->index = old->owners[n].index; 46874c3cbe3SAl Viro if (!s) /* result of fallback in untag */ 46974c3cbe3SAl Viro continue; 47074c3cbe3SAl Viro get_tree(s); 47174c3cbe3SAl Viro list_replace_init(&old->owners[n].list, &p->list); 47274c3cbe3SAl Viro } 47374c3cbe3SAl Viro p->index = (chunk->count - 1) | (1U<<31); 47474c3cbe3SAl Viro p->owner = tree; 47574c3cbe3SAl Viro get_tree(tree); 47674c3cbe3SAl Viro list_add(&p->list, &tree->chunks); 47774c3cbe3SAl Viro list_replace_rcu(&old->hash, &chunk->hash); 47874c3cbe3SAl Viro list_for_each_entry(owner, &chunk->trees, same_root) 47974c3cbe3SAl Viro owner->root = chunk; 48074c3cbe3SAl Viro old->dead = 1; 48174c3cbe3SAl Viro if (!tree->root) { 48274c3cbe3SAl Viro tree->root = chunk; 48374c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees); 48474c3cbe3SAl Viro } 48574c3cbe3SAl Viro spin_unlock(&hash_lock); 48628a3a7ebSEric Paris spin_unlock(&chunk_entry->lock); 48728a3a7ebSEric Paris spin_unlock(&old_entry->lock); 488be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 489e2a29943SLino Sanfilippo fsnotify_destroy_mark(old_entry, audit_tree_group); 490b3e8692bSMiklos Szeredi fsnotify_put_mark(chunk_entry); /* drop initial reference */ 49128a3a7ebSEric Paris fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ 49274c3cbe3SAl Viro return 0; 49374c3cbe3SAl Viro } 49474c3cbe3SAl Viro 4952991dd2bSRichard Guy Briggs static void audit_tree_log_remove_rule(struct audit_krule *rule) 49674c3cbe3SAl Viro { 49774c3cbe3SAl Viro struct audit_buffer *ab; 49874c3cbe3SAl Viro 49974c3cbe3SAl Viro ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); 5000644ec0cSKees Cook if (unlikely(!ab)) 5010644ec0cSKees Cook return; 502c1e8f06dSSteve Grubb audit_log_format(ab, "op=remove_rule"); 5039d960985SEric Paris audit_log_format(ab, " dir="); 50474c3cbe3SAl Viro audit_log_untrustedstring(ab, rule->tree->pathname); 5059d960985SEric Paris audit_log_key(ab, rule->filterkey); 50674c3cbe3SAl Viro audit_log_format(ab, " list=%d res=1", rule->listnr); 50774c3cbe3SAl Viro audit_log_end(ab); 5080644ec0cSKees Cook } 5090644ec0cSKees Cook 5100644ec0cSKees Cook static void kill_rules(struct audit_tree *tree) 5110644ec0cSKees Cook { 5120644ec0cSKees Cook struct audit_krule *rule, *next; 5130644ec0cSKees Cook struct audit_entry *entry; 5140644ec0cSKees Cook 5150644ec0cSKees Cook list_for_each_entry_safe(rule, next, &tree->rules, rlist) { 5160644ec0cSKees Cook entry = container_of(rule, struct audit_entry, rule); 5170644ec0cSKees Cook 5180644ec0cSKees Cook list_del_init(&rule->rlist); 5190644ec0cSKees Cook if (rule->tree) { 5200644ec0cSKees Cook /* not a half-baked one */ 5212991dd2bSRichard Guy Briggs audit_tree_log_remove_rule(rule); 52234d99af5SRichard Guy Briggs if (entry->rule.exe) 52334d99af5SRichard Guy Briggs audit_remove_mark(entry->rule.exe); 52474c3cbe3SAl Viro rule->tree = NULL; 52574c3cbe3SAl Viro list_del_rcu(&entry->list); 526e45aa212SAl Viro list_del(&entry->rule.list); 52774c3cbe3SAl Viro call_rcu(&entry->rcu, audit_free_rule_rcu); 52874c3cbe3SAl Viro } 52974c3cbe3SAl Viro } 53074c3cbe3SAl Viro } 53174c3cbe3SAl Viro 53274c3cbe3SAl Viro /* 53374c3cbe3SAl Viro * finish killing struct audit_tree 53474c3cbe3SAl Viro */ 53574c3cbe3SAl Viro static void prune_one(struct audit_tree *victim) 53674c3cbe3SAl Viro { 53774c3cbe3SAl Viro spin_lock(&hash_lock); 53874c3cbe3SAl Viro while (!list_empty(&victim->chunks)) { 53974c3cbe3SAl Viro struct node *p; 54074c3cbe3SAl Viro 54174c3cbe3SAl Viro p = list_entry(victim->chunks.next, struct node, list); 54274c3cbe3SAl Viro 5438f7b0ba1SAl Viro untag_chunk(p); 54474c3cbe3SAl Viro } 54574c3cbe3SAl Viro spin_unlock(&hash_lock); 54674c3cbe3SAl Viro put_tree(victim); 54774c3cbe3SAl Viro } 54874c3cbe3SAl Viro 54974c3cbe3SAl Viro /* trim the uncommitted chunks from tree */ 55074c3cbe3SAl Viro 55174c3cbe3SAl Viro static void trim_marked(struct audit_tree *tree) 55274c3cbe3SAl Viro { 55374c3cbe3SAl Viro struct list_head *p, *q; 55474c3cbe3SAl Viro spin_lock(&hash_lock); 55574c3cbe3SAl Viro if (tree->goner) { 55674c3cbe3SAl Viro spin_unlock(&hash_lock); 55774c3cbe3SAl Viro return; 55874c3cbe3SAl Viro } 55974c3cbe3SAl Viro /* reorder */ 56074c3cbe3SAl Viro for (p = tree->chunks.next; p != &tree->chunks; p = q) { 56174c3cbe3SAl Viro struct node *node = list_entry(p, struct node, list); 56274c3cbe3SAl Viro q = p->next; 56374c3cbe3SAl Viro if (node->index & (1U<<31)) { 56474c3cbe3SAl Viro list_del_init(p); 56574c3cbe3SAl Viro list_add(p, &tree->chunks); 56674c3cbe3SAl Viro } 56774c3cbe3SAl Viro } 56874c3cbe3SAl Viro 56974c3cbe3SAl Viro while (!list_empty(&tree->chunks)) { 57074c3cbe3SAl Viro struct node *node; 57174c3cbe3SAl Viro 57274c3cbe3SAl Viro node = list_entry(tree->chunks.next, struct node, list); 57374c3cbe3SAl Viro 57474c3cbe3SAl Viro /* have we run out of marked? */ 57574c3cbe3SAl Viro if (!(node->index & (1U<<31))) 57674c3cbe3SAl Viro break; 57774c3cbe3SAl Viro 5788f7b0ba1SAl Viro untag_chunk(node); 57974c3cbe3SAl Viro } 58074c3cbe3SAl Viro if (!tree->root && !tree->goner) { 58174c3cbe3SAl Viro tree->goner = 1; 58274c3cbe3SAl Viro spin_unlock(&hash_lock); 58374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 58474c3cbe3SAl Viro kill_rules(tree); 58574c3cbe3SAl Viro list_del_init(&tree->list); 58674c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 58774c3cbe3SAl Viro prune_one(tree); 58874c3cbe3SAl Viro } else { 58974c3cbe3SAl Viro spin_unlock(&hash_lock); 59074c3cbe3SAl Viro } 59174c3cbe3SAl Viro } 59274c3cbe3SAl Viro 593916d7576SAl Viro static void audit_schedule_prune(void); 594916d7576SAl Viro 59574c3cbe3SAl Viro /* called with audit_filter_mutex */ 59674c3cbe3SAl Viro int audit_remove_tree_rule(struct audit_krule *rule) 59774c3cbe3SAl Viro { 59874c3cbe3SAl Viro struct audit_tree *tree; 59974c3cbe3SAl Viro tree = rule->tree; 60074c3cbe3SAl Viro if (tree) { 60174c3cbe3SAl Viro spin_lock(&hash_lock); 60274c3cbe3SAl Viro list_del_init(&rule->rlist); 60374c3cbe3SAl Viro if (list_empty(&tree->rules) && !tree->goner) { 60474c3cbe3SAl Viro tree->root = NULL; 60574c3cbe3SAl Viro list_del_init(&tree->same_root); 60674c3cbe3SAl Viro tree->goner = 1; 60774c3cbe3SAl Viro list_move(&tree->list, &prune_list); 60874c3cbe3SAl Viro rule->tree = NULL; 60974c3cbe3SAl Viro spin_unlock(&hash_lock); 61074c3cbe3SAl Viro audit_schedule_prune(); 61174c3cbe3SAl Viro return 1; 61274c3cbe3SAl Viro } 61374c3cbe3SAl Viro rule->tree = NULL; 61474c3cbe3SAl Viro spin_unlock(&hash_lock); 61574c3cbe3SAl Viro return 1; 61674c3cbe3SAl Viro } 61774c3cbe3SAl Viro return 0; 61874c3cbe3SAl Viro } 61974c3cbe3SAl Viro 6201f707137SAl Viro static int compare_root(struct vfsmount *mnt, void *arg) 6211f707137SAl Viro { 622f410ff65SJan Kara return inode_to_key(d_backing_inode(mnt->mnt_root)) == 623f410ff65SJan Kara (unsigned long)arg; 6241f707137SAl Viro } 6251f707137SAl Viro 62674c3cbe3SAl Viro void audit_trim_trees(void) 62774c3cbe3SAl Viro { 62874c3cbe3SAl Viro struct list_head cursor; 62974c3cbe3SAl Viro 63074c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 63174c3cbe3SAl Viro list_add(&cursor, &tree_list); 63274c3cbe3SAl Viro while (cursor.next != &tree_list) { 63374c3cbe3SAl Viro struct audit_tree *tree; 63498bc993fSAl Viro struct path path; 63574c3cbe3SAl Viro struct vfsmount *root_mnt; 63674c3cbe3SAl Viro struct node *node; 63774c3cbe3SAl Viro int err; 63874c3cbe3SAl Viro 63974c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 64074c3cbe3SAl Viro get_tree(tree); 64174c3cbe3SAl Viro list_del(&cursor); 64274c3cbe3SAl Viro list_add(&cursor, &tree->list); 64374c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 64474c3cbe3SAl Viro 64598bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 64674c3cbe3SAl Viro if (err) 64774c3cbe3SAl Viro goto skip_it; 64874c3cbe3SAl Viro 649589ff870SAl Viro root_mnt = collect_mounts(&path); 65098bc993fSAl Viro path_put(&path); 651be34d1a3SDavid Howells if (IS_ERR(root_mnt)) 65274c3cbe3SAl Viro goto skip_it; 65374c3cbe3SAl Viro 65474c3cbe3SAl Viro spin_lock(&hash_lock); 65574c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) { 65628a3a7ebSEric Paris struct audit_chunk *chunk = find_chunk(node); 65725985edcSLucas De Marchi /* this could be NULL if the watch is dying else where... */ 65874c3cbe3SAl Viro node->index |= 1U<<31; 659f410ff65SJan Kara if (iterate_mounts(compare_root, 660f410ff65SJan Kara (void *)chunk_to_key(chunk), 661f410ff65SJan Kara root_mnt)) 66274c3cbe3SAl Viro node->index &= ~(1U<<31); 66374c3cbe3SAl Viro } 66474c3cbe3SAl Viro spin_unlock(&hash_lock); 66574c3cbe3SAl Viro trim_marked(tree); 66674c3cbe3SAl Viro drop_collected_mounts(root_mnt); 66774c3cbe3SAl Viro skip_it: 66812b2f117SChen Gang put_tree(tree); 66974c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 67074c3cbe3SAl Viro } 67174c3cbe3SAl Viro list_del(&cursor); 67274c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 67374c3cbe3SAl Viro } 67474c3cbe3SAl Viro 67574c3cbe3SAl Viro int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) 67674c3cbe3SAl Viro { 67774c3cbe3SAl Viro 67874c3cbe3SAl Viro if (pathname[0] != '/' || 67974c3cbe3SAl Viro rule->listnr != AUDIT_FILTER_EXIT || 6805af75d8dSAl Viro op != Audit_equal || 68174c3cbe3SAl Viro rule->inode_f || rule->watch || rule->tree) 68274c3cbe3SAl Viro return -EINVAL; 68374c3cbe3SAl Viro rule->tree = alloc_tree(pathname); 68474c3cbe3SAl Viro if (!rule->tree) 68574c3cbe3SAl Viro return -ENOMEM; 68674c3cbe3SAl Viro return 0; 68774c3cbe3SAl Viro } 68874c3cbe3SAl Viro 68974c3cbe3SAl Viro void audit_put_tree(struct audit_tree *tree) 69074c3cbe3SAl Viro { 69174c3cbe3SAl Viro put_tree(tree); 69274c3cbe3SAl Viro } 69374c3cbe3SAl Viro 6941f707137SAl Viro static int tag_mount(struct vfsmount *mnt, void *arg) 6951f707137SAl Viro { 6963b362157SDavid Howells return tag_chunk(d_backing_inode(mnt->mnt_root), arg); 6971f707137SAl Viro } 6981f707137SAl Viro 699f1aaf262SImre Palik /* 700f1aaf262SImre Palik * That gets run when evict_chunk() ends up needing to kill audit_tree. 701f1aaf262SImre Palik * Runs from a separate thread. 702f1aaf262SImre Palik */ 703f1aaf262SImre Palik static int prune_tree_thread(void *unused) 704f1aaf262SImre Palik { 705f1aaf262SImre Palik for (;;) { 7060bf676d1SJiri Slaby if (list_empty(&prune_list)) { 707f1aaf262SImre Palik set_current_state(TASK_INTERRUPTIBLE); 708f1aaf262SImre Palik schedule(); 7090bf676d1SJiri Slaby } 710f1aaf262SImre Palik 711f1aaf262SImre Palik mutex_lock(&audit_cmd_mutex); 712f1aaf262SImre Palik mutex_lock(&audit_filter_mutex); 713f1aaf262SImre Palik 714f1aaf262SImre Palik while (!list_empty(&prune_list)) { 715f1aaf262SImre Palik struct audit_tree *victim; 716f1aaf262SImre Palik 717f1aaf262SImre Palik victim = list_entry(prune_list.next, 718f1aaf262SImre Palik struct audit_tree, list); 719f1aaf262SImre Palik list_del_init(&victim->list); 720f1aaf262SImre Palik 721f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex); 722f1aaf262SImre Palik 723f1aaf262SImre Palik prune_one(victim); 724f1aaf262SImre Palik 725f1aaf262SImre Palik mutex_lock(&audit_filter_mutex); 726f1aaf262SImre Palik } 727f1aaf262SImre Palik 728f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex); 729f1aaf262SImre Palik mutex_unlock(&audit_cmd_mutex); 730f1aaf262SImre Palik } 731f1aaf262SImre Palik return 0; 732f1aaf262SImre Palik } 733f1aaf262SImre Palik 734f1aaf262SImre Palik static int audit_launch_prune(void) 735f1aaf262SImre Palik { 736f1aaf262SImre Palik if (prune_thread) 737f1aaf262SImre Palik return 0; 7380bf676d1SJiri Slaby prune_thread = kthread_run(prune_tree_thread, NULL, 739f1aaf262SImre Palik "audit_prune_tree"); 740f1aaf262SImre Palik if (IS_ERR(prune_thread)) { 741f1aaf262SImre Palik pr_err("cannot start thread audit_prune_tree"); 742f1aaf262SImre Palik prune_thread = NULL; 743f1aaf262SImre Palik return -ENOMEM; 744f1aaf262SImre Palik } 7450bf676d1SJiri Slaby return 0; 746f1aaf262SImre Palik } 747f1aaf262SImre Palik 74874c3cbe3SAl Viro /* called with audit_filter_mutex */ 74974c3cbe3SAl Viro int audit_add_tree_rule(struct audit_krule *rule) 75074c3cbe3SAl Viro { 75174c3cbe3SAl Viro struct audit_tree *seed = rule->tree, *tree; 75298bc993fSAl Viro struct path path; 7531f707137SAl Viro struct vfsmount *mnt; 75474c3cbe3SAl Viro int err; 75574c3cbe3SAl Viro 756736f3203SChen Gang rule->tree = NULL; 75774c3cbe3SAl Viro list_for_each_entry(tree, &tree_list, list) { 75874c3cbe3SAl Viro if (!strcmp(seed->pathname, tree->pathname)) { 75974c3cbe3SAl Viro put_tree(seed); 76074c3cbe3SAl Viro rule->tree = tree; 76174c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 76274c3cbe3SAl Viro return 0; 76374c3cbe3SAl Viro } 76474c3cbe3SAl Viro } 76574c3cbe3SAl Viro tree = seed; 76674c3cbe3SAl Viro list_add(&tree->list, &tree_list); 76774c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 76874c3cbe3SAl Viro /* do not set rule->tree yet */ 76974c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 77074c3cbe3SAl Viro 771f1aaf262SImre Palik if (unlikely(!prune_thread)) { 772f1aaf262SImre Palik err = audit_launch_prune(); 773f1aaf262SImre Palik if (err) 774f1aaf262SImre Palik goto Err; 775f1aaf262SImre Palik } 776f1aaf262SImre Palik 77798bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 77874c3cbe3SAl Viro if (err) 77974c3cbe3SAl Viro goto Err; 780589ff870SAl Viro mnt = collect_mounts(&path); 78198bc993fSAl Viro path_put(&path); 782be34d1a3SDavid Howells if (IS_ERR(mnt)) { 783be34d1a3SDavid Howells err = PTR_ERR(mnt); 78474c3cbe3SAl Viro goto Err; 78574c3cbe3SAl Viro } 78674c3cbe3SAl Viro 78774c3cbe3SAl Viro get_tree(tree); 7881f707137SAl Viro err = iterate_mounts(tag_mount, tree, mnt); 78974c3cbe3SAl Viro drop_collected_mounts(mnt); 79074c3cbe3SAl Viro 79174c3cbe3SAl Viro if (!err) { 79274c3cbe3SAl Viro struct node *node; 79374c3cbe3SAl Viro spin_lock(&hash_lock); 79474c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 79574c3cbe3SAl Viro node->index &= ~(1U<<31); 79674c3cbe3SAl Viro spin_unlock(&hash_lock); 79774c3cbe3SAl Viro } else { 79874c3cbe3SAl Viro trim_marked(tree); 79974c3cbe3SAl Viro goto Err; 80074c3cbe3SAl Viro } 80174c3cbe3SAl Viro 80274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 80374c3cbe3SAl Viro if (list_empty(&rule->rlist)) { 80474c3cbe3SAl Viro put_tree(tree); 80574c3cbe3SAl Viro return -ENOENT; 80674c3cbe3SAl Viro } 80774c3cbe3SAl Viro rule->tree = tree; 80874c3cbe3SAl Viro put_tree(tree); 80974c3cbe3SAl Viro 81074c3cbe3SAl Viro return 0; 81174c3cbe3SAl Viro Err: 81274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 81374c3cbe3SAl Viro list_del_init(&tree->list); 81474c3cbe3SAl Viro list_del_init(&tree->rules); 81574c3cbe3SAl Viro put_tree(tree); 81674c3cbe3SAl Viro return err; 81774c3cbe3SAl Viro } 81874c3cbe3SAl Viro 81974c3cbe3SAl Viro int audit_tag_tree(char *old, char *new) 82074c3cbe3SAl Viro { 82174c3cbe3SAl Viro struct list_head cursor, barrier; 82274c3cbe3SAl Viro int failed = 0; 8232096f759SAl Viro struct path path1, path2; 82474c3cbe3SAl Viro struct vfsmount *tagged; 82574c3cbe3SAl Viro int err; 82674c3cbe3SAl Viro 8272096f759SAl Viro err = kern_path(new, 0, &path2); 82874c3cbe3SAl Viro if (err) 82974c3cbe3SAl Viro return err; 8302096f759SAl Viro tagged = collect_mounts(&path2); 8312096f759SAl Viro path_put(&path2); 832be34d1a3SDavid Howells if (IS_ERR(tagged)) 833be34d1a3SDavid Howells return PTR_ERR(tagged); 83474c3cbe3SAl Viro 8352096f759SAl Viro err = kern_path(old, 0, &path1); 83674c3cbe3SAl Viro if (err) { 83774c3cbe3SAl Viro drop_collected_mounts(tagged); 83874c3cbe3SAl Viro return err; 83974c3cbe3SAl Viro } 84074c3cbe3SAl Viro 84174c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 84274c3cbe3SAl Viro list_add(&barrier, &tree_list); 84374c3cbe3SAl Viro list_add(&cursor, &barrier); 84474c3cbe3SAl Viro 84574c3cbe3SAl Viro while (cursor.next != &tree_list) { 84674c3cbe3SAl Viro struct audit_tree *tree; 8472096f759SAl Viro int good_one = 0; 84874c3cbe3SAl Viro 84974c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 85074c3cbe3SAl Viro get_tree(tree); 85174c3cbe3SAl Viro list_del(&cursor); 85274c3cbe3SAl Viro list_add(&cursor, &tree->list); 85374c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 85474c3cbe3SAl Viro 8552096f759SAl Viro err = kern_path(tree->pathname, 0, &path2); 8562096f759SAl Viro if (!err) { 8572096f759SAl Viro good_one = path_is_under(&path1, &path2); 8582096f759SAl Viro path_put(&path2); 85974c3cbe3SAl Viro } 86074c3cbe3SAl Viro 8612096f759SAl Viro if (!good_one) { 86274c3cbe3SAl Viro put_tree(tree); 86374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 86474c3cbe3SAl Viro continue; 86574c3cbe3SAl Viro } 86674c3cbe3SAl Viro 8671f707137SAl Viro failed = iterate_mounts(tag_mount, tree, tagged); 86874c3cbe3SAl Viro if (failed) { 86974c3cbe3SAl Viro put_tree(tree); 87074c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 87174c3cbe3SAl Viro break; 87274c3cbe3SAl Viro } 87374c3cbe3SAl Viro 87474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 87574c3cbe3SAl Viro spin_lock(&hash_lock); 87674c3cbe3SAl Viro if (!tree->goner) { 87774c3cbe3SAl Viro list_del(&tree->list); 87874c3cbe3SAl Viro list_add(&tree->list, &tree_list); 87974c3cbe3SAl Viro } 88074c3cbe3SAl Viro spin_unlock(&hash_lock); 88174c3cbe3SAl Viro put_tree(tree); 88274c3cbe3SAl Viro } 88374c3cbe3SAl Viro 88474c3cbe3SAl Viro while (barrier.prev != &tree_list) { 88574c3cbe3SAl Viro struct audit_tree *tree; 88674c3cbe3SAl Viro 88774c3cbe3SAl Viro tree = container_of(barrier.prev, struct audit_tree, list); 88874c3cbe3SAl Viro get_tree(tree); 88974c3cbe3SAl Viro list_del(&tree->list); 89074c3cbe3SAl Viro list_add(&tree->list, &barrier); 89174c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 89274c3cbe3SAl Viro 89374c3cbe3SAl Viro if (!failed) { 89474c3cbe3SAl Viro struct node *node; 89574c3cbe3SAl Viro spin_lock(&hash_lock); 89674c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 89774c3cbe3SAl Viro node->index &= ~(1U<<31); 89874c3cbe3SAl Viro spin_unlock(&hash_lock); 89974c3cbe3SAl Viro } else { 90074c3cbe3SAl Viro trim_marked(tree); 90174c3cbe3SAl Viro } 90274c3cbe3SAl Viro 90374c3cbe3SAl Viro put_tree(tree); 90474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 90574c3cbe3SAl Viro } 90674c3cbe3SAl Viro list_del(&barrier); 90774c3cbe3SAl Viro list_del(&cursor); 90874c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 9092096f759SAl Viro path_put(&path1); 91074c3cbe3SAl Viro drop_collected_mounts(tagged); 91174c3cbe3SAl Viro return failed; 91274c3cbe3SAl Viro } 91374c3cbe3SAl Viro 914916d7576SAl Viro 915916d7576SAl Viro static void audit_schedule_prune(void) 916916d7576SAl Viro { 917f1aaf262SImre Palik wake_up_process(prune_thread); 918916d7576SAl Viro } 919916d7576SAl Viro 920916d7576SAl Viro /* 921916d7576SAl Viro * ... and that one is done if evict_chunk() decides to delay until the end 922916d7576SAl Viro * of syscall. Runs synchronously. 923916d7576SAl Viro */ 924916d7576SAl Viro void audit_kill_trees(struct list_head *list) 925916d7576SAl Viro { 926916d7576SAl Viro mutex_lock(&audit_cmd_mutex); 927916d7576SAl Viro mutex_lock(&audit_filter_mutex); 928916d7576SAl Viro 929916d7576SAl Viro while (!list_empty(list)) { 930916d7576SAl Viro struct audit_tree *victim; 931916d7576SAl Viro 932916d7576SAl Viro victim = list_entry(list->next, struct audit_tree, list); 933916d7576SAl Viro kill_rules(victim); 934916d7576SAl Viro list_del_init(&victim->list); 935916d7576SAl Viro 936916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 937916d7576SAl Viro 938916d7576SAl Viro prune_one(victim); 939916d7576SAl Viro 940916d7576SAl Viro mutex_lock(&audit_filter_mutex); 941916d7576SAl Viro } 942916d7576SAl Viro 943916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 944916d7576SAl Viro mutex_unlock(&audit_cmd_mutex); 94574c3cbe3SAl Viro } 94674c3cbe3SAl Viro 94774c3cbe3SAl Viro /* 94874c3cbe3SAl Viro * Here comes the stuff asynchronous to auditctl operations 94974c3cbe3SAl Viro */ 95074c3cbe3SAl Viro 95174c3cbe3SAl Viro static void evict_chunk(struct audit_chunk *chunk) 95274c3cbe3SAl Viro { 95374c3cbe3SAl Viro struct audit_tree *owner; 954916d7576SAl Viro struct list_head *postponed = audit_killed_trees(); 955916d7576SAl Viro int need_prune = 0; 95674c3cbe3SAl Viro int n; 95774c3cbe3SAl Viro 95874c3cbe3SAl Viro if (chunk->dead) 95974c3cbe3SAl Viro return; 96074c3cbe3SAl Viro 96174c3cbe3SAl Viro chunk->dead = 1; 96274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 96374c3cbe3SAl Viro spin_lock(&hash_lock); 96474c3cbe3SAl Viro while (!list_empty(&chunk->trees)) { 96574c3cbe3SAl Viro owner = list_entry(chunk->trees.next, 96674c3cbe3SAl Viro struct audit_tree, same_root); 96774c3cbe3SAl Viro owner->goner = 1; 96874c3cbe3SAl Viro owner->root = NULL; 96974c3cbe3SAl Viro list_del_init(&owner->same_root); 97074c3cbe3SAl Viro spin_unlock(&hash_lock); 971916d7576SAl Viro if (!postponed) { 97274c3cbe3SAl Viro kill_rules(owner); 97374c3cbe3SAl Viro list_move(&owner->list, &prune_list); 974916d7576SAl Viro need_prune = 1; 975916d7576SAl Viro } else { 976916d7576SAl Viro list_move(&owner->list, postponed); 977916d7576SAl Viro } 97874c3cbe3SAl Viro spin_lock(&hash_lock); 97974c3cbe3SAl Viro } 98074c3cbe3SAl Viro list_del_rcu(&chunk->hash); 98174c3cbe3SAl Viro for (n = 0; n < chunk->count; n++) 98274c3cbe3SAl Viro list_del_init(&chunk->owners[n].list); 98374c3cbe3SAl Viro spin_unlock(&hash_lock); 984f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex); 985916d7576SAl Viro if (need_prune) 986916d7576SAl Viro audit_schedule_prune(); 98774c3cbe3SAl Viro } 98874c3cbe3SAl Viro 9893a9b16b4SEric Paris static int audit_tree_handle_event(struct fsnotify_group *group, 9907053aee2SJan Kara struct inode *to_tell, 991ce8f76fbSEric Paris struct fsnotify_mark *inode_mark, 9927053aee2SJan Kara struct fsnotify_mark *vfsmount_mark, 9933cd5eca8SAl Viro u32 mask, const void *data, int data_type, 9949385a84dSJan Kara const unsigned char *file_name, u32 cookie, 9959385a84dSJan Kara struct fsnotify_iter_info *iter_info) 99674c3cbe3SAl Viro { 99783c4c4b0SJan Kara return 0; 99828a3a7ebSEric Paris } 99974c3cbe3SAl Viro 1000e61ce867SEric Paris static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group) 100128a3a7ebSEric Paris { 100228a3a7ebSEric Paris struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark); 100328a3a7ebSEric Paris 100474c3cbe3SAl Viro evict_chunk(chunk); 1005b3e8692bSMiklos Szeredi 1006b3e8692bSMiklos Szeredi /* 1007b3e8692bSMiklos Szeredi * We are guaranteed to have at least one reference to the mark from 1008b3e8692bSMiklos Szeredi * either the inode or the caller of fsnotify_destroy_mark(). 1009b3e8692bSMiklos Szeredi */ 1010ab97f873SElena Reshetova BUG_ON(refcount_read(&entry->refcnt) < 1); 101174c3cbe3SAl Viro } 101274c3cbe3SAl Viro 101328a3a7ebSEric Paris static const struct fsnotify_ops audit_tree_ops = { 101428a3a7ebSEric Paris .handle_event = audit_tree_handle_event, 101528a3a7ebSEric Paris .freeing_mark = audit_tree_freeing_mark, 1016054c636eSJan Kara .free_mark = audit_tree_destroy_watch, 101774c3cbe3SAl Viro }; 101874c3cbe3SAl Viro 101974c3cbe3SAl Viro static int __init audit_tree_init(void) 102074c3cbe3SAl Viro { 102174c3cbe3SAl Viro int i; 102274c3cbe3SAl Viro 10230d2e2a1dSEric Paris audit_tree_group = fsnotify_alloc_group(&audit_tree_ops); 102428a3a7ebSEric Paris if (IS_ERR(audit_tree_group)) 102528a3a7ebSEric Paris audit_panic("cannot initialize fsnotify group for rectree watches"); 102674c3cbe3SAl Viro 102774c3cbe3SAl Viro for (i = 0; i < HASH_SIZE; i++) 102874c3cbe3SAl Viro INIT_LIST_HEAD(&chunk_hash_heads[i]); 102974c3cbe3SAl Viro 103074c3cbe3SAl Viro return 0; 103174c3cbe3SAl Viro } 103274c3cbe3SAl Viro __initcall(audit_tree_init); 1033