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 { 1786b3f05d2SJan Kara /* 1796b3f05d2SJan Kara * We have a reference to the mark so it should be attached to a 1806b3f05d2SJan Kara * connector. 1816b3f05d2SJan Kara */ 1826b3f05d2SJan Kara if (WARN_ON_ONCE(!chunk->mark.connector)) 1836b3f05d2SJan Kara return 0; 1846b3f05d2SJan Kara return (unsigned long)chunk->mark.connector->inode; 185f410ff65SJan Kara } 186f410ff65SJan Kara 187f410ff65SJan Kara static inline struct list_head *chunk_hash(unsigned long key) 188f410ff65SJan Kara { 189f410ff65SJan Kara unsigned long n = key / L1_CACHE_BYTES; 19074c3cbe3SAl Viro return chunk_hash_heads + n % HASH_SIZE; 19174c3cbe3SAl Viro } 19274c3cbe3SAl Viro 19328a3a7ebSEric Paris /* hash_lock & entry->lock is held by caller */ 19474c3cbe3SAl Viro static void insert_hash(struct audit_chunk *chunk) 19574c3cbe3SAl Viro { 1966b3f05d2SJan Kara unsigned long key = chunk_to_key(chunk); 19728a3a7ebSEric Paris struct list_head *list; 19828a3a7ebSEric Paris 19943471d15SJan Kara if (!(chunk->mark.flags & FSNOTIFY_MARK_FLAG_ATTACHED)) 20028a3a7ebSEric Paris return; 201f410ff65SJan Kara list = chunk_hash(key); 20274c3cbe3SAl Viro list_add_rcu(&chunk->hash, list); 20374c3cbe3SAl Viro } 20474c3cbe3SAl Viro 20574c3cbe3SAl Viro /* called under rcu_read_lock */ 20674c3cbe3SAl Viro struct audit_chunk *audit_tree_lookup(const struct inode *inode) 20774c3cbe3SAl Viro { 208f410ff65SJan Kara unsigned long key = inode_to_key(inode); 209f410ff65SJan Kara struct list_head *list = chunk_hash(key); 2106793a051SPaul E. McKenney struct audit_chunk *p; 21174c3cbe3SAl Viro 2126793a051SPaul E. McKenney list_for_each_entry_rcu(p, list, hash) { 213f410ff65SJan Kara if (chunk_to_key(p) == key) { 2148f7b0ba1SAl Viro atomic_long_inc(&p->refs); 21574c3cbe3SAl Viro return p; 21674c3cbe3SAl Viro } 21774c3cbe3SAl Viro } 21874c3cbe3SAl Viro return NULL; 21974c3cbe3SAl Viro } 22074c3cbe3SAl Viro 2216f1b5d7aSYaowei Bai bool audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree) 22274c3cbe3SAl Viro { 22374c3cbe3SAl Viro int n; 22474c3cbe3SAl Viro for (n = 0; n < chunk->count; n++) 22574c3cbe3SAl Viro if (chunk->owners[n].owner == tree) 2266f1b5d7aSYaowei Bai return true; 2276f1b5d7aSYaowei Bai return false; 22874c3cbe3SAl Viro } 22974c3cbe3SAl Viro 23074c3cbe3SAl Viro /* tagging and untagging inodes with trees */ 23174c3cbe3SAl Viro 2328f7b0ba1SAl Viro static struct audit_chunk *find_chunk(struct node *p) 23374c3cbe3SAl Viro { 2348f7b0ba1SAl Viro int index = p->index & ~(1U<<31); 2358f7b0ba1SAl Viro p -= index; 2368f7b0ba1SAl Viro return container_of(p, struct audit_chunk, owners[0]); 2378f7b0ba1SAl Viro } 2388f7b0ba1SAl Viro 2398f7b0ba1SAl Viro static void untag_chunk(struct node *p) 2408f7b0ba1SAl Viro { 2418f7b0ba1SAl Viro struct audit_chunk *chunk = find_chunk(p); 242e61ce867SEric Paris struct fsnotify_mark *entry = &chunk->mark; 243f7a998a9SAl Viro struct audit_chunk *new = NULL; 24474c3cbe3SAl Viro struct audit_tree *owner; 24574c3cbe3SAl Viro int size = chunk->count - 1; 24674c3cbe3SAl Viro int i, j; 24774c3cbe3SAl Viro 24828a3a7ebSEric Paris fsnotify_get_mark(entry); 2498f7b0ba1SAl Viro 2508f7b0ba1SAl Viro spin_unlock(&hash_lock); 2518f7b0ba1SAl Viro 252f7a998a9SAl Viro if (size) 253f7a998a9SAl Viro new = alloc_chunk(size); 254f7a998a9SAl Viro 255be29d20fSJan Kara mutex_lock(&entry->group->mark_mutex); 25628a3a7ebSEric Paris spin_lock(&entry->lock); 2576b3f05d2SJan Kara /* 2586b3f05d2SJan Kara * mark_mutex protects mark from getting detached and thus also from 2596b3f05d2SJan Kara * mark->connector->inode getting NULL. 2606b3f05d2SJan Kara */ 26143471d15SJan Kara if (chunk->dead || !(entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) { 26228a3a7ebSEric Paris spin_unlock(&entry->lock); 263be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 264f7a998a9SAl Viro if (new) 265f7a998a9SAl Viro free_chunk(new); 2668f7b0ba1SAl Viro goto out; 26774c3cbe3SAl Viro } 26874c3cbe3SAl Viro 26974c3cbe3SAl Viro owner = p->owner; 27074c3cbe3SAl Viro 27174c3cbe3SAl Viro if (!size) { 27274c3cbe3SAl Viro chunk->dead = 1; 27374c3cbe3SAl Viro spin_lock(&hash_lock); 27474c3cbe3SAl Viro list_del_init(&chunk->trees); 27574c3cbe3SAl Viro if (owner->root == chunk) 27674c3cbe3SAl Viro owner->root = NULL; 27774c3cbe3SAl Viro list_del_init(&p->list); 27874c3cbe3SAl Viro list_del_rcu(&chunk->hash); 27974c3cbe3SAl Viro spin_unlock(&hash_lock); 28028a3a7ebSEric Paris spin_unlock(&entry->lock); 281be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 282e2a29943SLino Sanfilippo fsnotify_destroy_mark(entry, audit_tree_group); 2838f7b0ba1SAl Viro goto out; 28474c3cbe3SAl Viro } 28574c3cbe3SAl Viro 28674c3cbe3SAl Viro if (!new) 28774c3cbe3SAl Viro goto Fallback; 288f7a998a9SAl Viro 28986ffe245SJan Kara if (fsnotify_add_mark_locked(&new->mark, entry->group, 29086ffe245SJan Kara entry->connector->inode, NULL, 1)) { 2910fe33aaeSMiklos Szeredi fsnotify_put_mark(&new->mark); 29274c3cbe3SAl Viro goto Fallback; 29374c3cbe3SAl Viro } 29474c3cbe3SAl Viro 29574c3cbe3SAl Viro chunk->dead = 1; 29674c3cbe3SAl Viro spin_lock(&hash_lock); 29774c3cbe3SAl Viro list_replace_init(&chunk->trees, &new->trees); 29874c3cbe3SAl Viro if (owner->root == chunk) { 29974c3cbe3SAl Viro list_del_init(&owner->same_root); 30074c3cbe3SAl Viro owner->root = NULL; 30174c3cbe3SAl Viro } 30274c3cbe3SAl Viro 3036f5d5114SAl Viro for (i = j = 0; j <= size; i++, j++) { 30474c3cbe3SAl Viro struct audit_tree *s; 30574c3cbe3SAl Viro if (&chunk->owners[j] == p) { 30674c3cbe3SAl Viro list_del_init(&p->list); 30774c3cbe3SAl Viro i--; 30874c3cbe3SAl Viro continue; 30974c3cbe3SAl Viro } 31074c3cbe3SAl Viro s = chunk->owners[j].owner; 31174c3cbe3SAl Viro new->owners[i].owner = s; 31274c3cbe3SAl Viro new->owners[i].index = chunk->owners[j].index - j + i; 31374c3cbe3SAl Viro if (!s) /* result of earlier fallback */ 31474c3cbe3SAl Viro continue; 31574c3cbe3SAl Viro get_tree(s); 3166f5d5114SAl Viro list_replace_init(&chunk->owners[j].list, &new->owners[i].list); 31774c3cbe3SAl Viro } 31874c3cbe3SAl Viro 31974c3cbe3SAl Viro list_replace_rcu(&chunk->hash, &new->hash); 32074c3cbe3SAl Viro list_for_each_entry(owner, &new->trees, same_root) 32174c3cbe3SAl Viro owner->root = new; 32274c3cbe3SAl Viro spin_unlock(&hash_lock); 32328a3a7ebSEric Paris spin_unlock(&entry->lock); 324be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 325e2a29943SLino Sanfilippo fsnotify_destroy_mark(entry, audit_tree_group); 326b3e8692bSMiklos Szeredi fsnotify_put_mark(&new->mark); /* drop initial reference */ 3278f7b0ba1SAl Viro goto out; 32874c3cbe3SAl Viro 32974c3cbe3SAl Viro Fallback: 33074c3cbe3SAl Viro // do the best we can 33174c3cbe3SAl Viro spin_lock(&hash_lock); 33274c3cbe3SAl Viro if (owner->root == chunk) { 33374c3cbe3SAl Viro list_del_init(&owner->same_root); 33474c3cbe3SAl Viro owner->root = NULL; 33574c3cbe3SAl Viro } 33674c3cbe3SAl Viro list_del_init(&p->list); 33774c3cbe3SAl Viro p->owner = NULL; 33874c3cbe3SAl Viro put_tree(owner); 33974c3cbe3SAl Viro spin_unlock(&hash_lock); 34028a3a7ebSEric Paris spin_unlock(&entry->lock); 341be29d20fSJan Kara mutex_unlock(&entry->group->mark_mutex); 3428f7b0ba1SAl Viro out: 34328a3a7ebSEric Paris fsnotify_put_mark(entry); 3448f7b0ba1SAl Viro spin_lock(&hash_lock); 34574c3cbe3SAl Viro } 34674c3cbe3SAl Viro 34774c3cbe3SAl Viro static int create_chunk(struct inode *inode, struct audit_tree *tree) 34874c3cbe3SAl Viro { 349e61ce867SEric Paris struct fsnotify_mark *entry; 35074c3cbe3SAl Viro struct audit_chunk *chunk = alloc_chunk(1); 35174c3cbe3SAl Viro if (!chunk) 35274c3cbe3SAl Viro return -ENOMEM; 35374c3cbe3SAl Viro 35428a3a7ebSEric Paris entry = &chunk->mark; 3555444e298SEric Paris if (fsnotify_add_mark(entry, audit_tree_group, inode, NULL, 0)) { 3560fe33aaeSMiklos Szeredi fsnotify_put_mark(entry); 35774c3cbe3SAl Viro return -ENOSPC; 35874c3cbe3SAl Viro } 35974c3cbe3SAl Viro 36028a3a7ebSEric Paris spin_lock(&entry->lock); 36174c3cbe3SAl Viro spin_lock(&hash_lock); 36274c3cbe3SAl Viro if (tree->goner) { 36374c3cbe3SAl Viro spin_unlock(&hash_lock); 36474c3cbe3SAl Viro chunk->dead = 1; 36528a3a7ebSEric Paris spin_unlock(&entry->lock); 366e2a29943SLino Sanfilippo fsnotify_destroy_mark(entry, audit_tree_group); 36728a3a7ebSEric Paris fsnotify_put_mark(entry); 36874c3cbe3SAl Viro return 0; 36974c3cbe3SAl Viro } 37074c3cbe3SAl Viro chunk->owners[0].index = (1U << 31); 37174c3cbe3SAl Viro chunk->owners[0].owner = tree; 37274c3cbe3SAl Viro get_tree(tree); 37374c3cbe3SAl Viro list_add(&chunk->owners[0].list, &tree->chunks); 37474c3cbe3SAl Viro if (!tree->root) { 37574c3cbe3SAl Viro tree->root = chunk; 37674c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees); 37774c3cbe3SAl Viro } 37874c3cbe3SAl Viro insert_hash(chunk); 37974c3cbe3SAl Viro spin_unlock(&hash_lock); 38028a3a7ebSEric Paris spin_unlock(&entry->lock); 381b3e8692bSMiklos Szeredi fsnotify_put_mark(entry); /* drop initial reference */ 38274c3cbe3SAl Viro return 0; 38374c3cbe3SAl Viro } 38474c3cbe3SAl Viro 38574c3cbe3SAl Viro /* the first tagged inode becomes root of tree */ 38674c3cbe3SAl Viro static int tag_chunk(struct inode *inode, struct audit_tree *tree) 38774c3cbe3SAl Viro { 388e61ce867SEric Paris struct fsnotify_mark *old_entry, *chunk_entry; 38974c3cbe3SAl Viro struct audit_tree *owner; 39074c3cbe3SAl Viro struct audit_chunk *chunk, *old; 39174c3cbe3SAl Viro struct node *p; 39274c3cbe3SAl Viro int n; 39374c3cbe3SAl Viro 3945444e298SEric Paris old_entry = fsnotify_find_inode_mark(audit_tree_group, inode); 39528a3a7ebSEric Paris if (!old_entry) 39674c3cbe3SAl Viro return create_chunk(inode, tree); 39774c3cbe3SAl Viro 39828a3a7ebSEric Paris old = container_of(old_entry, struct audit_chunk, mark); 39974c3cbe3SAl Viro 40074c3cbe3SAl Viro /* are we already there? */ 40174c3cbe3SAl Viro spin_lock(&hash_lock); 40274c3cbe3SAl Viro for (n = 0; n < old->count; n++) { 40374c3cbe3SAl Viro if (old->owners[n].owner == tree) { 40474c3cbe3SAl Viro spin_unlock(&hash_lock); 40528a3a7ebSEric Paris fsnotify_put_mark(old_entry); 40674c3cbe3SAl Viro return 0; 40774c3cbe3SAl Viro } 40874c3cbe3SAl Viro } 40974c3cbe3SAl Viro spin_unlock(&hash_lock); 41074c3cbe3SAl Viro 41174c3cbe3SAl Viro chunk = alloc_chunk(old->count + 1); 412b4c30aadSAl Viro if (!chunk) { 41328a3a7ebSEric Paris fsnotify_put_mark(old_entry); 41474c3cbe3SAl Viro return -ENOMEM; 415b4c30aadSAl Viro } 41674c3cbe3SAl Viro 41728a3a7ebSEric Paris chunk_entry = &chunk->mark; 41828a3a7ebSEric Paris 419be29d20fSJan Kara mutex_lock(&old_entry->group->mark_mutex); 42028a3a7ebSEric Paris spin_lock(&old_entry->lock); 4216b3f05d2SJan Kara /* 4226b3f05d2SJan Kara * mark_mutex protects mark from getting detached and thus also from 4236b3f05d2SJan Kara * mark->connector->inode getting NULL. 4246b3f05d2SJan Kara */ 42543471d15SJan Kara if (!(old_entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) { 42628a3a7ebSEric Paris /* old_entry is being shot, lets just lie */ 42728a3a7ebSEric Paris spin_unlock(&old_entry->lock); 428be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 42928a3a7ebSEric Paris fsnotify_put_mark(old_entry); 43074c3cbe3SAl Viro free_chunk(chunk); 43128a3a7ebSEric Paris return -ENOENT; 43228a3a7ebSEric Paris } 43328a3a7ebSEric Paris 434be29d20fSJan Kara if (fsnotify_add_mark_locked(chunk_entry, old_entry->group, 43586ffe245SJan Kara old_entry->connector->inode, NULL, 1)) { 43628a3a7ebSEric Paris spin_unlock(&old_entry->lock); 437be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 4380fe33aaeSMiklos Szeredi fsnotify_put_mark(chunk_entry); 43928a3a7ebSEric Paris fsnotify_put_mark(old_entry); 44074c3cbe3SAl Viro return -ENOSPC; 44174c3cbe3SAl Viro } 44228a3a7ebSEric Paris 44328a3a7ebSEric Paris /* even though we hold old_entry->lock, this is safe since chunk_entry->lock could NEVER have been grabbed before */ 44428a3a7ebSEric Paris spin_lock(&chunk_entry->lock); 44574c3cbe3SAl Viro spin_lock(&hash_lock); 44628a3a7ebSEric Paris 44728a3a7ebSEric Paris /* we now hold old_entry->lock, chunk_entry->lock, and hash_lock */ 44874c3cbe3SAl Viro if (tree->goner) { 44974c3cbe3SAl Viro spin_unlock(&hash_lock); 45074c3cbe3SAl Viro chunk->dead = 1; 45128a3a7ebSEric Paris spin_unlock(&chunk_entry->lock); 45228a3a7ebSEric Paris spin_unlock(&old_entry->lock); 453be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 45428a3a7ebSEric Paris 455e2a29943SLino Sanfilippo fsnotify_destroy_mark(chunk_entry, audit_tree_group); 45628a3a7ebSEric Paris 45728a3a7ebSEric Paris fsnotify_put_mark(chunk_entry); 45828a3a7ebSEric Paris fsnotify_put_mark(old_entry); 45974c3cbe3SAl Viro return 0; 46074c3cbe3SAl Viro } 46174c3cbe3SAl Viro list_replace_init(&old->trees, &chunk->trees); 46274c3cbe3SAl Viro for (n = 0, p = chunk->owners; n < old->count; n++, p++) { 46374c3cbe3SAl Viro struct audit_tree *s = old->owners[n].owner; 46474c3cbe3SAl Viro p->owner = s; 46574c3cbe3SAl Viro p->index = old->owners[n].index; 46674c3cbe3SAl Viro if (!s) /* result of fallback in untag */ 46774c3cbe3SAl Viro continue; 46874c3cbe3SAl Viro get_tree(s); 46974c3cbe3SAl Viro list_replace_init(&old->owners[n].list, &p->list); 47074c3cbe3SAl Viro } 47174c3cbe3SAl Viro p->index = (chunk->count - 1) | (1U<<31); 47274c3cbe3SAl Viro p->owner = tree; 47374c3cbe3SAl Viro get_tree(tree); 47474c3cbe3SAl Viro list_add(&p->list, &tree->chunks); 47574c3cbe3SAl Viro list_replace_rcu(&old->hash, &chunk->hash); 47674c3cbe3SAl Viro list_for_each_entry(owner, &chunk->trees, same_root) 47774c3cbe3SAl Viro owner->root = chunk; 47874c3cbe3SAl Viro old->dead = 1; 47974c3cbe3SAl Viro if (!tree->root) { 48074c3cbe3SAl Viro tree->root = chunk; 48174c3cbe3SAl Viro list_add(&tree->same_root, &chunk->trees); 48274c3cbe3SAl Viro } 48374c3cbe3SAl Viro spin_unlock(&hash_lock); 48428a3a7ebSEric Paris spin_unlock(&chunk_entry->lock); 48528a3a7ebSEric Paris spin_unlock(&old_entry->lock); 486be29d20fSJan Kara mutex_unlock(&old_entry->group->mark_mutex); 487e2a29943SLino Sanfilippo fsnotify_destroy_mark(old_entry, audit_tree_group); 488b3e8692bSMiklos Szeredi fsnotify_put_mark(chunk_entry); /* drop initial reference */ 48928a3a7ebSEric Paris fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ 49074c3cbe3SAl Viro return 0; 49174c3cbe3SAl Viro } 49274c3cbe3SAl Viro 4932991dd2bSRichard Guy Briggs static void audit_tree_log_remove_rule(struct audit_krule *rule) 49474c3cbe3SAl Viro { 49574c3cbe3SAl Viro struct audit_buffer *ab; 49674c3cbe3SAl Viro 49774c3cbe3SAl Viro ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); 4980644ec0cSKees Cook if (unlikely(!ab)) 4990644ec0cSKees Cook return; 500c1e8f06dSSteve Grubb audit_log_format(ab, "op=remove_rule"); 5019d960985SEric Paris audit_log_format(ab, " dir="); 50274c3cbe3SAl Viro audit_log_untrustedstring(ab, rule->tree->pathname); 5039d960985SEric Paris audit_log_key(ab, rule->filterkey); 50474c3cbe3SAl Viro audit_log_format(ab, " list=%d res=1", rule->listnr); 50574c3cbe3SAl Viro audit_log_end(ab); 5060644ec0cSKees Cook } 5070644ec0cSKees Cook 5080644ec0cSKees Cook static void kill_rules(struct audit_tree *tree) 5090644ec0cSKees Cook { 5100644ec0cSKees Cook struct audit_krule *rule, *next; 5110644ec0cSKees Cook struct audit_entry *entry; 5120644ec0cSKees Cook 5130644ec0cSKees Cook list_for_each_entry_safe(rule, next, &tree->rules, rlist) { 5140644ec0cSKees Cook entry = container_of(rule, struct audit_entry, rule); 5150644ec0cSKees Cook 5160644ec0cSKees Cook list_del_init(&rule->rlist); 5170644ec0cSKees Cook if (rule->tree) { 5180644ec0cSKees Cook /* not a half-baked one */ 5192991dd2bSRichard Guy Briggs audit_tree_log_remove_rule(rule); 52034d99af5SRichard Guy Briggs if (entry->rule.exe) 52134d99af5SRichard Guy Briggs audit_remove_mark(entry->rule.exe); 52274c3cbe3SAl Viro rule->tree = NULL; 52374c3cbe3SAl Viro list_del_rcu(&entry->list); 524e45aa212SAl Viro list_del(&entry->rule.list); 52574c3cbe3SAl Viro call_rcu(&entry->rcu, audit_free_rule_rcu); 52674c3cbe3SAl Viro } 52774c3cbe3SAl Viro } 52874c3cbe3SAl Viro } 52974c3cbe3SAl Viro 53074c3cbe3SAl Viro /* 53174c3cbe3SAl Viro * finish killing struct audit_tree 53274c3cbe3SAl Viro */ 53374c3cbe3SAl Viro static void prune_one(struct audit_tree *victim) 53474c3cbe3SAl Viro { 53574c3cbe3SAl Viro spin_lock(&hash_lock); 53674c3cbe3SAl Viro while (!list_empty(&victim->chunks)) { 53774c3cbe3SAl Viro struct node *p; 53874c3cbe3SAl Viro 53974c3cbe3SAl Viro p = list_entry(victim->chunks.next, struct node, list); 54074c3cbe3SAl Viro 5418f7b0ba1SAl Viro untag_chunk(p); 54274c3cbe3SAl Viro } 54374c3cbe3SAl Viro spin_unlock(&hash_lock); 54474c3cbe3SAl Viro put_tree(victim); 54574c3cbe3SAl Viro } 54674c3cbe3SAl Viro 54774c3cbe3SAl Viro /* trim the uncommitted chunks from tree */ 54874c3cbe3SAl Viro 54974c3cbe3SAl Viro static void trim_marked(struct audit_tree *tree) 55074c3cbe3SAl Viro { 55174c3cbe3SAl Viro struct list_head *p, *q; 55274c3cbe3SAl Viro spin_lock(&hash_lock); 55374c3cbe3SAl Viro if (tree->goner) { 55474c3cbe3SAl Viro spin_unlock(&hash_lock); 55574c3cbe3SAl Viro return; 55674c3cbe3SAl Viro } 55774c3cbe3SAl Viro /* reorder */ 55874c3cbe3SAl Viro for (p = tree->chunks.next; p != &tree->chunks; p = q) { 55974c3cbe3SAl Viro struct node *node = list_entry(p, struct node, list); 56074c3cbe3SAl Viro q = p->next; 56174c3cbe3SAl Viro if (node->index & (1U<<31)) { 56274c3cbe3SAl Viro list_del_init(p); 56374c3cbe3SAl Viro list_add(p, &tree->chunks); 56474c3cbe3SAl Viro } 56574c3cbe3SAl Viro } 56674c3cbe3SAl Viro 56774c3cbe3SAl Viro while (!list_empty(&tree->chunks)) { 56874c3cbe3SAl Viro struct node *node; 56974c3cbe3SAl Viro 57074c3cbe3SAl Viro node = list_entry(tree->chunks.next, struct node, list); 57174c3cbe3SAl Viro 57274c3cbe3SAl Viro /* have we run out of marked? */ 57374c3cbe3SAl Viro if (!(node->index & (1U<<31))) 57474c3cbe3SAl Viro break; 57574c3cbe3SAl Viro 5768f7b0ba1SAl Viro untag_chunk(node); 57774c3cbe3SAl Viro } 57874c3cbe3SAl Viro if (!tree->root && !tree->goner) { 57974c3cbe3SAl Viro tree->goner = 1; 58074c3cbe3SAl Viro spin_unlock(&hash_lock); 58174c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 58274c3cbe3SAl Viro kill_rules(tree); 58374c3cbe3SAl Viro list_del_init(&tree->list); 58474c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 58574c3cbe3SAl Viro prune_one(tree); 58674c3cbe3SAl Viro } else { 58774c3cbe3SAl Viro spin_unlock(&hash_lock); 58874c3cbe3SAl Viro } 58974c3cbe3SAl Viro } 59074c3cbe3SAl Viro 591916d7576SAl Viro static void audit_schedule_prune(void); 592916d7576SAl Viro 59374c3cbe3SAl Viro /* called with audit_filter_mutex */ 59474c3cbe3SAl Viro int audit_remove_tree_rule(struct audit_krule *rule) 59574c3cbe3SAl Viro { 59674c3cbe3SAl Viro struct audit_tree *tree; 59774c3cbe3SAl Viro tree = rule->tree; 59874c3cbe3SAl Viro if (tree) { 59974c3cbe3SAl Viro spin_lock(&hash_lock); 60074c3cbe3SAl Viro list_del_init(&rule->rlist); 60174c3cbe3SAl Viro if (list_empty(&tree->rules) && !tree->goner) { 60274c3cbe3SAl Viro tree->root = NULL; 60374c3cbe3SAl Viro list_del_init(&tree->same_root); 60474c3cbe3SAl Viro tree->goner = 1; 60574c3cbe3SAl Viro list_move(&tree->list, &prune_list); 60674c3cbe3SAl Viro rule->tree = NULL; 60774c3cbe3SAl Viro spin_unlock(&hash_lock); 60874c3cbe3SAl Viro audit_schedule_prune(); 60974c3cbe3SAl Viro return 1; 61074c3cbe3SAl Viro } 61174c3cbe3SAl Viro rule->tree = NULL; 61274c3cbe3SAl Viro spin_unlock(&hash_lock); 61374c3cbe3SAl Viro return 1; 61474c3cbe3SAl Viro } 61574c3cbe3SAl Viro return 0; 61674c3cbe3SAl Viro } 61774c3cbe3SAl Viro 6181f707137SAl Viro static int compare_root(struct vfsmount *mnt, void *arg) 6191f707137SAl Viro { 620f410ff65SJan Kara return inode_to_key(d_backing_inode(mnt->mnt_root)) == 621f410ff65SJan Kara (unsigned long)arg; 6221f707137SAl Viro } 6231f707137SAl Viro 62474c3cbe3SAl Viro void audit_trim_trees(void) 62574c3cbe3SAl Viro { 62674c3cbe3SAl Viro struct list_head cursor; 62774c3cbe3SAl Viro 62874c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 62974c3cbe3SAl Viro list_add(&cursor, &tree_list); 63074c3cbe3SAl Viro while (cursor.next != &tree_list) { 63174c3cbe3SAl Viro struct audit_tree *tree; 63298bc993fSAl Viro struct path path; 63374c3cbe3SAl Viro struct vfsmount *root_mnt; 63474c3cbe3SAl Viro struct node *node; 63574c3cbe3SAl Viro int err; 63674c3cbe3SAl Viro 63774c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 63874c3cbe3SAl Viro get_tree(tree); 63974c3cbe3SAl Viro list_del(&cursor); 64074c3cbe3SAl Viro list_add(&cursor, &tree->list); 64174c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 64274c3cbe3SAl Viro 64398bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 64474c3cbe3SAl Viro if (err) 64574c3cbe3SAl Viro goto skip_it; 64674c3cbe3SAl Viro 647589ff870SAl Viro root_mnt = collect_mounts(&path); 64898bc993fSAl Viro path_put(&path); 649be34d1a3SDavid Howells if (IS_ERR(root_mnt)) 65074c3cbe3SAl Viro goto skip_it; 65174c3cbe3SAl Viro 65274c3cbe3SAl Viro spin_lock(&hash_lock); 65374c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) { 65428a3a7ebSEric Paris struct audit_chunk *chunk = find_chunk(node); 65525985edcSLucas De Marchi /* this could be NULL if the watch is dying else where... */ 65674c3cbe3SAl Viro node->index |= 1U<<31; 657f410ff65SJan Kara if (iterate_mounts(compare_root, 658f410ff65SJan Kara (void *)chunk_to_key(chunk), 659f410ff65SJan Kara root_mnt)) 66074c3cbe3SAl Viro node->index &= ~(1U<<31); 66174c3cbe3SAl Viro } 66274c3cbe3SAl Viro spin_unlock(&hash_lock); 66374c3cbe3SAl Viro trim_marked(tree); 66474c3cbe3SAl Viro drop_collected_mounts(root_mnt); 66574c3cbe3SAl Viro skip_it: 66612b2f117SChen Gang put_tree(tree); 66774c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 66874c3cbe3SAl Viro } 66974c3cbe3SAl Viro list_del(&cursor); 67074c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 67174c3cbe3SAl Viro } 67274c3cbe3SAl Viro 67374c3cbe3SAl Viro int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) 67474c3cbe3SAl Viro { 67574c3cbe3SAl Viro 67674c3cbe3SAl Viro if (pathname[0] != '/' || 67774c3cbe3SAl Viro rule->listnr != AUDIT_FILTER_EXIT || 6785af75d8dSAl Viro op != Audit_equal || 67974c3cbe3SAl Viro rule->inode_f || rule->watch || rule->tree) 68074c3cbe3SAl Viro return -EINVAL; 68174c3cbe3SAl Viro rule->tree = alloc_tree(pathname); 68274c3cbe3SAl Viro if (!rule->tree) 68374c3cbe3SAl Viro return -ENOMEM; 68474c3cbe3SAl Viro return 0; 68574c3cbe3SAl Viro } 68674c3cbe3SAl Viro 68774c3cbe3SAl Viro void audit_put_tree(struct audit_tree *tree) 68874c3cbe3SAl Viro { 68974c3cbe3SAl Viro put_tree(tree); 69074c3cbe3SAl Viro } 69174c3cbe3SAl Viro 6921f707137SAl Viro static int tag_mount(struct vfsmount *mnt, void *arg) 6931f707137SAl Viro { 6943b362157SDavid Howells return tag_chunk(d_backing_inode(mnt->mnt_root), arg); 6951f707137SAl Viro } 6961f707137SAl Viro 697f1aaf262SImre Palik /* 698f1aaf262SImre Palik * That gets run when evict_chunk() ends up needing to kill audit_tree. 699f1aaf262SImre Palik * Runs from a separate thread. 700f1aaf262SImre Palik */ 701f1aaf262SImre Palik static int prune_tree_thread(void *unused) 702f1aaf262SImre Palik { 703f1aaf262SImre Palik for (;;) { 7040bf676d1SJiri Slaby if (list_empty(&prune_list)) { 705f1aaf262SImre Palik set_current_state(TASK_INTERRUPTIBLE); 706f1aaf262SImre Palik schedule(); 7070bf676d1SJiri Slaby } 708f1aaf262SImre Palik 709f1aaf262SImre Palik mutex_lock(&audit_cmd_mutex); 710f1aaf262SImre Palik mutex_lock(&audit_filter_mutex); 711f1aaf262SImre Palik 712f1aaf262SImre Palik while (!list_empty(&prune_list)) { 713f1aaf262SImre Palik struct audit_tree *victim; 714f1aaf262SImre Palik 715f1aaf262SImre Palik victim = list_entry(prune_list.next, 716f1aaf262SImre Palik struct audit_tree, list); 717f1aaf262SImre Palik list_del_init(&victim->list); 718f1aaf262SImre Palik 719f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex); 720f1aaf262SImre Palik 721f1aaf262SImre Palik prune_one(victim); 722f1aaf262SImre Palik 723f1aaf262SImre Palik mutex_lock(&audit_filter_mutex); 724f1aaf262SImre Palik } 725f1aaf262SImre Palik 726f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex); 727f1aaf262SImre Palik mutex_unlock(&audit_cmd_mutex); 728f1aaf262SImre Palik } 729f1aaf262SImre Palik return 0; 730f1aaf262SImre Palik } 731f1aaf262SImre Palik 732f1aaf262SImre Palik static int audit_launch_prune(void) 733f1aaf262SImre Palik { 734f1aaf262SImre Palik if (prune_thread) 735f1aaf262SImre Palik return 0; 7360bf676d1SJiri Slaby prune_thread = kthread_run(prune_tree_thread, NULL, 737f1aaf262SImre Palik "audit_prune_tree"); 738f1aaf262SImre Palik if (IS_ERR(prune_thread)) { 739f1aaf262SImre Palik pr_err("cannot start thread audit_prune_tree"); 740f1aaf262SImre Palik prune_thread = NULL; 741f1aaf262SImre Palik return -ENOMEM; 742f1aaf262SImre Palik } 7430bf676d1SJiri Slaby return 0; 744f1aaf262SImre Palik } 745f1aaf262SImre Palik 74674c3cbe3SAl Viro /* called with audit_filter_mutex */ 74774c3cbe3SAl Viro int audit_add_tree_rule(struct audit_krule *rule) 74874c3cbe3SAl Viro { 74974c3cbe3SAl Viro struct audit_tree *seed = rule->tree, *tree; 75098bc993fSAl Viro struct path path; 7511f707137SAl Viro struct vfsmount *mnt; 75274c3cbe3SAl Viro int err; 75374c3cbe3SAl Viro 754736f3203SChen Gang rule->tree = NULL; 75574c3cbe3SAl Viro list_for_each_entry(tree, &tree_list, list) { 75674c3cbe3SAl Viro if (!strcmp(seed->pathname, tree->pathname)) { 75774c3cbe3SAl Viro put_tree(seed); 75874c3cbe3SAl Viro rule->tree = tree; 75974c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 76074c3cbe3SAl Viro return 0; 76174c3cbe3SAl Viro } 76274c3cbe3SAl Viro } 76374c3cbe3SAl Viro tree = seed; 76474c3cbe3SAl Viro list_add(&tree->list, &tree_list); 76574c3cbe3SAl Viro list_add(&rule->rlist, &tree->rules); 76674c3cbe3SAl Viro /* do not set rule->tree yet */ 76774c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 76874c3cbe3SAl Viro 769f1aaf262SImre Palik if (unlikely(!prune_thread)) { 770f1aaf262SImre Palik err = audit_launch_prune(); 771f1aaf262SImre Palik if (err) 772f1aaf262SImre Palik goto Err; 773f1aaf262SImre Palik } 774f1aaf262SImre Palik 77598bc993fSAl Viro err = kern_path(tree->pathname, 0, &path); 77674c3cbe3SAl Viro if (err) 77774c3cbe3SAl Viro goto Err; 778589ff870SAl Viro mnt = collect_mounts(&path); 77998bc993fSAl Viro path_put(&path); 780be34d1a3SDavid Howells if (IS_ERR(mnt)) { 781be34d1a3SDavid Howells err = PTR_ERR(mnt); 78274c3cbe3SAl Viro goto Err; 78374c3cbe3SAl Viro } 78474c3cbe3SAl Viro 78574c3cbe3SAl Viro get_tree(tree); 7861f707137SAl Viro err = iterate_mounts(tag_mount, tree, mnt); 78774c3cbe3SAl Viro drop_collected_mounts(mnt); 78874c3cbe3SAl Viro 78974c3cbe3SAl Viro if (!err) { 79074c3cbe3SAl Viro struct node *node; 79174c3cbe3SAl Viro spin_lock(&hash_lock); 79274c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 79374c3cbe3SAl Viro node->index &= ~(1U<<31); 79474c3cbe3SAl Viro spin_unlock(&hash_lock); 79574c3cbe3SAl Viro } else { 79674c3cbe3SAl Viro trim_marked(tree); 79774c3cbe3SAl Viro goto Err; 79874c3cbe3SAl Viro } 79974c3cbe3SAl Viro 80074c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 80174c3cbe3SAl Viro if (list_empty(&rule->rlist)) { 80274c3cbe3SAl Viro put_tree(tree); 80374c3cbe3SAl Viro return -ENOENT; 80474c3cbe3SAl Viro } 80574c3cbe3SAl Viro rule->tree = tree; 80674c3cbe3SAl Viro put_tree(tree); 80774c3cbe3SAl Viro 80874c3cbe3SAl Viro return 0; 80974c3cbe3SAl Viro Err: 81074c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 81174c3cbe3SAl Viro list_del_init(&tree->list); 81274c3cbe3SAl Viro list_del_init(&tree->rules); 81374c3cbe3SAl Viro put_tree(tree); 81474c3cbe3SAl Viro return err; 81574c3cbe3SAl Viro } 81674c3cbe3SAl Viro 81774c3cbe3SAl Viro int audit_tag_tree(char *old, char *new) 81874c3cbe3SAl Viro { 81974c3cbe3SAl Viro struct list_head cursor, barrier; 82074c3cbe3SAl Viro int failed = 0; 8212096f759SAl Viro struct path path1, path2; 82274c3cbe3SAl Viro struct vfsmount *tagged; 82374c3cbe3SAl Viro int err; 82474c3cbe3SAl Viro 8252096f759SAl Viro err = kern_path(new, 0, &path2); 82674c3cbe3SAl Viro if (err) 82774c3cbe3SAl Viro return err; 8282096f759SAl Viro tagged = collect_mounts(&path2); 8292096f759SAl Viro path_put(&path2); 830be34d1a3SDavid Howells if (IS_ERR(tagged)) 831be34d1a3SDavid Howells return PTR_ERR(tagged); 83274c3cbe3SAl Viro 8332096f759SAl Viro err = kern_path(old, 0, &path1); 83474c3cbe3SAl Viro if (err) { 83574c3cbe3SAl Viro drop_collected_mounts(tagged); 83674c3cbe3SAl Viro return err; 83774c3cbe3SAl Viro } 83874c3cbe3SAl Viro 83974c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 84074c3cbe3SAl Viro list_add(&barrier, &tree_list); 84174c3cbe3SAl Viro list_add(&cursor, &barrier); 84274c3cbe3SAl Viro 84374c3cbe3SAl Viro while (cursor.next != &tree_list) { 84474c3cbe3SAl Viro struct audit_tree *tree; 8452096f759SAl Viro int good_one = 0; 84674c3cbe3SAl Viro 84774c3cbe3SAl Viro tree = container_of(cursor.next, struct audit_tree, list); 84874c3cbe3SAl Viro get_tree(tree); 84974c3cbe3SAl Viro list_del(&cursor); 85074c3cbe3SAl Viro list_add(&cursor, &tree->list); 85174c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 85274c3cbe3SAl Viro 8532096f759SAl Viro err = kern_path(tree->pathname, 0, &path2); 8542096f759SAl Viro if (!err) { 8552096f759SAl Viro good_one = path_is_under(&path1, &path2); 8562096f759SAl Viro path_put(&path2); 85774c3cbe3SAl Viro } 85874c3cbe3SAl Viro 8592096f759SAl Viro if (!good_one) { 86074c3cbe3SAl Viro put_tree(tree); 86174c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 86274c3cbe3SAl Viro continue; 86374c3cbe3SAl Viro } 86474c3cbe3SAl Viro 8651f707137SAl Viro failed = iterate_mounts(tag_mount, tree, tagged); 86674c3cbe3SAl Viro if (failed) { 86774c3cbe3SAl Viro put_tree(tree); 86874c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 86974c3cbe3SAl Viro break; 87074c3cbe3SAl Viro } 87174c3cbe3SAl Viro 87274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 87374c3cbe3SAl Viro spin_lock(&hash_lock); 87474c3cbe3SAl Viro if (!tree->goner) { 87574c3cbe3SAl Viro list_del(&tree->list); 87674c3cbe3SAl Viro list_add(&tree->list, &tree_list); 87774c3cbe3SAl Viro } 87874c3cbe3SAl Viro spin_unlock(&hash_lock); 87974c3cbe3SAl Viro put_tree(tree); 88074c3cbe3SAl Viro } 88174c3cbe3SAl Viro 88274c3cbe3SAl Viro while (barrier.prev != &tree_list) { 88374c3cbe3SAl Viro struct audit_tree *tree; 88474c3cbe3SAl Viro 88574c3cbe3SAl Viro tree = container_of(barrier.prev, struct audit_tree, list); 88674c3cbe3SAl Viro get_tree(tree); 88774c3cbe3SAl Viro list_del(&tree->list); 88874c3cbe3SAl Viro list_add(&tree->list, &barrier); 88974c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 89074c3cbe3SAl Viro 89174c3cbe3SAl Viro if (!failed) { 89274c3cbe3SAl Viro struct node *node; 89374c3cbe3SAl Viro spin_lock(&hash_lock); 89474c3cbe3SAl Viro list_for_each_entry(node, &tree->chunks, list) 89574c3cbe3SAl Viro node->index &= ~(1U<<31); 89674c3cbe3SAl Viro spin_unlock(&hash_lock); 89774c3cbe3SAl Viro } else { 89874c3cbe3SAl Viro trim_marked(tree); 89974c3cbe3SAl Viro } 90074c3cbe3SAl Viro 90174c3cbe3SAl Viro put_tree(tree); 90274c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 90374c3cbe3SAl Viro } 90474c3cbe3SAl Viro list_del(&barrier); 90574c3cbe3SAl Viro list_del(&cursor); 90674c3cbe3SAl Viro mutex_unlock(&audit_filter_mutex); 9072096f759SAl Viro path_put(&path1); 90874c3cbe3SAl Viro drop_collected_mounts(tagged); 90974c3cbe3SAl Viro return failed; 91074c3cbe3SAl Viro } 91174c3cbe3SAl Viro 912916d7576SAl Viro 913916d7576SAl Viro static void audit_schedule_prune(void) 914916d7576SAl Viro { 915f1aaf262SImre Palik wake_up_process(prune_thread); 916916d7576SAl Viro } 917916d7576SAl Viro 918916d7576SAl Viro /* 919916d7576SAl Viro * ... and that one is done if evict_chunk() decides to delay until the end 920916d7576SAl Viro * of syscall. Runs synchronously. 921916d7576SAl Viro */ 922916d7576SAl Viro void audit_kill_trees(struct list_head *list) 923916d7576SAl Viro { 924916d7576SAl Viro mutex_lock(&audit_cmd_mutex); 925916d7576SAl Viro mutex_lock(&audit_filter_mutex); 926916d7576SAl Viro 927916d7576SAl Viro while (!list_empty(list)) { 928916d7576SAl Viro struct audit_tree *victim; 929916d7576SAl Viro 930916d7576SAl Viro victim = list_entry(list->next, struct audit_tree, list); 931916d7576SAl Viro kill_rules(victim); 932916d7576SAl Viro list_del_init(&victim->list); 933916d7576SAl Viro 934916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 935916d7576SAl Viro 936916d7576SAl Viro prune_one(victim); 937916d7576SAl Viro 938916d7576SAl Viro mutex_lock(&audit_filter_mutex); 939916d7576SAl Viro } 940916d7576SAl Viro 941916d7576SAl Viro mutex_unlock(&audit_filter_mutex); 942916d7576SAl Viro mutex_unlock(&audit_cmd_mutex); 94374c3cbe3SAl Viro } 94474c3cbe3SAl Viro 94574c3cbe3SAl Viro /* 94674c3cbe3SAl Viro * Here comes the stuff asynchronous to auditctl operations 94774c3cbe3SAl Viro */ 94874c3cbe3SAl Viro 94974c3cbe3SAl Viro static void evict_chunk(struct audit_chunk *chunk) 95074c3cbe3SAl Viro { 95174c3cbe3SAl Viro struct audit_tree *owner; 952916d7576SAl Viro struct list_head *postponed = audit_killed_trees(); 953916d7576SAl Viro int need_prune = 0; 95474c3cbe3SAl Viro int n; 95574c3cbe3SAl Viro 95674c3cbe3SAl Viro if (chunk->dead) 95774c3cbe3SAl Viro return; 95874c3cbe3SAl Viro 95974c3cbe3SAl Viro chunk->dead = 1; 96074c3cbe3SAl Viro mutex_lock(&audit_filter_mutex); 96174c3cbe3SAl Viro spin_lock(&hash_lock); 96274c3cbe3SAl Viro while (!list_empty(&chunk->trees)) { 96374c3cbe3SAl Viro owner = list_entry(chunk->trees.next, 96474c3cbe3SAl Viro struct audit_tree, same_root); 96574c3cbe3SAl Viro owner->goner = 1; 96674c3cbe3SAl Viro owner->root = NULL; 96774c3cbe3SAl Viro list_del_init(&owner->same_root); 96874c3cbe3SAl Viro spin_unlock(&hash_lock); 969916d7576SAl Viro if (!postponed) { 97074c3cbe3SAl Viro kill_rules(owner); 97174c3cbe3SAl Viro list_move(&owner->list, &prune_list); 972916d7576SAl Viro need_prune = 1; 973916d7576SAl Viro } else { 974916d7576SAl Viro list_move(&owner->list, postponed); 975916d7576SAl Viro } 97674c3cbe3SAl Viro spin_lock(&hash_lock); 97774c3cbe3SAl Viro } 97874c3cbe3SAl Viro list_del_rcu(&chunk->hash); 97974c3cbe3SAl Viro for (n = 0; n < chunk->count; n++) 98074c3cbe3SAl Viro list_del_init(&chunk->owners[n].list); 98174c3cbe3SAl Viro spin_unlock(&hash_lock); 982f1aaf262SImre Palik mutex_unlock(&audit_filter_mutex); 983916d7576SAl Viro if (need_prune) 984916d7576SAl Viro audit_schedule_prune(); 98574c3cbe3SAl Viro } 98674c3cbe3SAl Viro 9873a9b16b4SEric Paris static int audit_tree_handle_event(struct fsnotify_group *group, 9887053aee2SJan Kara struct inode *to_tell, 989ce8f76fbSEric Paris struct fsnotify_mark *inode_mark, 9907053aee2SJan Kara struct fsnotify_mark *vfsmount_mark, 9913cd5eca8SAl Viro u32 mask, const void *data, int data_type, 9929385a84dSJan Kara const unsigned char *file_name, u32 cookie, 9939385a84dSJan Kara struct fsnotify_iter_info *iter_info) 99474c3cbe3SAl Viro { 99583c4c4b0SJan Kara return 0; 99628a3a7ebSEric Paris } 99774c3cbe3SAl Viro 998e61ce867SEric Paris static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group) 99928a3a7ebSEric Paris { 100028a3a7ebSEric Paris struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark); 100128a3a7ebSEric Paris 100274c3cbe3SAl Viro evict_chunk(chunk); 1003b3e8692bSMiklos Szeredi 1004b3e8692bSMiklos Szeredi /* 1005b3e8692bSMiklos Szeredi * We are guaranteed to have at least one reference to the mark from 1006b3e8692bSMiklos Szeredi * either the inode or the caller of fsnotify_destroy_mark(). 1007b3e8692bSMiklos Szeredi */ 1008b3e8692bSMiklos Szeredi BUG_ON(atomic_read(&entry->refcnt) < 1); 100974c3cbe3SAl Viro } 101074c3cbe3SAl Viro 101128a3a7ebSEric Paris static const struct fsnotify_ops audit_tree_ops = { 101228a3a7ebSEric Paris .handle_event = audit_tree_handle_event, 101328a3a7ebSEric Paris .freeing_mark = audit_tree_freeing_mark, 101474c3cbe3SAl Viro }; 101574c3cbe3SAl Viro 101674c3cbe3SAl Viro static int __init audit_tree_init(void) 101774c3cbe3SAl Viro { 101874c3cbe3SAl Viro int i; 101974c3cbe3SAl Viro 10200d2e2a1dSEric Paris audit_tree_group = fsnotify_alloc_group(&audit_tree_ops); 102128a3a7ebSEric Paris if (IS_ERR(audit_tree_group)) 102228a3a7ebSEric Paris audit_panic("cannot initialize fsnotify group for rectree watches"); 102374c3cbe3SAl Viro 102474c3cbe3SAl Viro for (i = 0; i < HASH_SIZE; i++) 102574c3cbe3SAl Viro INIT_LIST_HEAD(&chunk_hash_heads[i]); 102674c3cbe3SAl Viro 102774c3cbe3SAl Viro return 0; 102874c3cbe3SAl Viro } 102974c3cbe3SAl Viro __initcall(audit_tree_init); 1030