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); 40f1aaf262SImre Palik static struct task_struct *prune_thread; 4174c3cbe3SAl Viro 4274c3cbe3SAl Viro /* 4374c3cbe3SAl Viro * One struct chunk is attached to each inode of interest. 4474c3cbe3SAl Viro * We replace struct chunk on tagging/untagging. 4574c3cbe3SAl Viro * Rules have pointer to struct audit_tree. 4674c3cbe3SAl Viro * Rules have struct list_head rlist forming a list of rules over 4774c3cbe3SAl Viro * the same tree. 4874c3cbe3SAl Viro * References to struct chunk are collected at audit_inode{,_child}() 4974c3cbe3SAl Viro * time and used in AUDIT_TREE rule matching. 5074c3cbe3SAl Viro * These references are dropped at the same time we are calling 5174c3cbe3SAl Viro * audit_free_names(), etc. 5274c3cbe3SAl Viro * 5374c3cbe3SAl Viro * Cyclic lists galore: 5474c3cbe3SAl Viro * tree.chunks anchors chunk.owners[].list hash_lock 5574c3cbe3SAl Viro * tree.rules anchors rule.rlist audit_filter_mutex 5674c3cbe3SAl Viro * chunk.trees anchors tree.same_root hash_lock 5774c3cbe3SAl Viro * chunk.hash is a hash with middle bits of watch.inode as 5874c3cbe3SAl Viro * a hash function. RCU, hash_lock 5974c3cbe3SAl Viro * 6074c3cbe3SAl Viro * tree is refcounted; one reference for "some rules on rules_list refer to 6174c3cbe3SAl Viro * it", one for each chunk with pointer to it. 6274c3cbe3SAl Viro * 6328a3a7ebSEric Paris * chunk is refcounted by embedded fsnotify_mark + .refs (non-zero refcount 648f7b0ba1SAl Viro * of watch contributes 1 to .refs). 6574c3cbe3SAl Viro * 6674c3cbe3SAl Viro * node.index allows to get from node.list to containing chunk. 6774c3cbe3SAl Viro * MSB of that sucker is stolen to mark taggings that we might have to 6874c3cbe3SAl Viro * revert - several operations have very unpleasant cleanup logics and 6974c3cbe3SAl Viro * that makes a difference. Some. 7074c3cbe3SAl Viro */ 7174c3cbe3SAl Viro 7228a3a7ebSEric Paris static struct fsnotify_group *audit_tree_group; 7374c3cbe3SAl Viro 7474c3cbe3SAl Viro static struct audit_tree *alloc_tree(const char *s) 7574c3cbe3SAl Viro { 7674c3cbe3SAl Viro struct audit_tree *tree; 7774c3cbe3SAl Viro 7874c3cbe3SAl Viro tree = kmalloc(sizeof(struct audit_tree) + strlen(s) + 1, GFP_KERNEL); 7974c3cbe3SAl Viro if (tree) { 8074c3cbe3SAl Viro atomic_set(&tree->count, 1); 8174c3cbe3SAl Viro tree->goner = 0; 8274c3cbe3SAl Viro INIT_LIST_HEAD(&tree->chunks); 8374c3cbe3SAl Viro INIT_LIST_HEAD(&tree->rules); 8474c3cbe3SAl Viro INIT_LIST_HEAD(&tree->list); 8574c3cbe3SAl Viro INIT_LIST_HEAD(&tree->same_root); 8674c3cbe3SAl Viro tree->root = NULL; 8774c3cbe3SAl Viro strcpy(tree->pathname, s); 8874c3cbe3SAl Viro } 8974c3cbe3SAl Viro return tree; 9074c3cbe3SAl Viro } 9174c3cbe3SAl Viro 9274c3cbe3SAl Viro static inline void get_tree(struct audit_tree *tree) 9374c3cbe3SAl Viro { 9474c3cbe3SAl Viro atomic_inc(&tree->count); 9574c3cbe3SAl Viro } 9674c3cbe3SAl Viro 9774c3cbe3SAl Viro static inline void put_tree(struct audit_tree *tree) 9874c3cbe3SAl Viro { 9974c3cbe3SAl Viro if (atomic_dec_and_test(&tree->count)) 1003b097c46SLai Jiangshan kfree_rcu(tree, head); 10174c3cbe3SAl Viro } 10274c3cbe3SAl Viro 10374c3cbe3SAl Viro /* to avoid bringing the entire thing in audit.h */ 10474c3cbe3SAl Viro const char *audit_tree_path(struct audit_tree *tree) 10574c3cbe3SAl Viro { 10674c3cbe3SAl Viro return tree->pathname; 10774c3cbe3SAl Viro } 10874c3cbe3SAl Viro 1098f7b0ba1SAl Viro static void free_chunk(struct audit_chunk *chunk) 11074c3cbe3SAl Viro { 11174c3cbe3SAl Viro int i; 11274c3cbe3SAl Viro 11374c3cbe3SAl Viro for (i = 0; i < chunk->count; i++) { 11474c3cbe3SAl Viro if (chunk->owners[i].owner) 11574c3cbe3SAl Viro put_tree(chunk->owners[i].owner); 11674c3cbe3SAl Viro } 11774c3cbe3SAl Viro kfree(chunk); 11874c3cbe3SAl Viro } 11974c3cbe3SAl Viro 12074c3cbe3SAl Viro void audit_put_chunk(struct audit_chunk *chunk) 12174c3cbe3SAl Viro { 1228f7b0ba1SAl Viro if (atomic_long_dec_and_test(&chunk->refs)) 1238f7b0ba1SAl Viro free_chunk(chunk); 1248f7b0ba1SAl Viro } 1258f7b0ba1SAl Viro 1268f7b0ba1SAl Viro static void __put_chunk(struct rcu_head *rcu) 1278f7b0ba1SAl Viro { 1288f7b0ba1SAl Viro struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head); 1298f7b0ba1SAl Viro audit_put_chunk(chunk); 13074c3cbe3SAl Viro } 13174c3cbe3SAl Viro 132e61ce867SEric Paris static void audit_tree_destroy_watch(struct fsnotify_mark *entry) 13328a3a7ebSEric Paris { 13428a3a7ebSEric Paris struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark); 13528a3a7ebSEric Paris call_rcu(&chunk->head, __put_chunk); 13628a3a7ebSEric Paris } 13728a3a7ebSEric Paris 13828a3a7ebSEric Paris static struct audit_chunk *alloc_chunk(int count) 13928a3a7ebSEric Paris { 14028a3a7ebSEric Paris struct audit_chunk *chunk; 14128a3a7ebSEric Paris size_t size; 14228a3a7ebSEric Paris int i; 14328a3a7ebSEric Paris 14428a3a7ebSEric Paris size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node); 14528a3a7ebSEric Paris chunk = kzalloc(size, GFP_KERNEL); 14628a3a7ebSEric Paris if (!chunk) 14728a3a7ebSEric Paris return NULL; 14828a3a7ebSEric Paris 14928a3a7ebSEric Paris INIT_LIST_HEAD(&chunk->hash); 15028a3a7ebSEric Paris INIT_LIST_HEAD(&chunk->trees); 15128a3a7ebSEric Paris chunk->count = count; 15228a3a7ebSEric Paris atomic_long_set(&chunk->refs, 1); 15328a3a7ebSEric Paris for (i = 0; i < count; i++) { 15428a3a7ebSEric Paris INIT_LIST_HEAD(&chunk->owners[i].list); 15528a3a7ebSEric Paris chunk->owners[i].index = i; 15628a3a7ebSEric Paris } 15728a3a7ebSEric Paris fsnotify_init_mark(&chunk->mark, audit_tree_destroy_watch); 158799b6014SMiklos Szeredi chunk->mark.mask = FS_IN_IGNORED; 15928a3a7ebSEric Paris return chunk; 16028a3a7ebSEric Paris } 16128a3a7ebSEric Paris 16274c3cbe3SAl Viro enum {HASH_SIZE = 128}; 16374c3cbe3SAl Viro static struct list_head chunk_hash_heads[HASH_SIZE]; 16474c3cbe3SAl Viro static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock); 16574c3cbe3SAl Viro 166f410ff65SJan Kara /* Function to return search key in our hash from inode. */ 167f410ff65SJan Kara static unsigned long inode_to_key(const struct inode *inode) 16874c3cbe3SAl Viro { 169f410ff65SJan Kara return (unsigned long)inode; 170f410ff65SJan Kara } 171f410ff65SJan Kara 172f410ff65SJan Kara /* 173f410ff65SJan Kara * Function to return search key in our hash from chunk. Key 0 is special and 174f410ff65SJan Kara * should never be present in the hash. 175f410ff65SJan Kara */ 176f410ff65SJan Kara static unsigned long chunk_to_key(struct audit_chunk *chunk) 177f410ff65SJan Kara { 178f410ff65SJan Kara return (unsigned long)chunk->mark.inode; 179f410ff65SJan Kara } 180f410ff65SJan Kara 181f410ff65SJan Kara static inline struct list_head *chunk_hash(unsigned long key) 182f410ff65SJan Kara { 183f410ff65SJan Kara unsigned long n = key / L1_CACHE_BYTES; 18474c3cbe3SAl Viro return chunk_hash_heads + n % HASH_SIZE; 18574c3cbe3SAl Viro } 18674c3cbe3SAl Viro 18728a3a7ebSEric Paris /* hash_lock & entry->lock is held by caller */ 18874c3cbe3SAl Viro static void insert_hash(struct audit_chunk *chunk) 18974c3cbe3SAl Viro { 190f410ff65SJan Kara unsigned long key = chunk_to_key(chunk); 19128a3a7ebSEric Paris struct list_head *list; 19228a3a7ebSEric Paris 19343471d15SJan Kara if (!(chunk->mark.flags & FSNOTIFY_MARK_FLAG_ATTACHED)) 19428a3a7ebSEric Paris return; 195f410ff65SJan Kara list = chunk_hash(key); 19674c3cbe3SAl Viro list_add_rcu(&chunk->hash, list); 19774c3cbe3SAl Viro } 19874c3cbe3SAl Viro 19974c3cbe3SAl Viro /* called under rcu_read_lock */ 20074c3cbe3SAl Viro struct audit_chunk *audit_tree_lookup(const struct inode *inode) 20174c3cbe3SAl Viro { 202f410ff65SJan Kara unsigned long key = inode_to_key(inode); 203f410ff65SJan Kara struct list_head *list = chunk_hash(key); 2046793a051SPaul E. McKenney struct audit_chunk *p; 20574c3cbe3SAl Viro 2066793a051SPaul E. McKenney list_for_each_entry_rcu(p, list, hash) { 207f410ff65SJan Kara if (chunk_to_key(p) == key) { 2088f7b0ba1SAl Viro atomic_long_inc(&p->refs); 20974c3cbe3SAl Viro return p; 21074c3cbe3SAl Viro } 21174c3cbe3SAl Viro } 21274c3cbe3SAl Viro return NULL; 21374c3cbe3SAl Viro } 21474c3cbe3SAl Viro 2156f1b5d7aSYaowei Bai bool audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree) 21674c3cbe3SAl Viro { 21774c3cbe3SAl Viro int n; 21874c3cbe3SAl Viro for (n = 0; n < chunk->count; n++) 21974c3cbe3SAl Viro if (chunk->owners[n].owner == tree) 2206f1b5d7aSYaowei Bai return true; 2216f1b5d7aSYaowei Bai return false; 22274c3cbe3SAl Viro } 22374c3cbe3SAl Viro 22474c3cbe3SAl Viro /* tagging and untagging inodes with trees */ 22574c3cbe3SAl Viro 2268f7b0ba1SAl Viro static struct audit_chunk *find_chunk(struct node *p) 22774c3cbe3SAl Viro { 2288f7b0ba1SAl Viro int index = p->index & ~(1U<<31); 2298f7b0ba1SAl Viro p -= index; 2308f7b0ba1SAl Viro return container_of(p, struct audit_chunk, owners[0]); 2318f7b0ba1SAl Viro } 2328f7b0ba1SAl Viro 2338f7b0ba1SAl Viro static void untag_chunk(struct node *p) 2348f7b0ba1SAl Viro { 2358f7b0ba1SAl Viro struct audit_chunk *chunk = find_chunk(p); 236e61ce867SEric Paris struct fsnotify_mark *entry = &chunk->mark; 237f7a998a9SAl Viro struct audit_chunk *new = NULL; 23874c3cbe3SAl Viro struct audit_tree *owner; 23974c3cbe3SAl Viro int size = chunk->count - 1; 24074c3cbe3SAl Viro int i, j; 24174c3cbe3SAl Viro 24228a3a7ebSEric Paris fsnotify_get_mark(entry); 2438f7b0ba1SAl Viro 2448f7b0ba1SAl Viro spin_unlock(&hash_lock); 2458f7b0ba1SAl Viro 246f7a998a9SAl Viro if (size) 247f7a998a9SAl Viro new = alloc_chunk(size); 248f7a998a9SAl Viro 249be29d20fSJan Kara mutex_lock(&entry->group->mark_mutex); 25028a3a7ebSEric Paris spin_lock(&entry->lock); 25143471d15SJan Kara if (chunk->dead || !(entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) { 25228a3a7ebSEric Paris spin_unlock(&entry->lock); 253be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 254f7a998a9SAl Viro if (new) 255f7a998a9SAl Viro free_chunk(new); 2568f7b0ba1SAl Viro goto out; 25774c3cbe3SAl Viro } 25874c3cbe3SAl Viro 25974c3cbe3SAl Viro owner = p->owner; 26074c3cbe3SAl Viro 26174c3cbe3SAl Viro if (!size) { 26274c3cbe3SAl Viro chunk->dead = 1; 26374c3cbe3SAl Viro spin_lock(&hash_lock); 26474c3cbe3SAl Viro list_del_init(&chunk->trees); 26574c3cbe3SAl Viro if (owner->root == chunk) 26674c3cbe3SAl Viro owner->root = NULL; 26774c3cbe3SAl Viro list_del_init(&p->list); 26874c3cbe3SAl Viro list_del_rcu(&chunk->hash); 26974c3cbe3SAl Viro spin_unlock(&hash_lock); 27028a3a7ebSEric Paris spin_unlock(&entry->lock); 271be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 272e2a29943SLino Sanfilippo fsnotify_destroy_mark(entry, audit_tree_group); 2738f7b0ba1SAl Viro goto out; 27474c3cbe3SAl Viro } 27574c3cbe3SAl Viro 27674c3cbe3SAl Viro if (!new) 27774c3cbe3SAl Viro goto Fallback; 278f7a998a9SAl Viro 279be29d20fSJan Kara if (fsnotify_add_mark_locked(&new->mark, entry->group, entry->inode, 280be29d20fSJan Kara NULL, 1)) { 2810fe33aaeSMiklos Szeredi fsnotify_put_mark(&new->mark); 28274c3cbe3SAl Viro goto Fallback; 28374c3cbe3SAl Viro } 28474c3cbe3SAl Viro 28574c3cbe3SAl Viro chunk->dead = 1; 28674c3cbe3SAl Viro spin_lock(&hash_lock); 28774c3cbe3SAl Viro list_replace_init(&chunk->trees, &new->trees); 28874c3cbe3SAl Viro if (owner->root == chunk) { 28974c3cbe3SAl Viro list_del_init(&owner->same_root); 29074c3cbe3SAl Viro owner->root = NULL; 29174c3cbe3SAl Viro } 29274c3cbe3SAl Viro 2936f5d5114SAl Viro for (i = j = 0; j <= size; i++, j++) { 29474c3cbe3SAl Viro struct audit_tree *s; 29574c3cbe3SAl Viro if (&chunk->owners[j] == p) { 29674c3cbe3SAl Viro list_del_init(&p->list); 29774c3cbe3SAl Viro i--; 29874c3cbe3SAl Viro continue; 29974c3cbe3SAl Viro } 30074c3cbe3SAl Viro s = chunk->owners[j].owner; 30174c3cbe3SAl Viro new->owners[i].owner = s; 30274c3cbe3SAl Viro new->owners[i].index = chunk->owners[j].index - j + i; 30374c3cbe3SAl Viro if (!s) /* result of earlier fallback */ 30474c3cbe3SAl Viro continue; 30574c3cbe3SAl Viro get_tree(s); 3066f5d5114SAl Viro list_replace_init(&chunk->owners[j].list, &new->owners[i].list); 30774c3cbe3SAl Viro } 30874c3cbe3SAl Viro 30974c3cbe3SAl Viro list_replace_rcu(&chunk->hash, &new->hash); 31074c3cbe3SAl Viro list_for_each_entry(owner, &new->trees, same_root) 31174c3cbe3SAl Viro owner->root = new; 31274c3cbe3SAl Viro spin_unlock(&hash_lock); 31328a3a7ebSEric Paris spin_unlock(&entry->lock); 314be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 315e2a29943SLino Sanfilippo fsnotify_destroy_mark(entry, audit_tree_group); 316b3e8692bSMiklos Szeredi fsnotify_put_mark(&new->mark); /* drop initial reference */ 3178f7b0ba1SAl Viro goto out; 31874c3cbe3SAl Viro 31974c3cbe3SAl Viro Fallback: 32074c3cbe3SAl Viro // do the best we can 32174c3cbe3SAl Viro spin_lock(&hash_lock); 32274c3cbe3SAl Viro if (owner->root == chunk) { 32374c3cbe3SAl Viro list_del_init(&owner->same_root); 32474c3cbe3SAl Viro owner->root = NULL; 32574c3cbe3SAl Viro } 32674c3cbe3SAl Viro list_del_init(&p->list); 32774c3cbe3SAl Viro p->owner = NULL; 32874c3cbe3SAl Viro put_tree(owner); 32974c3cbe3SAl Viro spin_unlock(&hash_lock); 33028a3a7ebSEric Paris spin_unlock(&entry->lock); 331be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 3328f7b0ba1SAl Viro out: 33328a3a7ebSEric Paris fsnotify_put_mark(entry); 3348f7b0ba1SAl Viro spin_lock(&hash_lock); 33574c3cbe3SAl Viro } 33674c3cbe3SAl Viro 33774c3cbe3SAl Viro static int create_chunk(struct inode *inode, struct audit_tree *tree) 33874c3cbe3SAl Viro { 339e61ce867SEric Paris struct fsnotify_mark *entry; 34074c3cbe3SAl Viro struct audit_chunk *chunk = alloc_chunk(1); 34174c3cbe3SAl Viro if (!chunk) 34274c3cbe3SAl Viro return -ENOMEM; 34374c3cbe3SAl Viro 34428a3a7ebSEric Paris entry = &chunk->mark; 3455444e298SEric Paris if (fsnotify_add_mark(entry, audit_tree_group, inode, NULL, 0)) { 3460fe33aaeSMiklos Szeredi fsnotify_put_mark(entry); 34774c3cbe3SAl Viro return -ENOSPC; 34874c3cbe3SAl Viro } 34974c3cbe3SAl Viro 35028a3a7ebSEric Paris spin_lock(&entry->lock); 35174c3cbe3SAl Viro spin_lock(&hash_lock); 35274c3cbe3SAl Viro if (tree->goner) { 35374c3cbe3SAl Viro spin_unlock(&hash_lock); 35474c3cbe3SAl Viro chunk->dead = 1; 35528a3a7ebSEric Paris spin_unlock(&entry->lock); 356e2a29943SLino Sanfilippo fsnotify_destroy_mark(entry, audit_tree_group); 35728a3a7ebSEric Paris fsnotify_put_mark(entry); 35874c3cbe3SAl Viro return 0; 35974c3cbe3SAl Viro } 36074c3cbe3SAl Viro chunk->owners[0].index = (1U << 31); 36174c3cbe3SAl Viro chunk->owners[0].owner = tree; 36274c3cbe3SAl Viro get_tree(tree); 36374c3cbe3SAl Viro list_add(&chunk->owners[0].list, &tree->chunks); 36474c3cbe3SAl Viro if (!tree->root) { 36574c3cbe3SAl Viro tree->root = chunk; 36674c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees); 36774c3cbe3SAl Viro } 36874c3cbe3SAl Viro insert_hash(chunk); 36974c3cbe3SAl Viro spin_unlock(&hash_lock); 37028a3a7ebSEric Paris spin_unlock(&entry->lock); 371b3e8692bSMiklos Szeredi fsnotify_put_mark(entry); /* drop initial reference */ 37274c3cbe3SAl Viro return 0; 37374c3cbe3SAl Viro } 37474c3cbe3SAl Viro 37574c3cbe3SAl Viro /* the first tagged inode becomes root of tree */ 37674c3cbe3SAl Viro static int tag_chunk(struct inode *inode, struct audit_tree *tree) 37774c3cbe3SAl Viro { 378e61ce867SEric Paris struct fsnotify_mark *old_entry, *chunk_entry; 37974c3cbe3SAl Viro struct audit_tree *owner; 38074c3cbe3SAl Viro struct audit_chunk *chunk, *old; 38174c3cbe3SAl Viro struct node *p; 38274c3cbe3SAl Viro int n; 38374c3cbe3SAl Viro 3845444e298SEric Paris old_entry = fsnotify_find_inode_mark(audit_tree_group, inode); 38528a3a7ebSEric Paris if (!old_entry) 38674c3cbe3SAl Viro return create_chunk(inode, tree); 38774c3cbe3SAl Viro 38828a3a7ebSEric Paris old = container_of(old_entry, struct audit_chunk, mark); 38974c3cbe3SAl Viro 39074c3cbe3SAl Viro /* are we already there? */ 39174c3cbe3SAl Viro spin_lock(&hash_lock); 39274c3cbe3SAl Viro for (n = 0; n < old->count; n++) { 39374c3cbe3SAl Viro if (old->owners[n].owner == tree) { 39474c3cbe3SAl Viro spin_unlock(&hash_lock); 39528a3a7ebSEric Paris fsnotify_put_mark(old_entry); 39674c3cbe3SAl Viro return 0; 39774c3cbe3SAl Viro } 39874c3cbe3SAl Viro } 39974c3cbe3SAl Viro spin_unlock(&hash_lock); 40074c3cbe3SAl Viro 40174c3cbe3SAl Viro chunk = alloc_chunk(old->count + 1); 402b4c30aadSAl Viro if (!chunk) { 40328a3a7ebSEric Paris fsnotify_put_mark(old_entry); 40474c3cbe3SAl Viro return -ENOMEM; 405b4c30aadSAl Viro } 40674c3cbe3SAl Viro 40728a3a7ebSEric Paris chunk_entry = &chunk->mark; 40828a3a7ebSEric Paris 409be29d20fSJan Kara mutex_lock(&old_entry->group->mark_mutex); 41028a3a7ebSEric Paris spin_lock(&old_entry->lock); 41143471d15SJan Kara if (!(old_entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) { 41228a3a7ebSEric Paris /* old_entry is being shot, lets just lie */ 41328a3a7ebSEric Paris spin_unlock(&old_entry->lock); 414be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 41528a3a7ebSEric Paris fsnotify_put_mark(old_entry); 41674c3cbe3SAl Viro free_chunk(chunk); 41728a3a7ebSEric Paris return -ENOENT; 41828a3a7ebSEric Paris } 41928a3a7ebSEric Paris 420be29d20fSJan Kara if (fsnotify_add_mark_locked(chunk_entry, old_entry->group, 421be29d20fSJan Kara old_entry->inode, NULL, 1)) { 42228a3a7ebSEric Paris spin_unlock(&old_entry->lock); 423be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 4240fe33aaeSMiklos Szeredi fsnotify_put_mark(chunk_entry); 42528a3a7ebSEric Paris fsnotify_put_mark(old_entry); 42674c3cbe3SAl Viro return -ENOSPC; 42774c3cbe3SAl Viro } 42828a3a7ebSEric Paris 42928a3a7ebSEric Paris /* even though we hold old_entry->lock, this is safe since chunk_entry->lock could NEVER have been grabbed before */ 43028a3a7ebSEric Paris spin_lock(&chunk_entry->lock); 43174c3cbe3SAl Viro spin_lock(&hash_lock); 43228a3a7ebSEric Paris 43328a3a7ebSEric Paris /* we now hold old_entry->lock, chunk_entry->lock, and hash_lock */ 43474c3cbe3SAl Viro if (tree->goner) { 43574c3cbe3SAl Viro spin_unlock(&hash_lock); 43674c3cbe3SAl Viro chunk->dead = 1; 43728a3a7ebSEric Paris spin_unlock(&chunk_entry->lock); 43828a3a7ebSEric Paris spin_unlock(&old_entry->lock); 439be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 44028a3a7ebSEric Paris 441e2a29943SLino Sanfilippo fsnotify_destroy_mark(chunk_entry, audit_tree_group); 44228a3a7ebSEric Paris 44328a3a7ebSEric Paris fsnotify_put_mark(chunk_entry); 44428a3a7ebSEric Paris fsnotify_put_mark(old_entry); 44574c3cbe3SAl Viro return 0; 44674c3cbe3SAl Viro } 44774c3cbe3SAl Viro list_replace_init(&old->trees, &chunk->trees); 44874c3cbe3SAl Viro for (n = 0, p = chunk->owners; n < old->count; n++, p++) { 44974c3cbe3SAl Viro struct audit_tree *s = old->owners[n].owner; 45074c3cbe3SAl Viro p->owner = s; 45174c3cbe3SAl Viro p->index = old->owners[n].index; 45274c3cbe3SAl Viro if (!s) /* result of fallback in untag */ 45374c3cbe3SAl Viro continue; 45474c3cbe3SAl Viro get_tree(s); 45574c3cbe3SAl Viro list_replace_init(&old->owners[n].list, &p->list); 45674c3cbe3SAl Viro } 45774c3cbe3SAl Viro p->index = (chunk->count - 1) | (1U<<31); 45874c3cbe3SAl Viro p->owner = tree; 45974c3cbe3SAl Viro get_tree(tree); 46074c3cbe3SAl Viro list_add(&p->list, &tree->chunks); 46174c3cbe3SAl Viro list_replace_rcu(&old->hash, &chunk->hash); 46274c3cbe3SAl Viro list_for_each_entry(owner, &chunk->trees, same_root) 46374c3cbe3SAl Viro owner->root = chunk; 46474c3cbe3SAl Viro old->dead = 1; 46574c3cbe3SAl Viro if (!tree->root) { 46674c3cbe3SAl Viro tree->root = chunk; 46774c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees); 46874c3cbe3SAl Viro } 46974c3cbe3SAl Viro spin_unlock(&hash_lock); 47028a3a7ebSEric Paris spin_unlock(&chunk_entry->lock); 47128a3a7ebSEric Paris spin_unlock(&old_entry->lock); 472be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 473e2a29943SLino Sanfilippo fsnotify_destroy_mark(old_entry, audit_tree_group); 474b3e8692bSMiklos Szeredi fsnotify_put_mark(chunk_entry); /* drop initial reference */ 47528a3a7ebSEric Paris fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ 47674c3cbe3SAl Viro return 0; 47774c3cbe3SAl Viro } 47874c3cbe3SAl Viro 4792991dd2bSRichard Guy Briggs static void audit_tree_log_remove_rule(struct audit_krule *rule) 48074c3cbe3SAl Viro { 48174c3cbe3SAl Viro struct audit_buffer *ab; 48274c3cbe3SAl Viro 48374c3cbe3SAl Viro ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); 4840644ec0cSKees Cook if (unlikely(!ab)) 4850644ec0cSKees Cook return; 486c1e8f06dSSteve Grubb audit_log_format(ab, "op=remove_rule"); 4879d960985SEric Paris audit_log_format(ab, " dir="); 48874c3cbe3SAl Viro audit_log_untrustedstring(ab, rule->tree->pathname); 4899d960985SEric Paris audit_log_key(ab, rule->filterkey); 49074c3cbe3SAl Viro audit_log_format(ab, " list=%d res=1", rule->listnr); 49174c3cbe3SAl Viro audit_log_end(ab); 4920644ec0cSKees Cook } 4930644ec0cSKees Cook 4940644ec0cSKees Cook static void kill_rules(struct audit_tree *tree) 4950644ec0cSKees Cook { 4960644ec0cSKees Cook struct audit_krule *rule, *next; 4970644ec0cSKees Cook struct audit_entry *entry; 4980644ec0cSKees Cook 4990644ec0cSKees Cook list_for_each_entry_safe(rule, next, &tree->rules, rlist) { 5000644ec0cSKees Cook entry = container_of(rule, struct audit_entry, rule); 5010644ec0cSKees Cook 5020644ec0cSKees Cook list_del_init(&rule->rlist); 5030644ec0cSKees Cook if (rule->tree) { 5040644ec0cSKees Cook /* not a half-baked one */ 5052991dd2bSRichard Guy Briggs audit_tree_log_remove_rule(rule); 50634d99af5SRichard Guy Briggs if (entry->rule.exe) 50734d99af5SRichard Guy Briggs audit_remove_mark(entry->rule.exe); 50874c3cbe3SAl Viro rule->tree = NULL; 50974c3cbe3SAl Viro list_del_rcu(&entry->list); 510e45aa212SAl Viro list_del(&entry->rule.list); 51174c3cbe3SAl Viro call_rcu(&entry->rcu, audit_free_rule_rcu); 51274c3cbe3SAl Viro } 51374c3cbe3SAl Viro } 51474c3cbe3SAl Viro } 51574c3cbe3SAl Viro 51674c3cbe3SAl Viro /* 51774c3cbe3SAl Viro * finish killing struct audit_tree 51874c3cbe3SAl Viro */ 51974c3cbe3SAl Viro static void prune_one(struct audit_tree *victim) 52074c3cbe3SAl Viro { 52174c3cbe3SAl Viro spin_lock(&hash_lock); 52274c3cbe3SAl Viro while (!list_empty(&victim->chunks)) { 52374c3cbe3SAl Viro struct node *p; 52474c3cbe3SAl Viro 52574c3cbe3SAl Viro p = list_entry(victim->chunks.next, struct node, list); 52674c3cbe3SAl Viro 5278f7b0ba1SAl Viro untag_chunk(p); 52874c3cbe3SAl Viro } 52974c3cbe3SAl Viro spin_unlock(&hash_lock); 53074c3cbe3SAl Viro put_tree(victim); 53174c3cbe3SAl Viro } 53274c3cbe3SAl Viro 53374c3cbe3SAl Viro /* trim the uncommitted chunks from tree */ 53474c3cbe3SAl Viro 53574c3cbe3SAl Viro static void trim_marked(struct audit_tree *tree) 53674c3cbe3SAl Viro { 53774c3cbe3SAl Viro struct list_head *p, *q; 53874c3cbe3SAl Viro spin_lock(&hash_lock); 53974c3cbe3SAl Viro if (tree->goner) { 54074c3cbe3SAl Viro spin_unlock(&hash_lock); 54174c3cbe3SAl Viro return; 54274c3cbe3SAl Viro } 54374c3cbe3SAl Viro /* reorder */ 54474c3cbe3SAl Viro for (p = tree->chunks.next; p != &tree->chunks; p = q) { 54574c3cbe3SAl Viro struct node *node = list_entry(p, struct node, list); 54674c3cbe3SAl Viro q = p->next; 54774c3cbe3SAl Viro if (node->index & (1U<<31)) { 54874c3cbe3SAl Viro list_del_init(p); 54974c3cbe3SAl Viro list_add(p, &tree->chunks); 55074c3cbe3SAl Viro } 55174c3cbe3SAl Viro } 55274c3cbe3SAl Viro 55374c3cbe3SAl Viro while (!list_empty(&tree->chunks)) { 55474c3cbe3SAl Viro struct node *node; 55574c3cbe3SAl Viro 55674c3cbe3SAl Viro node = list_entry(tree->chunks.next, struct node, list); 55774c3cbe3SAl Viro 55874c3cbe3SAl Viro /* have we run out of marked? */ 55974c3cbe3SAl Viro if (!(node->index & (1U<<31))) 56074c3cbe3SAl Viro break; 56174c3cbe3SAl Viro 5628f7b0ba1SAl Viro untag_chunk(node); 56374c3cbe3SAl Viro } 56474c3cbe3SAl Viro if (!tree->root && !tree->goner) { 56574c3cbe3SAl Viro tree->goner = 1; 56674c3cbe3SAl Viro spin_unlock(&hash_lock); 56774c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 56874c3cbe3SAl Viro kill_rules(tree); 56974c3cbe3SAl Viro list_del_init(&tree->list); 57074c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 57174c3cbe3SAl Viro prune_one(tree); 57274c3cbe3SAl Viro } else { 57374c3cbe3SAl Viro spin_unlock(&hash_lock); 57474c3cbe3SAl Viro } 57574c3cbe3SAl Viro } 57674c3cbe3SAl Viro 577916d7576SAl Viro static void audit_schedule_prune(void); 578916d7576SAl Viro 57974c3cbe3SAl Viro /* called with audit_filter_mutex */ 58074c3cbe3SAl Viro int audit_remove_tree_rule(struct audit_krule *rule) 58174c3cbe3SAl Viro { 58274c3cbe3SAl Viro struct audit_tree *tree; 58374c3cbe3SAl Viro tree = rule->tree; 58474c3cbe3SAl Viro if (tree) { 58574c3cbe3SAl Viro spin_lock(&hash_lock); 58674c3cbe3SAl Viro list_del_init(&rule->rlist); 58774c3cbe3SAl Viro if (list_empty(&tree->rules) && !tree->goner) { 58874c3cbe3SAl Viro tree->root = NULL; 58974c3cbe3SAl Viro list_del_init(&tree->same_root); 59074c3cbe3SAl Viro tree->goner = 1; 59174c3cbe3SAl Viro list_move(&tree->list, &prune_list); 59274c3cbe3SAl Viro rule->tree = NULL; 59374c3cbe3SAl Viro spin_unlock(&hash_lock); 59474c3cbe3SAl Viro audit_schedule_prune(); 59574c3cbe3SAl Viro return 1; 59674c3cbe3SAl Viro } 59774c3cbe3SAl Viro rule->tree = NULL; 59874c3cbe3SAl Viro spin_unlock(&hash_lock); 59974c3cbe3SAl Viro return 1; 60074c3cbe3SAl Viro } 60174c3cbe3SAl Viro return 0; 60274c3cbe3SAl Viro } 60374c3cbe3SAl Viro 6041f707137SAl Viro static int compare_root(struct vfsmount *mnt, void *arg) 6051f707137SAl Viro { 606f410ff65SJan Kara return inode_to_key(d_backing_inode(mnt->mnt_root)) == 607f410ff65SJan Kara (unsigned long)arg; 6081f707137SAl Viro } 6091f707137SAl Viro 61074c3cbe3SAl Viro void audit_trim_trees(void) 61174c3cbe3SAl Viro { 61274c3cbe3SAl Viro struct list_head cursor; 61374c3cbe3SAl Viro 61474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 61574c3cbe3SAl Viro list_add(&cursor, &tree_list); 61674c3cbe3SAl Viro while (cursor.next != &tree_list) { 61774c3cbe3SAl Viro struct audit_tree *tree; 61898bc993fSAl Viro struct path path; 61974c3cbe3SAl Viro struct vfsmount *root_mnt; 62074c3cbe3SAl Viro struct node *node; 62174c3cbe3SAl Viro int err; 62274c3cbe3SAl Viro 62374c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 62474c3cbe3SAl Viro get_tree(tree); 62574c3cbe3SAl Viro list_del(&cursor); 62674c3cbe3SAl Viro list_add(&cursor, &tree->list); 62774c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 62874c3cbe3SAl Viro 62998bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 63074c3cbe3SAl Viro if (err) 63174c3cbe3SAl Viro goto skip_it; 63274c3cbe3SAl Viro 633589ff870SAl Viro root_mnt = collect_mounts(&path); 63498bc993fSAl Viro path_put(&path); 635be34d1a3SDavid Howells if (IS_ERR(root_mnt)) 63674c3cbe3SAl Viro goto skip_it; 63774c3cbe3SAl Viro 63874c3cbe3SAl Viro spin_lock(&hash_lock); 63974c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) { 64028a3a7ebSEric Paris struct audit_chunk *chunk = find_chunk(node); 64125985edcSLucas De Marchi /* this could be NULL if the watch is dying else where... */ 64274c3cbe3SAl Viro node->index |= 1U<<31; 643f410ff65SJan Kara if (iterate_mounts(compare_root, 644f410ff65SJan Kara (void *)chunk_to_key(chunk), 645f410ff65SJan Kara root_mnt)) 64674c3cbe3SAl Viro node->index &= ~(1U<<31); 64774c3cbe3SAl Viro } 64874c3cbe3SAl Viro spin_unlock(&hash_lock); 64974c3cbe3SAl Viro trim_marked(tree); 65074c3cbe3SAl Viro drop_collected_mounts(root_mnt); 65174c3cbe3SAl Viro skip_it: 65212b2f117SChen Gang put_tree(tree); 65374c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 65474c3cbe3SAl Viro } 65574c3cbe3SAl Viro list_del(&cursor); 65674c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 65774c3cbe3SAl Viro } 65874c3cbe3SAl Viro 65974c3cbe3SAl Viro int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) 66074c3cbe3SAl Viro { 66174c3cbe3SAl Viro 66274c3cbe3SAl Viro if (pathname[0] != '/' || 66374c3cbe3SAl Viro rule->listnr != AUDIT_FILTER_EXIT || 6645af75d8dSAl Viro op != Audit_equal || 66574c3cbe3SAl Viro rule->inode_f || rule->watch || rule->tree) 66674c3cbe3SAl Viro return -EINVAL; 66774c3cbe3SAl Viro rule->tree = alloc_tree(pathname); 66874c3cbe3SAl Viro if (!rule->tree) 66974c3cbe3SAl Viro return -ENOMEM; 67074c3cbe3SAl Viro return 0; 67174c3cbe3SAl Viro } 67274c3cbe3SAl Viro 67374c3cbe3SAl Viro void audit_put_tree(struct audit_tree *tree) 67474c3cbe3SAl Viro { 67574c3cbe3SAl Viro put_tree(tree); 67674c3cbe3SAl Viro } 67774c3cbe3SAl Viro 6781f707137SAl Viro static int tag_mount(struct vfsmount *mnt, void *arg) 6791f707137SAl Viro { 6803b362157SDavid Howells return tag_chunk(d_backing_inode(mnt->mnt_root), arg); 6811f707137SAl Viro } 6821f707137SAl Viro 683f1aaf262SImre Palik /* 684f1aaf262SImre Palik * That gets run when evict_chunk() ends up needing to kill audit_tree. 685f1aaf262SImre Palik * Runs from a separate thread. 686f1aaf262SImre Palik */ 687f1aaf262SImre Palik static int prune_tree_thread(void *unused) 688f1aaf262SImre Palik { 689f1aaf262SImre Palik for (;;) { 6900bf676d1SJiri Slaby if (list_empty(&prune_list)) { 691f1aaf262SImre Palik set_current_state(TASK_INTERRUPTIBLE); 692f1aaf262SImre Palik schedule(); 6930bf676d1SJiri Slaby } 694f1aaf262SImre Palik 695f1aaf262SImre Palik mutex_lock(&audit_cmd_mutex); 696f1aaf262SImre Palik mutex_lock(&audit_filter_mutex); 697f1aaf262SImre Palik 698f1aaf262SImre Palik while (!list_empty(&prune_list)) { 699f1aaf262SImre Palik struct audit_tree *victim; 700f1aaf262SImre Palik 701f1aaf262SImre Palik victim = list_entry(prune_list.next, 702f1aaf262SImre Palik struct audit_tree, list); 703f1aaf262SImre Palik list_del_init(&victim->list); 704f1aaf262SImre Palik 705f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex); 706f1aaf262SImre Palik 707f1aaf262SImre Palik prune_one(victim); 708f1aaf262SImre Palik 709f1aaf262SImre Palik mutex_lock(&audit_filter_mutex); 710f1aaf262SImre Palik } 711f1aaf262SImre Palik 712f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex); 713f1aaf262SImre Palik mutex_unlock(&audit_cmd_mutex); 714f1aaf262SImre Palik } 715f1aaf262SImre Palik return 0; 716f1aaf262SImre Palik } 717f1aaf262SImre Palik 718f1aaf262SImre Palik static int audit_launch_prune(void) 719f1aaf262SImre Palik { 720f1aaf262SImre Palik if (prune_thread) 721f1aaf262SImre Palik return 0; 7220bf676d1SJiri Slaby prune_thread = kthread_run(prune_tree_thread, NULL, 723f1aaf262SImre Palik "audit_prune_tree"); 724f1aaf262SImre Palik if (IS_ERR(prune_thread)) { 725f1aaf262SImre Palik pr_err("cannot start thread audit_prune_tree"); 726f1aaf262SImre Palik prune_thread = NULL; 727f1aaf262SImre Palik return -ENOMEM; 728f1aaf262SImre Palik } 7290bf676d1SJiri Slaby return 0; 730f1aaf262SImre Palik } 731f1aaf262SImre Palik 73274c3cbe3SAl Viro /* called with audit_filter_mutex */ 73374c3cbe3SAl Viro int audit_add_tree_rule(struct audit_krule *rule) 73474c3cbe3SAl Viro { 73574c3cbe3SAl Viro struct audit_tree *seed = rule->tree, *tree; 73698bc993fSAl Viro struct path path; 7371f707137SAl Viro struct vfsmount *mnt; 73874c3cbe3SAl Viro int err; 73974c3cbe3SAl Viro 740736f3203SChen Gang rule->tree = NULL; 74174c3cbe3SAl Viro list_for_each_entry(tree, &tree_list, list) { 74274c3cbe3SAl Viro if (!strcmp(seed->pathname, tree->pathname)) { 74374c3cbe3SAl Viro put_tree(seed); 74474c3cbe3SAl Viro rule->tree = tree; 74574c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 74674c3cbe3SAl Viro return 0; 74774c3cbe3SAl Viro } 74874c3cbe3SAl Viro } 74974c3cbe3SAl Viro tree = seed; 75074c3cbe3SAl Viro list_add(&tree->list, &tree_list); 75174c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 75274c3cbe3SAl Viro /* do not set rule->tree yet */ 75374c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 75474c3cbe3SAl Viro 755f1aaf262SImre Palik if (unlikely(!prune_thread)) { 756f1aaf262SImre Palik err = audit_launch_prune(); 757f1aaf262SImre Palik if (err) 758f1aaf262SImre Palik goto Err; 759f1aaf262SImre Palik } 760f1aaf262SImre Palik 76198bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 76274c3cbe3SAl Viro if (err) 76374c3cbe3SAl Viro goto Err; 764589ff870SAl Viro mnt = collect_mounts(&path); 76598bc993fSAl Viro path_put(&path); 766be34d1a3SDavid Howells if (IS_ERR(mnt)) { 767be34d1a3SDavid Howells err = PTR_ERR(mnt); 76874c3cbe3SAl Viro goto Err; 76974c3cbe3SAl Viro } 77074c3cbe3SAl Viro 77174c3cbe3SAl Viro get_tree(tree); 7721f707137SAl Viro err = iterate_mounts(tag_mount, tree, mnt); 77374c3cbe3SAl Viro drop_collected_mounts(mnt); 77474c3cbe3SAl Viro 77574c3cbe3SAl Viro if (!err) { 77674c3cbe3SAl Viro struct node *node; 77774c3cbe3SAl Viro spin_lock(&hash_lock); 77874c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 77974c3cbe3SAl Viro node->index &= ~(1U<<31); 78074c3cbe3SAl Viro spin_unlock(&hash_lock); 78174c3cbe3SAl Viro } else { 78274c3cbe3SAl Viro trim_marked(tree); 78374c3cbe3SAl Viro goto Err; 78474c3cbe3SAl Viro } 78574c3cbe3SAl Viro 78674c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 78774c3cbe3SAl Viro if (list_empty(&rule->rlist)) { 78874c3cbe3SAl Viro put_tree(tree); 78974c3cbe3SAl Viro return -ENOENT; 79074c3cbe3SAl Viro } 79174c3cbe3SAl Viro rule->tree = tree; 79274c3cbe3SAl Viro put_tree(tree); 79374c3cbe3SAl Viro 79474c3cbe3SAl Viro return 0; 79574c3cbe3SAl Viro Err: 79674c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 79774c3cbe3SAl Viro list_del_init(&tree->list); 79874c3cbe3SAl Viro list_del_init(&tree->rules); 79974c3cbe3SAl Viro put_tree(tree); 80074c3cbe3SAl Viro return err; 80174c3cbe3SAl Viro } 80274c3cbe3SAl Viro 80374c3cbe3SAl Viro int audit_tag_tree(char *old, char *new) 80474c3cbe3SAl Viro { 80574c3cbe3SAl Viro struct list_head cursor, barrier; 80674c3cbe3SAl Viro int failed = 0; 8072096f759SAl Viro struct path path1, path2; 80874c3cbe3SAl Viro struct vfsmount *tagged; 80974c3cbe3SAl Viro int err; 81074c3cbe3SAl Viro 8112096f759SAl Viro err = kern_path(new, 0, &path2); 81274c3cbe3SAl Viro if (err) 81374c3cbe3SAl Viro return err; 8142096f759SAl Viro tagged = collect_mounts(&path2); 8152096f759SAl Viro path_put(&path2); 816be34d1a3SDavid Howells if (IS_ERR(tagged)) 817be34d1a3SDavid Howells return PTR_ERR(tagged); 81874c3cbe3SAl Viro 8192096f759SAl Viro err = kern_path(old, 0, &path1); 82074c3cbe3SAl Viro if (err) { 82174c3cbe3SAl Viro drop_collected_mounts(tagged); 82274c3cbe3SAl Viro return err; 82374c3cbe3SAl Viro } 82474c3cbe3SAl Viro 82574c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 82674c3cbe3SAl Viro list_add(&barrier, &tree_list); 82774c3cbe3SAl Viro list_add(&cursor, &barrier); 82874c3cbe3SAl Viro 82974c3cbe3SAl Viro while (cursor.next != &tree_list) { 83074c3cbe3SAl Viro struct audit_tree *tree; 8312096f759SAl Viro int good_one = 0; 83274c3cbe3SAl Viro 83374c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 83474c3cbe3SAl Viro get_tree(tree); 83574c3cbe3SAl Viro list_del(&cursor); 83674c3cbe3SAl Viro list_add(&cursor, &tree->list); 83774c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 83874c3cbe3SAl Viro 8392096f759SAl Viro err = kern_path(tree->pathname, 0, &path2); 8402096f759SAl Viro if (!err) { 8412096f759SAl Viro good_one = path_is_under(&path1, &path2); 8422096f759SAl Viro path_put(&path2); 84374c3cbe3SAl Viro } 84474c3cbe3SAl Viro 8452096f759SAl Viro if (!good_one) { 84674c3cbe3SAl Viro put_tree(tree); 84774c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 84874c3cbe3SAl Viro continue; 84974c3cbe3SAl Viro } 85074c3cbe3SAl Viro 8511f707137SAl Viro failed = iterate_mounts(tag_mount, tree, tagged); 85274c3cbe3SAl Viro if (failed) { 85374c3cbe3SAl Viro put_tree(tree); 85474c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 85574c3cbe3SAl Viro break; 85674c3cbe3SAl Viro } 85774c3cbe3SAl Viro 85874c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 85974c3cbe3SAl Viro spin_lock(&hash_lock); 86074c3cbe3SAl Viro if (!tree->goner) { 86174c3cbe3SAl Viro list_del(&tree->list); 86274c3cbe3SAl Viro list_add(&tree->list, &tree_list); 86374c3cbe3SAl Viro } 86474c3cbe3SAl Viro spin_unlock(&hash_lock); 86574c3cbe3SAl Viro put_tree(tree); 86674c3cbe3SAl Viro } 86774c3cbe3SAl Viro 86874c3cbe3SAl Viro while (barrier.prev != &tree_list) { 86974c3cbe3SAl Viro struct audit_tree *tree; 87074c3cbe3SAl Viro 87174c3cbe3SAl Viro tree = container_of(barrier.prev, struct audit_tree, list); 87274c3cbe3SAl Viro get_tree(tree); 87374c3cbe3SAl Viro list_del(&tree->list); 87474c3cbe3SAl Viro list_add(&tree->list, &barrier); 87574c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 87674c3cbe3SAl Viro 87774c3cbe3SAl Viro if (!failed) { 87874c3cbe3SAl Viro struct node *node; 87974c3cbe3SAl Viro spin_lock(&hash_lock); 88074c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 88174c3cbe3SAl Viro node->index &= ~(1U<<31); 88274c3cbe3SAl Viro spin_unlock(&hash_lock); 88374c3cbe3SAl Viro } else { 88474c3cbe3SAl Viro trim_marked(tree); 88574c3cbe3SAl Viro } 88674c3cbe3SAl Viro 88774c3cbe3SAl Viro put_tree(tree); 88874c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 88974c3cbe3SAl Viro } 89074c3cbe3SAl Viro list_del(&barrier); 89174c3cbe3SAl Viro list_del(&cursor); 89274c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 8932096f759SAl Viro path_put(&path1); 89474c3cbe3SAl Viro drop_collected_mounts(tagged); 89574c3cbe3SAl Viro return failed; 89674c3cbe3SAl Viro } 89774c3cbe3SAl Viro 898916d7576SAl Viro 899916d7576SAl Viro static void audit_schedule_prune(void) 900916d7576SAl Viro { 901f1aaf262SImre Palik wake_up_process(prune_thread); 902916d7576SAl Viro } 903916d7576SAl Viro 904916d7576SAl Viro /* 905916d7576SAl Viro * ... and that one is done if evict_chunk() decides to delay until the end 906916d7576SAl Viro * of syscall. Runs synchronously. 907916d7576SAl Viro */ 908916d7576SAl Viro void audit_kill_trees(struct list_head *list) 909916d7576SAl Viro { 910916d7576SAl Viro mutex_lock(&audit_cmd_mutex); 911916d7576SAl Viro mutex_lock(&audit_filter_mutex); 912916d7576SAl Viro 913916d7576SAl Viro while (!list_empty(list)) { 914916d7576SAl Viro struct audit_tree *victim; 915916d7576SAl Viro 916916d7576SAl Viro victim = list_entry(list->next, struct audit_tree, list); 917916d7576SAl Viro kill_rules(victim); 918916d7576SAl Viro list_del_init(&victim->list); 919916d7576SAl Viro 920916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 921916d7576SAl Viro 922916d7576SAl Viro prune_one(victim); 923916d7576SAl Viro 924916d7576SAl Viro mutex_lock(&audit_filter_mutex); 925916d7576SAl Viro } 926916d7576SAl Viro 927916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 928916d7576SAl Viro mutex_unlock(&audit_cmd_mutex); 92974c3cbe3SAl Viro } 93074c3cbe3SAl Viro 93174c3cbe3SAl Viro /* 93274c3cbe3SAl Viro * Here comes the stuff asynchronous to auditctl operations 93374c3cbe3SAl Viro */ 93474c3cbe3SAl Viro 93574c3cbe3SAl Viro static void evict_chunk(struct audit_chunk *chunk) 93674c3cbe3SAl Viro { 93774c3cbe3SAl Viro struct audit_tree *owner; 938916d7576SAl Viro struct list_head *postponed = audit_killed_trees(); 939916d7576SAl Viro int need_prune = 0; 94074c3cbe3SAl Viro int n; 94174c3cbe3SAl Viro 94274c3cbe3SAl Viro if (chunk->dead) 94374c3cbe3SAl Viro return; 94474c3cbe3SAl Viro 94574c3cbe3SAl Viro chunk->dead = 1; 94674c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 94774c3cbe3SAl Viro spin_lock(&hash_lock); 94874c3cbe3SAl Viro while (!list_empty(&chunk->trees)) { 94974c3cbe3SAl Viro owner = list_entry(chunk->trees.next, 95074c3cbe3SAl Viro struct audit_tree, same_root); 95174c3cbe3SAl Viro owner->goner = 1; 95274c3cbe3SAl Viro owner->root = NULL; 95374c3cbe3SAl Viro list_del_init(&owner->same_root); 95474c3cbe3SAl Viro spin_unlock(&hash_lock); 955916d7576SAl Viro if (!postponed) { 95674c3cbe3SAl Viro kill_rules(owner); 95774c3cbe3SAl Viro list_move(&owner->list, &prune_list); 958916d7576SAl Viro need_prune = 1; 959916d7576SAl Viro } else { 960916d7576SAl Viro list_move(&owner->list, postponed); 961916d7576SAl Viro } 96274c3cbe3SAl Viro spin_lock(&hash_lock); 96374c3cbe3SAl Viro } 96474c3cbe3SAl Viro list_del_rcu(&chunk->hash); 96574c3cbe3SAl Viro for (n = 0; n < chunk->count; n++) 96674c3cbe3SAl Viro list_del_init(&chunk->owners[n].list); 96774c3cbe3SAl Viro spin_unlock(&hash_lock); 968f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex); 969916d7576SAl Viro if (need_prune) 970916d7576SAl Viro audit_schedule_prune(); 97174c3cbe3SAl Viro } 97274c3cbe3SAl Viro 9733a9b16b4SEric Paris static int audit_tree_handle_event(struct fsnotify_group *group, 9747053aee2SJan Kara struct inode *to_tell, 975ce8f76fbSEric Paris struct fsnotify_mark *inode_mark, 9767053aee2SJan Kara struct fsnotify_mark *vfsmount_mark, 9773cd5eca8SAl Viro u32 mask, const void *data, int data_type, 97845a22f4cSJan Kara const unsigned char *file_name, u32 cookie) 97974c3cbe3SAl Viro { 98083c4c4b0SJan Kara return 0; 98128a3a7ebSEric Paris } 98274c3cbe3SAl Viro 983e61ce867SEric Paris static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group) 98428a3a7ebSEric Paris { 98528a3a7ebSEric Paris struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark); 98628a3a7ebSEric Paris 98774c3cbe3SAl Viro evict_chunk(chunk); 988b3e8692bSMiklos Szeredi 989b3e8692bSMiklos Szeredi /* 990b3e8692bSMiklos Szeredi * We are guaranteed to have at least one reference to the mark from 991b3e8692bSMiklos Szeredi * either the inode or the caller of fsnotify_destroy_mark(). 992b3e8692bSMiklos Szeredi */ 993b3e8692bSMiklos Szeredi BUG_ON(atomic_read(&entry->refcnt) < 1); 99474c3cbe3SAl Viro } 99574c3cbe3SAl Viro 99628a3a7ebSEric Paris static const struct fsnotify_ops audit_tree_ops = { 99728a3a7ebSEric Paris .handle_event = audit_tree_handle_event, 99828a3a7ebSEric Paris .freeing_mark = audit_tree_freeing_mark, 99974c3cbe3SAl Viro }; 100074c3cbe3SAl Viro 100174c3cbe3SAl Viro static int __init audit_tree_init(void) 100274c3cbe3SAl Viro { 100374c3cbe3SAl Viro int i; 100474c3cbe3SAl Viro 10050d2e2a1dSEric Paris audit_tree_group = fsnotify_alloc_group(&audit_tree_ops); 100628a3a7ebSEric Paris if (IS_ERR(audit_tree_group)) 100728a3a7ebSEric Paris audit_panic("cannot initialize fsnotify group for rectree watches"); 100874c3cbe3SAl Viro 100974c3cbe3SAl Viro for (i = 0; i < HASH_SIZE; i++) 101074c3cbe3SAl Viro INIT_LIST_HEAD(&chunk_hash_heads[i]); 101174c3cbe3SAl Viro 101274c3cbe3SAl Viro return 0; 101374c3cbe3SAl Viro } 101474c3cbe3SAl Viro __initcall(audit_tree_init); 1015