aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/audit_tree.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2007-07-22 08:04:18 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2007-10-21 02:37:45 -0400
commit74c3cbe33bc077ac1159cadfea608b501e100344 (patch)
tree4c4023caa4e15d19780255fa5880df3d36eb292c /kernel/audit_tree.c
parent455434d450a358ac5bcf3fc58f8913d13c544622 (diff)
[PATCH] audit: watching subtrees
New kind of audit rule predicates: "object is visible in given subtree". The part that can be sanely implemented, that is. Limitations: * if you have hardlink from outside of tree, you'd better watch it too (or just watch the object itself, obviously) * if you mount something under a watched tree, tell audit that new chunk should be added to watched subtrees * if you umount something in a watched tree and it's still mounted elsewhere, you will get matches on events happening there. New command tells audit to recalculate the trees, trimming such sources of false positives. Note that it's _not_ about path - if something mounted in several places (multiple mount, bindings, different namespaces, etc.), the match does _not_ depend on which one we are using for access. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel/audit_tree.c')
-rw-r--r--kernel/audit_tree.c903
1 files changed, 903 insertions, 0 deletions
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
new file mode 100644
index 00000000000..f4fcf58f20f
--- /dev/null
+++ b/kernel/audit_tree.c
@@ -0,0 +1,903 @@
1#include "audit.h"
2#include <linux/inotify.h>
3#include <linux/namei.h>
4#include <linux/mount.h>
5
6struct audit_tree;
7struct audit_chunk;
8
9struct audit_tree {
10 atomic_t count;
11 int goner;
12 struct audit_chunk *root;
13 struct list_head chunks;
14 struct list_head rules;
15 struct list_head list;
16 struct list_head same_root;
17 struct rcu_head head;
18 char pathname[];
19};
20
21struct audit_chunk {
22 struct list_head hash;
23 struct inotify_watch watch;
24 struct list_head trees; /* with root here */
25 int dead;
26 int count;
27 struct rcu_head head;
28 struct node {
29 struct list_head list;
30 struct audit_tree *owner;
31 unsigned index; /* index; upper bit indicates 'will prune' */
32 } owners[];
33};
34
35static LIST_HEAD(tree_list);
36static LIST_HEAD(prune_list);
37
38/*
39 * One struct chunk is attached to each inode of interest.
40 * We replace struct chunk on tagging/untagging.
41 * Rules have pointer to struct audit_tree.
42 * Rules have struct list_head rlist forming a list of rules over
43 * the same tree.
44 * References to struct chunk are collected at audit_inode{,_child}()
45 * time and used in AUDIT_TREE rule matching.
46 * These references are dropped at the same time we are calling
47 * audit_free_names(), etc.
48 *
49 * Cyclic lists galore:
50 * tree.chunks anchors chunk.owners[].list hash_lock
51 * tree.rules anchors rule.rlist audit_filter_mutex
52 * chunk.trees anchors tree.same_root hash_lock
53 * chunk.hash is a hash with middle bits of watch.inode as
54 * a hash function. RCU, hash_lock
55 *
56 * tree is refcounted; one reference for "some rules on rules_list refer to
57 * it", one for each chunk with pointer to it.
58 *
59 * chunk is refcounted by embedded inotify_watch.
60 *
61 * node.index allows to get from node.list to containing chunk.
62 * MSB of that sucker is stolen to mark taggings that we might have to
63 * revert - several operations have very unpleasant cleanup logics and
64 * that makes a difference. Some.
65 */
66
67static struct inotify_handle *rtree_ih;
68
69static struct audit_tree *alloc_tree(const char *s)
70{
71 struct audit_tree *tree;
72
73 tree = kmalloc(sizeof(struct audit_tree) + strlen(s) + 1, GFP_KERNEL);
74 if (tree) {
75 atomic_set(&tree->count, 1);
76 tree->goner = 0;
77 INIT_LIST_HEAD(&tree->chunks);
78 INIT_LIST_HEAD(&tree->rules);
79 INIT_LIST_HEAD(&tree->list);
80 INIT_LIST_HEAD(&tree->same_root);
81 tree->root = NULL;
82 strcpy(tree->pathname, s);
83 }
84 return tree;
85}
86
87static inline void get_tree(struct audit_tree *tree)
88{
89 atomic_inc(&tree->count);
90}
91
92static void __put_tree(struct rcu_head *rcu)
93{
94 struct audit_tree *tree = container_of(rcu, struct audit_tree, head);
95 kfree(tree);
96}
97
98static inline void put_tree(struct audit_tree *tree)
99{
100 if (atomic_dec_and_test(&tree->count))
101 call_rcu(&tree->head, __put_tree);
102}
103
104/* to avoid bringing the entire thing in audit.h */
105const char *audit_tree_path(struct audit_tree *tree)
106{
107 return tree->pathname;
108}
109
110static struct audit_chunk *alloc_chunk(int count)
111{
112 struct audit_chunk *chunk;
113 size_t size;
114 int i;
115
116 size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
117 chunk = kzalloc(size, GFP_KERNEL);
118 if (!chunk)
119 return NULL;
120
121 INIT_LIST_HEAD(&chunk->hash);
122 INIT_LIST_HEAD(&chunk->trees);
123 chunk->count = count;
124 for (i = 0; i < count; i++) {
125 INIT_LIST_HEAD(&chunk->owners[i].list);
126 chunk->owners[i].index = i;
127 }
128 inotify_init_watch(&chunk->watch);
129 return chunk;
130}
131
132static void __free_chunk(struct rcu_head *rcu)
133{
134 struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
135 int i;
136
137 for (i = 0; i < chunk->count; i++) {
138 if (chunk->owners[i].owner)
139 put_tree(chunk->owners[i].owner);
140 }
141 kfree(chunk);
142}
143
144static inline void free_chunk(struct audit_chunk *chunk)
145{
146 call_rcu(&chunk->head, __free_chunk);
147}
148
149void audit_put_chunk(struct audit_chunk *chunk)
150{
151 put_inotify_watch(&chunk->watch);
152}
153
154enum {HASH_SIZE = 128};
155static struct list_head chunk_hash_heads[HASH_SIZE];
156static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock);
157
158static inline struct list_head *chunk_hash(const struct inode *inode)
159{
160 unsigned long n = (unsigned long)inode / L1_CACHE_BYTES;
161 return chunk_hash_heads + n % HASH_SIZE;
162}
163
164/* hash_lock is held by caller */
165static void insert_hash(struct audit_chunk *chunk)
166{
167 struct list_head *list = chunk_hash(chunk->watch.inode);
168 list_add_rcu(&chunk->hash, list);
169}
170
171/* called under rcu_read_lock */
172struct audit_chunk *audit_tree_lookup(const struct inode *inode)
173{
174 struct list_head *list = chunk_hash(inode);
175 struct list_head *pos;
176
177 list_for_each_rcu(pos, list) {
178 struct audit_chunk *p = container_of(pos, struct audit_chunk, hash);
179 if (p->watch.inode == inode) {
180 get_inotify_watch(&p->watch);
181 return p;
182 }
183 }
184 return NULL;
185}
186
187int audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
188{
189 int n;
190 for (n = 0; n < chunk->count; n++)
191 if (chunk->owners[n].owner == tree)
192 return 1;
193 return 0;
194}
195
196/* tagging and untagging inodes with trees */
197
198static void untag_chunk(struct audit_chunk *chunk, struct node *p)
199{
200 struct audit_chunk *new;
201 struct audit_tree *owner;
202 int size = chunk->count - 1;
203 int i, j;
204
205 mutex_lock(&chunk->watch.inode->inotify_mutex);
206 if (chunk->dead) {
207 mutex_unlock(&chunk->watch.inode->inotify_mutex);
208 return;
209 }
210
211 owner = p->owner;
212
213 if (!size) {
214 chunk->dead = 1;
215 spin_lock(&hash_lock);
216 list_del_init(&chunk->trees);
217 if (owner->root == chunk)
218 owner->root = NULL;
219 list_del_init(&p->list);
220 list_del_rcu(&chunk->hash);
221 spin_unlock(&hash_lock);
222 inotify_evict_watch(&chunk->watch);
223 mutex_unlock(&chunk->watch.inode->inotify_mutex);
224 put_inotify_watch(&chunk->watch);
225 return;
226 }
227
228 new = alloc_chunk(size);
229 if (!new)
230 goto Fallback;
231 if (inotify_clone_watch(&chunk->watch, &new->watch) < 0) {
232 free_chunk(new);
233 goto Fallback;
234 }
235
236 chunk->dead = 1;
237 spin_lock(&hash_lock);
238 list_replace_init(&chunk->trees, &new->trees);
239 if (owner->root == chunk) {
240 list_del_init(&owner->same_root);
241 owner->root = NULL;
242 }
243
244 for (i = j = 0; i < size; i++, j++) {
245 struct audit_tree *s;
246 if (&chunk->owners[j] == p) {
247 list_del_init(&p->list);
248 i--;
249 continue;
250 }
251 s = chunk->owners[j].owner;
252 new->owners[i].owner = s;
253 new->owners[i].index = chunk->owners[j].index - j + i;
254 if (!s) /* result of earlier fallback */
255 continue;
256 get_tree(s);
257 list_replace_init(&chunk->owners[i].list, &new->owners[j].list);
258 }
259
260 list_replace_rcu(&chunk->hash, &new->hash);
261 list_for_each_entry(owner, &new->trees, same_root)
262 owner->root = new;
263 spin_unlock(&hash_lock);
264 inotify_evict_watch(&chunk->watch);
265 mutex_unlock(&chunk->watch.inode->inotify_mutex);
266 put_inotify_watch(&chunk->watch);
267 return;
268
269Fallback:
270 // do the best we can
271 spin_lock(&hash_lock);
272 if (owner->root == chunk) {
273 list_del_init(&owner->same_root);
274 owner->root = NULL;
275 }
276 list_del_init(&p->list);
277 p->owner = NULL;
278 put_tree(owner);
279 spin_unlock(&hash_lock);
280 mutex_unlock(&chunk->watch.inode->inotify_mutex);
281}
282
283static int create_chunk(struct inode *inode, struct audit_tree *tree)
284{
285 struct audit_chunk *chunk = alloc_chunk(1);
286 if (!chunk)
287 return -ENOMEM;
288
289 if (inotify_add_watch(rtree_ih, &chunk->watch, inode, IN_IGNORED | IN_DELETE_SELF) < 0) {
290 free_chunk(chunk);
291 return -ENOSPC;
292 }
293
294 mutex_lock(&inode->inotify_mutex);
295 spin_lock(&hash_lock);
296 if (tree->goner) {
297 spin_unlock(&hash_lock);
298 chunk->dead = 1;
299 inotify_evict_watch(&chunk->watch);
300 mutex_unlock(&inode->inotify_mutex);
301 put_inotify_watch(&chunk->watch);
302 return 0;
303 }
304 chunk->owners[0].index = (1U << 31);
305 chunk->owners[0].owner = tree;
306 get_tree(tree);
307 list_add(&chunk->owners[0].list, &tree->chunks);
308 if (!tree->root) {
309 tree->root = chunk;
310 list_add(&tree->same_root, &chunk->trees);
311 }
312 insert_hash(chunk);
313 spin_unlock(&hash_lock);
314 mutex_unlock(&inode->inotify_mutex);
315 return 0;
316}
317
318/* the first tagged inode becomes root of tree */
319static int tag_chunk(struct inode *inode, struct audit_tree *tree)
320{
321 struct inotify_watch *watch;
322 struct audit_tree *owner;
323 struct audit_chunk *chunk, *old;
324 struct node *p;
325 int n;
326
327 if (inotify_find_watch(rtree_ih, inode, &watch) < 0)
328 return create_chunk(inode, tree);
329
330 old = container_of(watch, struct audit_chunk, watch);
331
332 /* are we already there? */
333 spin_lock(&hash_lock);
334 for (n = 0; n < old->count; n++) {
335 if (old->owners[n].owner == tree) {
336 spin_unlock(&hash_lock);
337 put_inotify_watch(watch);
338 return 0;
339 }
340 }
341 spin_unlock(&hash_lock);
342
343 chunk = alloc_chunk(old->count + 1);
344 if (!chunk)
345 return -ENOMEM;
346
347 mutex_lock(&inode->inotify_mutex);
348 if (inotify_clone_watch(&old->watch, &chunk->watch) < 0) {
349 mutex_unlock(&inode->inotify_mutex);
350 free_chunk(chunk);
351 return -ENOSPC;
352 }
353 spin_lock(&hash_lock);
354 if (tree->goner) {
355 spin_unlock(&hash_lock);
356 chunk->dead = 1;
357 inotify_evict_watch(&chunk->watch);
358 mutex_unlock(&inode->inotify_mutex);
359 put_inotify_watch(&chunk->watch);
360 return 0;
361 }
362 list_replace_init(&old->trees, &chunk->trees);
363 for (n = 0, p = chunk->owners; n < old->count; n++, p++) {
364 struct audit_tree *s = old->owners[n].owner;
365 p->owner = s;
366 p->index = old->owners[n].index;
367 if (!s) /* result of fallback in untag */
368 continue;
369 get_tree(s);
370 list_replace_init(&old->owners[n].list, &p->list);
371 }
372 p->index = (chunk->count - 1) | (1U<<31);
373 p->owner = tree;
374 get_tree(tree);
375 list_add(&p->list, &tree->chunks);
376 list_replace_rcu(&old->hash, &chunk->hash);
377 list_for_each_entry(owner, &chunk->trees, same_root)
378 owner->root = chunk;
379 old->dead = 1;
380 if (!tree->root) {
381 tree->root = chunk;
382 list_add(&tree->same_root, &chunk->trees);
383 }
384 spin_unlock(&hash_lock);
385 inotify_evict_watch(&old->watch);
386 mutex_unlock(&inode->inotify_mutex);
387 put_inotify_watch(&old->watch);
388 return 0;
389}
390
391static struct audit_chunk *find_chunk(struct node *p)
392{
393 int index = p->index & ~(1U<<31);
394 p -= index;
395 return container_of(p, struct audit_chunk, owners[0]);
396}
397
398static void kill_rules(struct audit_tree *tree)
399{
400 struct audit_krule *rule, *next;
401 struct audit_entry *entry;
402 struct audit_buffer *ab;
403
404 list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
405 entry = container_of(rule, struct audit_entry, rule);
406
407 list_del_init(&rule->rlist);
408 if (rule->tree) {
409 /* not a half-baked one */
410 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
411 audit_log_format(ab, "op=remove rule dir=");
412 audit_log_untrustedstring(ab, rule->tree->pathname);
413 if (rule->filterkey) {
414 audit_log_format(ab, " key=");
415 audit_log_untrustedstring(ab, rule->filterkey);
416 } else
417 audit_log_format(ab, " key=(null)");
418 audit_log_format(ab, " list=%d res=1", rule->listnr);
419 audit_log_end(ab);
420 rule->tree = NULL;
421 list_del_rcu(&entry->list);
422 call_rcu(&entry->rcu, audit_free_rule_rcu);
423 }
424 }
425}
426
427/*
428 * finish killing struct audit_tree
429 */
430static void prune_one(struct audit_tree *victim)
431{
432 spin_lock(&hash_lock);
433 while (!list_empty(&victim->chunks)) {
434 struct node *p;
435 struct audit_chunk *chunk;
436
437 p = list_entry(victim->chunks.next, struct node, list);
438 chunk = find_chunk(p);
439 get_inotify_watch(&chunk->watch);
440 spin_unlock(&hash_lock);
441
442 untag_chunk(chunk, p);
443
444 put_inotify_watch(&chunk->watch);
445 spin_lock(&hash_lock);
446 }
447 spin_unlock(&hash_lock);
448 put_tree(victim);
449}
450
451/* trim the uncommitted chunks from tree */
452
453static void trim_marked(struct audit_tree *tree)
454{
455 struct list_head *p, *q;
456 spin_lock(&hash_lock);
457 if (tree->goner) {
458 spin_unlock(&hash_lock);
459 return;
460 }
461 /* reorder */
462 for (p = tree->chunks.next; p != &tree->chunks; p = q) {
463 struct node *node = list_entry(p, struct node, list);
464 q = p->next;
465 if (node->index & (1U<<31)) {
466 list_del_init(p);
467 list_add(p, &tree->chunks);
468 }
469 }
470
471 while (!list_empty(&tree->chunks)) {
472 struct node *node;
473 struct audit_chunk *chunk;
474
475 node = list_entry(tree->chunks.next, struct node, list);
476
477 /* have we run out of marked? */
478 if (!(node->index & (1U<<31)))
479 break;
480
481 chunk = find_chunk(node);
482 get_inotify_watch(&chunk->watch);
483 spin_unlock(&hash_lock);
484
485 untag_chunk(chunk, node);
486
487 put_inotify_watch(&chunk->watch);
488 spin_lock(&hash_lock);
489 }
490 if (!tree->root && !tree->goner) {
491 tree->goner = 1;
492 spin_unlock(&hash_lock);
493 mutex_lock(&audit_filter_mutex);
494 kill_rules(tree);
495 list_del_init(&tree->list);
496 mutex_unlock(&audit_filter_mutex);
497 prune_one(tree);
498 } else {
499 spin_unlock(&hash_lock);
500 }
501}
502
503/* called with audit_filter_mutex */
504int audit_remove_tree_rule(struct audit_krule *rule)
505{
506 struct audit_tree *tree;
507 tree = rule->tree;
508 if (tree) {
509 spin_lock(&hash_lock);
510 list_del_init(&rule->rlist);
511 if (list_empty(&tree->rules) && !tree->goner) {
512 tree->root = NULL;
513 list_del_init(&tree->same_root);
514 tree->goner = 1;
515 list_move(&tree->list, &prune_list);
516 rule->tree = NULL;
517 spin_unlock(&hash_lock);
518 audit_schedule_prune();
519 return 1;
520 }
521 rule->tree = NULL;
522 spin_unlock(&hash_lock);
523 return 1;
524 }
525 return 0;
526}
527
528void audit_trim_trees(void)
529{
530 struct list_head cursor;
531
532 mutex_lock(&audit_filter_mutex);
533 list_add(&cursor, &tree_list);
534 while (cursor.next != &tree_list) {
535 struct audit_tree *tree;
536 struct nameidata nd;
537 struct vfsmount *root_mnt;
538 struct node *node;
539 struct list_head list;
540 int err;
541
542 tree = container_of(cursor.next, struct audit_tree, list);
543 get_tree(tree);
544 list_del(&cursor);
545 list_add(&cursor, &tree->list);
546 mutex_unlock(&audit_filter_mutex);
547
548 err = path_lookup(tree->pathname, 0, &nd);
549 if (err)
550 goto skip_it;
551
552 root_mnt = collect_mounts(nd.mnt, nd.dentry);
553 path_release(&nd);
554 if (!root_mnt)
555 goto skip_it;
556
557 list_add_tail(&list, &root_mnt->mnt_list);
558 spin_lock(&hash_lock);
559 list_for_each_entry(node, &tree->chunks, list) {
560 struct audit_chunk *chunk = find_chunk(node);
561 struct inode *inode = chunk->watch.inode;
562 struct vfsmount *mnt;
563 node->index |= 1U<<31;
564 list_for_each_entry(mnt, &list, mnt_list) {
565 if (mnt->mnt_root->d_inode == inode) {
566 node->index &= ~(1U<<31);
567 break;
568 }
569 }
570 }
571 spin_unlock(&hash_lock);
572 trim_marked(tree);
573 put_tree(tree);
574 list_del_init(&list);
575 drop_collected_mounts(root_mnt);
576skip_it:
577 mutex_lock(&audit_filter_mutex);
578 }
579 list_del(&cursor);
580 mutex_unlock(&audit_filter_mutex);
581}
582
583static int is_under(struct vfsmount *mnt, struct dentry *dentry,
584 struct nameidata *nd)
585{
586 if (mnt != nd->mnt) {
587 for (;;) {
588 if (mnt->mnt_parent == mnt)
589 return 0;
590 if (mnt->mnt_parent == nd->mnt)
591 break;
592 mnt = mnt->mnt_parent;
593 }
594 dentry = mnt->mnt_mountpoint;
595 }
596 return is_subdir(dentry, nd->dentry);
597}
598
599int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
600{
601
602 if (pathname[0] != '/' ||
603 rule->listnr != AUDIT_FILTER_EXIT ||
604 op & ~AUDIT_EQUAL ||
605 rule->inode_f || rule->watch || rule->tree)
606 return -EINVAL;
607 rule->tree = alloc_tree(pathname);
608 if (!rule->tree)
609 return -ENOMEM;
610 return 0;
611}
612
613void audit_put_tree(struct audit_tree *tree)
614{
615 put_tree(tree);
616}
617
618/* called with audit_filter_mutex */
619int audit_add_tree_rule(struct audit_krule *rule)
620{
621 struct audit_tree *seed = rule->tree, *tree;
622 struct nameidata nd;
623 struct vfsmount *mnt, *p;
624 struct list_head list;
625 int err;
626
627 list_for_each_entry(tree, &tree_list, list) {
628 if (!strcmp(seed->pathname, tree->pathname)) {
629 put_tree(seed);
630 rule->tree = tree;
631 list_add(&rule->rlist, &tree->rules);
632 return 0;
633 }
634 }
635 tree = seed;
636 list_add(&tree->list, &tree_list);
637 list_add(&rule->rlist, &tree->rules);
638 /* do not set rule->tree yet */
639 mutex_unlock(&audit_filter_mutex);
640
641 err = path_lookup(tree->pathname, 0, &nd);
642 if (err)
643 goto Err;
644 mnt = collect_mounts(nd.mnt, nd.dentry);
645 path_release(&nd);
646 if (!mnt) {
647 err = -ENOMEM;
648 goto Err;
649 }
650 list_add_tail(&list, &mnt->mnt_list);
651
652 get_tree(tree);
653 list_for_each_entry(p, &list, mnt_list) {
654 err = tag_chunk(p->mnt_root->d_inode, tree);
655 if (err)
656 break;
657 }
658
659 list_del(&list);
660 drop_collected_mounts(mnt);
661
662 if (!err) {
663 struct node *node;
664 spin_lock(&hash_lock);
665 list_for_each_entry(node, &tree->chunks, list)
666 node->index &= ~(1U<<31);
667 spin_unlock(&hash_lock);
668 } else {
669 trim_marked(tree);
670 goto Err;
671 }
672
673 mutex_lock(&audit_filter_mutex);
674 if (list_empty(&rule->rlist)) {
675 put_tree(tree);
676 return -ENOENT;
677 }
678 rule->tree = tree;
679 put_tree(tree);
680
681 return 0;
682Err:
683 mutex_lock(&audit_filter_mutex);
684 list_del_init(&tree->list);
685 list_del_init(&tree->rules);
686 put_tree(tree);
687 return err;
688}
689
690int audit_tag_tree(char *old, char *new)
691{
692 struct list_head cursor, barrier;
693 int failed = 0;
694 struct nameidata nd;
695 struct vfsmount *tagged;
696 struct list_head list;
697 struct vfsmount *mnt;
698 struct dentry *dentry;
699 int err;
700
701 err = path_lookup(new, 0, &nd);
702 if (err)
703 return err;
704 tagged = collect_mounts(nd.mnt, nd.dentry);
705 path_release(&nd);
706 if (!tagged)
707 return -ENOMEM;
708
709 err = path_lookup(old, 0, &nd);
710 if (err) {
711 drop_collected_mounts(tagged);
712 return err;
713 }
714 mnt = mntget(nd.mnt);
715 dentry = dget(nd.dentry);
716 path_release(&nd);
717
718 if (dentry == tagged->mnt_root && dentry == mnt->mnt_root)
719 follow_up(&mnt, &dentry);
720
721 list_add_tail(&list, &tagged->mnt_list);
722
723 mutex_lock(&audit_filter_mutex);
724 list_add(&barrier, &tree_list);
725 list_add(&cursor, &barrier);
726
727 while (cursor.next != &tree_list) {
728 struct audit_tree *tree;
729 struct vfsmount *p;
730
731 tree = container_of(cursor.next, struct audit_tree, list);
732 get_tree(tree);
733 list_del(&cursor);
734 list_add(&cursor, &tree->list);
735 mutex_unlock(&audit_filter_mutex);
736
737 err = path_lookup(tree->pathname, 0, &nd);
738 if (err) {
739 put_tree(tree);
740 mutex_lock(&audit_filter_mutex);
741 continue;
742 }
743
744 spin_lock(&vfsmount_lock);
745 if (!is_under(mnt, dentry, &nd)) {
746 spin_unlock(&vfsmount_lock);
747 path_release(&nd);
748 put_tree(tree);
749 mutex_lock(&audit_filter_mutex);
750 continue;
751 }
752 spin_unlock(&vfsmount_lock);
753 path_release(&nd);
754
755 list_for_each_entry(p, &list, mnt_list) {
756 failed = tag_chunk(p->mnt_root->d_inode, tree);
757 if (failed)
758 break;
759 }
760
761 if (failed) {
762 put_tree(tree);
763 mutex_lock(&audit_filter_mutex);
764 break;
765 }
766
767 mutex_lock(&audit_filter_mutex);
768 spin_lock(&hash_lock);
769 if (!tree->goner) {
770 list_del(&tree->list);
771 list_add(&tree->list, &tree_list);
772 }
773 spin_unlock(&hash_lock);
774 put_tree(tree);
775 }
776
777 while (barrier.prev != &tree_list) {
778 struct audit_tree *tree;
779
780 tree = container_of(barrier.prev, struct audit_tree, list);
781 get_tree(tree);
782 list_del(&tree->list);
783 list_add(&tree->list, &barrier);
784 mutex_unlock(&audit_filter_mutex);
785
786 if (!failed) {
787 struct node *node;
788 spin_lock(&hash_lock);
789 list_for_each_entry(node, &tree->chunks, list)
790 node->index &= ~(1U<<31);
791 spin_unlock(&hash_lock);
792 } else {
793 trim_marked(tree);
794 }
795
796 put_tree(tree);
797 mutex_lock(&audit_filter_mutex);
798 }
799 list_del(&barrier);
800 list_del(&cursor);
801 list_del(&list);
802 mutex_unlock(&audit_filter_mutex);
803 dput(dentry);
804 mntput(mnt);
805 drop_collected_mounts(tagged);
806 return failed;
807}
808
809/*
810 * That gets run when evict_chunk() ends up needing to kill audit_tree.
811 * Runs from a separate thread, with audit_cmd_mutex held.
812 */
813void audit_prune_trees(void)
814{
815 mutex_lock(&audit_filter_mutex);
816
817 while (!list_empty(&prune_list)) {
818 struct audit_tree *victim;
819
820 victim = list_entry(prune_list.next, struct audit_tree, list);
821 list_del_init(&victim->list);
822
823 mutex_unlock(&audit_filter_mutex);
824
825 prune_one(victim);
826
827 mutex_lock(&audit_filter_mutex);
828 }
829
830 mutex_unlock(&audit_filter_mutex);
831}
832
833/*
834 * Here comes the stuff asynchronous to auditctl operations
835 */
836
837/* inode->inotify_mutex is locked */
838static void evict_chunk(struct audit_chunk *chunk)
839{
840 struct audit_tree *owner;
841 int n;
842
843 if (chunk->dead)
844 return;
845
846 chunk->dead = 1;
847 mutex_lock(&audit_filter_mutex);
848 spin_lock(&hash_lock);
849 while (!list_empty(&chunk->trees)) {
850 owner = list_entry(chunk->trees.next,
851 struct audit_tree, same_root);
852 owner->goner = 1;
853 owner->root = NULL;
854 list_del_init(&owner->same_root);
855 spin_unlock(&hash_lock);
856 kill_rules(owner);
857 list_move(&owner->list, &prune_list);
858 audit_schedule_prune();
859 spin_lock(&hash_lock);
860 }
861 list_del_rcu(&chunk->hash);
862 for (n = 0; n < chunk->count; n++)
863 list_del_init(&chunk->owners[n].list);
864 spin_unlock(&hash_lock);
865 mutex_unlock(&audit_filter_mutex);
866}
867
868static void handle_event(struct inotify_watch *watch, u32 wd, u32 mask,
869 u32 cookie, const char *dname, struct inode *inode)
870{
871 struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
872
873 if (mask & IN_IGNORED) {
874 evict_chunk(chunk);
875 put_inotify_watch(watch);
876 }
877}
878
879static void destroy_watch(struct inotify_watch *watch)
880{
881 struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
882 free_chunk(chunk);
883}
884
885static const struct inotify_operations rtree_inotify_ops = {
886 .handle_event = handle_event,
887 .destroy_watch = destroy_watch,
888};
889
890static int __init audit_tree_init(void)
891{
892 int i;
893
894 rtree_ih = inotify_init(&rtree_inotify_ops);
895 if (IS_ERR(rtree_ih))
896 audit_panic("cannot initialize inotify handle for rectree watches");
897
898 for (i = 0; i < HASH_SIZE; i++)
899 INIT_LIST_HEAD(&chunk_hash_heads[i]);
900
901 return 0;
902}
903__initcall(audit_tree_init);