Commit 74c3cbe33bc077ac1159cadfea608b501e100344

Authored by Al Viro
1 parent 455434d450

[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>

Showing 10 changed files with 1310 additions and 10 deletions Side-by-side Diff

... ... @@ -38,7 +38,7 @@
38 38 EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
39 39  
40 40 __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock);
41   -static __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
  41 +__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
42 42  
43 43 EXPORT_SYMBOL(dcache_lock);
44 44  
include/linux/audit.h
... ... @@ -63,6 +63,8 @@
63 63 #define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */
64 64 #define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */
65 65 #define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */
  66 +#define AUDIT_TRIM 1014 /* Trim junk from watched tree */
  67 +#define AUDIT_MAKE_EQUIV 1015 /* Append to watched tree */
66 68 #define AUDIT_TTY_GET 1016 /* Get TTY auditing status */
67 69 #define AUDIT_TTY_SET 1017 /* Set TTY auditing status */
68 70  
... ... @@ -203,6 +205,7 @@
203 205 #define AUDIT_SUCCESS 104 /* exit >= 0; value ignored */
204 206 #define AUDIT_WATCH 105
205 207 #define AUDIT_PERM 106
  208 +#define AUDIT_DIR 107
206 209  
207 210 #define AUDIT_ARG0 200
208 211 #define AUDIT_ARG1 (AUDIT_ARG0+1)
include/linux/dcache.h
... ... @@ -178,6 +178,7 @@
178 178 #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */
179 179  
180 180 extern spinlock_t dcache_lock;
  181 +extern seqlock_t rename_lock;
181 182  
182 183 /**
183 184 * d_drop - drop a dentry
... ... @@ -234,6 +234,10 @@
234 234 such as SELinux. To use audit's filesystem watch feature, please
235 235 ensure that INOTIFY is configured.
236 236  
  237 +config AUDIT_TREE
  238 + def_bool y
  239 + depends on AUDITSYSCALL && INOTIFY
  240 +
237 241 config IKCONFIG
238 242 tristate "Kernel .config support"
239 243 ---help---
... ... @@ -46,6 +46,7 @@
46 46 obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
47 47 obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
48 48 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
  49 +obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
49 50 obj-$(CONFIG_KPROBES) += kprobes.o
50 51 obj-$(CONFIG_SYSFS) += ksysfs.o
51 52 obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
... ... @@ -468,6 +468,21 @@
468 468 return 0;
469 469 }
470 470  
  471 +#ifdef CONFIG_AUDIT_TREE
  472 +static int prune_tree_thread(void *unused)
  473 +{
  474 + mutex_lock(&audit_cmd_mutex);
  475 + audit_prune_trees();
  476 + mutex_unlock(&audit_cmd_mutex);
  477 + return 0;
  478 +}
  479 +
  480 +void audit_schedule_prune(void)
  481 +{
  482 + kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
  483 +}
  484 +#endif
  485 +
471 486 struct sk_buff *audit_make_reply(int pid, int seq, int type, int done,
472 487 int multi, void *payload, int size)
473 488 {
... ... @@ -540,6 +555,8 @@
540 555 case AUDIT_SIGNAL_INFO:
541 556 case AUDIT_TTY_GET:
542 557 case AUDIT_TTY_SET:
  558 + case AUDIT_TRIM:
  559 + case AUDIT_MAKE_EQUIV:
543 560 if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
544 561 err = -EPERM;
545 562 break;
... ... @@ -756,6 +773,76 @@
756 773 uid, seq, data, nlmsg_len(nlh),
757 774 loginuid, sid);
758 775 break;
  776 + case AUDIT_TRIM:
  777 + audit_trim_trees();
  778 + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
  779 + if (!ab)
  780 + break;
  781 + audit_log_format(ab, "auid=%u", loginuid);
  782 + if (sid) {
  783 + u32 len;
  784 + ctx = NULL;
  785 + if (selinux_sid_to_string(sid, &ctx, &len))
  786 + audit_log_format(ab, " ssid=%u", sid);
  787 + else
  788 + audit_log_format(ab, " subj=%s", ctx);
  789 + kfree(ctx);
  790 + }
  791 + audit_log_format(ab, " op=trim res=1");
  792 + audit_log_end(ab);
  793 + break;
  794 + case AUDIT_MAKE_EQUIV: {
  795 + void *bufp = data;
  796 + u32 sizes[2];
  797 + size_t len = nlmsg_len(nlh);
  798 + char *old, *new;
  799 +
  800 + err = -EINVAL;
  801 + if (len < 2 * sizeof(u32))
  802 + break;
  803 + memcpy(sizes, bufp, 2 * sizeof(u32));
  804 + bufp += 2 * sizeof(u32);
  805 + len -= 2 * sizeof(u32);
  806 + old = audit_unpack_string(&bufp, &len, sizes[0]);
  807 + if (IS_ERR(old)) {
  808 + err = PTR_ERR(old);
  809 + break;
  810 + }
  811 + new = audit_unpack_string(&bufp, &len, sizes[1]);
  812 + if (IS_ERR(new)) {
  813 + err = PTR_ERR(new);
  814 + kfree(old);
  815 + break;
  816 + }
  817 + /* OK, here comes... */
  818 + err = audit_tag_tree(old, new);
  819 +
  820 + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
  821 + if (!ab) {
  822 + kfree(old);
  823 + kfree(new);
  824 + break;
  825 + }
  826 + audit_log_format(ab, "auid=%u", loginuid);
  827 + if (sid) {
  828 + u32 len;
  829 + ctx = NULL;
  830 + if (selinux_sid_to_string(sid, &ctx, &len))
  831 + audit_log_format(ab, " ssid=%u", sid);
  832 + else
  833 + audit_log_format(ab, " subj=%s", ctx);
  834 + kfree(ctx);
  835 + }
  836 + audit_log_format(ab, " op=make_equiv old=");
  837 + audit_log_untrustedstring(ab, old);
  838 + audit_log_format(ab, " new=");
  839 + audit_log_untrustedstring(ab, new);
  840 + audit_log_format(ab, " res=%d", !err);
  841 + audit_log_end(ab);
  842 + kfree(old);
  843 + kfree(new);
  844 + break;
  845 + }
759 846 case AUDIT_SIGNAL_INFO:
760 847 err = selinux_sid_to_string(audit_sig_sid, &ctx, &len);
761 848 if (err)
... ... @@ -73,6 +73,9 @@
73 73 struct selinux_audit_rule *se_rule;
74 74 };
75 75  
  76 +struct audit_tree;
  77 +struct audit_chunk;
  78 +
76 79 struct audit_krule {
77 80 int vers_ops;
78 81 u32 flags;
... ... @@ -86,7 +89,8 @@
86 89 struct audit_field *arch_f; /* quick access to arch field */
87 90 struct audit_field *inode_f; /* quick access to an inode field */
88 91 struct audit_watch *watch; /* associated watch */
89   - struct list_head rlist; /* entry in audit_watch.rules list */
  92 + struct audit_tree *tree; /* associated watched tree */
  93 + struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
90 94 };
91 95  
92 96 struct audit_entry {
... ... @@ -129,6 +133,34 @@
129 133 extern void audit_handle_ievent(struct inotify_watch *, u32, u32, u32,
130 134 const char *, struct inode *);
131 135 extern int selinux_audit_rule_update(void);
  136 +
  137 +extern struct mutex audit_filter_mutex;
  138 +extern void audit_free_rule_rcu(struct rcu_head *);
  139 +
  140 +#ifdef CONFIG_AUDIT_TREE
  141 +extern struct audit_chunk *audit_tree_lookup(const struct inode *);
  142 +extern void audit_put_chunk(struct audit_chunk *);
  143 +extern int audit_tree_match(struct audit_chunk *, struct audit_tree *);
  144 +extern int audit_make_tree(struct audit_krule *, char *, u32);
  145 +extern int audit_add_tree_rule(struct audit_krule *);
  146 +extern int audit_remove_tree_rule(struct audit_krule *);
  147 +extern void audit_trim_trees(void);
  148 +extern int audit_tag_tree(char *old, char *new);
  149 +extern void audit_schedule_prune(void);
  150 +extern void audit_prune_trees(void);
  151 +extern const char *audit_tree_path(struct audit_tree *);
  152 +extern void audit_put_tree(struct audit_tree *);
  153 +#else
  154 +#define audit_remove_tree_rule(rule) BUG()
  155 +#define audit_add_tree_rule(rule) -EINVAL
  156 +#define audit_make_tree(rule, str, op) -EINVAL
  157 +#define audit_trim_trees() (void)0
  158 +#define audit_put_tree(tree) (void)0
  159 +#define audit_tag_tree(old, new) -EINVAL
  160 +#define audit_tree_path(rule) "" /* never called */
  161 +#endif
  162 +
  163 +extern char *audit_unpack_string(void **, size_t *, size_t);
132 164  
133 165 #ifdef CONFIG_AUDITSYSCALL
134 166 extern int __audit_signal_info(int sig, struct task_struct *t);
  1 +#include "audit.h"
  2 +#include <linux/inotify.h>
  3 +#include <linux/namei.h>
  4 +#include <linux/mount.h>
  5 +
  6 +struct audit_tree;
  7 +struct audit_chunk;
  8 +
  9 +struct 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 +
  21 +struct 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 +
  35 +static LIST_HEAD(tree_list);
  36 +static 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 +
  67 +static struct inotify_handle *rtree_ih;
  68 +
  69 +static 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 +
  87 +static inline void get_tree(struct audit_tree *tree)
  88 +{
  89 + atomic_inc(&tree->count);
  90 +}
  91 +
  92 +static 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 +
  98 +static 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 */
  105 +const char *audit_tree_path(struct audit_tree *tree)
  106 +{
  107 + return tree->pathname;
  108 +}
  109 +
  110 +static 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 +
  132 +static 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 +
  144 +static inline void free_chunk(struct audit_chunk *chunk)
  145 +{
  146 + call_rcu(&chunk->head, __free_chunk);
  147 +}
  148 +
  149 +void audit_put_chunk(struct audit_chunk *chunk)
  150 +{
  151 + put_inotify_watch(&chunk->watch);
  152 +}
  153 +
  154 +enum {HASH_SIZE = 128};
  155 +static struct list_head chunk_hash_heads[HASH_SIZE];
  156 +static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock);
  157 +
  158 +static 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 */
  165 +static 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 */
  172 +struct 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 +
  187 +int 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 +
  198 +static 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 +
  269 +Fallback:
  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 +
  283 +static 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 */
  319 +static 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 +
  391 +static 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 +
  398 +static 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 + */
  430 +static 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 +
  453 +static 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 */
  504 +int 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 +
  528 +void 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);
  576 +skip_it:
  577 + mutex_lock(&audit_filter_mutex);
  578 + }
  579 + list_del(&cursor);
  580 + mutex_unlock(&audit_filter_mutex);
  581 +}
  582 +
  583 +static 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 +
  599 +int 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 +
  613 +void audit_put_tree(struct audit_tree *tree)
  614 +{
  615 + put_tree(tree);
  616 +}
  617 +
  618 +/* called with audit_filter_mutex */
  619 +int 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;
  682 +Err:
  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 +
  690 +int 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 + */
  813 +void 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 */
  838 +static 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 +
  868 +static 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 +
  879 +static 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 +
  885 +static const struct inotify_operations rtree_inotify_ops = {
  886 + .handle_event = handle_event,
  887 + .destroy_watch = destroy_watch,
  888 +};
  889 +
  890 +static 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);
kernel/auditfilter.c
... ... @@ -87,7 +87,7 @@
87 87 #endif
88 88 };
89 89  
90   -static DEFINE_MUTEX(audit_filter_mutex);
  90 +DEFINE_MUTEX(audit_filter_mutex);
91 91  
92 92 /* Inotify handle */
93 93 extern struct inotify_handle *audit_ih;
... ... @@ -145,7 +145,7 @@
145 145 kfree(e);
146 146 }
147 147  
148   -static inline void audit_free_rule_rcu(struct rcu_head *head)
  148 +void audit_free_rule_rcu(struct rcu_head *head)
149 149 {
150 150 struct audit_entry *e = container_of(head, struct audit_entry, rcu);
151 151 audit_free_rule(e);
... ... @@ -217,7 +217,7 @@
217 217  
218 218 /* Unpack a filter field's string representation from user-space
219 219 * buffer. */
220   -static char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
  220 +char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
221 221 {
222 222 char *str;
223 223  
... ... @@ -247,7 +247,7 @@
247 247 struct audit_field *f)
248 248 {
249 249 if (krule->listnr != AUDIT_FILTER_EXIT ||
250   - krule->watch || krule->inode_f)
  250 + krule->watch || krule->inode_f || krule->tree)
251 251 return -EINVAL;
252 252  
253 253 krule->inode_f = f;
... ... @@ -266,7 +266,7 @@
266 266 if (path[0] != '/' || path[len-1] == '/' ||
267 267 krule->listnr != AUDIT_FILTER_EXIT ||
268 268 op & ~AUDIT_EQUAL ||
269   - krule->inode_f || krule->watch) /* 1 inode # per rule, for hash */
  269 + krule->inode_f || krule->watch || krule->tree)
270 270 return -EINVAL;
271 271  
272 272 watch = audit_init_watch(path);
... ... @@ -622,6 +622,17 @@
622 622 goto exit_free;
623 623 }
624 624 break;
  625 + case AUDIT_DIR:
  626 + str = audit_unpack_string(&bufp, &remain, f->val);
  627 + if (IS_ERR(str))
  628 + goto exit_free;
  629 + entry->rule.buflen += f->val;
  630 +
  631 + err = audit_make_tree(&entry->rule, str, f->op);
  632 + kfree(str);
  633 + if (err)
  634 + goto exit_free;
  635 + break;
625 636 case AUDIT_INODE:
626 637 err = audit_to_inode(&entry->rule, f);
627 638 if (err)
... ... @@ -668,7 +679,7 @@
668 679 }
669 680  
670 681 /* Pack a filter field's string representation into data block. */
671   -static inline size_t audit_pack_string(void **bufp, char *str)
  682 +static inline size_t audit_pack_string(void **bufp, const char *str)
672 683 {
673 684 size_t len = strlen(str);
674 685  
... ... @@ -747,6 +758,11 @@
747 758 data->buflen += data->values[i] =
748 759 audit_pack_string(&bufp, krule->watch->path);
749 760 break;
  761 + case AUDIT_DIR:
  762 + data->buflen += data->values[i] =
  763 + audit_pack_string(&bufp,
  764 + audit_tree_path(krule->tree));
  765 + break;
750 766 case AUDIT_FILTERKEY:
751 767 data->buflen += data->values[i] =
752 768 audit_pack_string(&bufp, krule->filterkey);
... ... @@ -795,6 +811,11 @@
795 811 if (strcmp(a->watch->path, b->watch->path))
796 812 return 1;
797 813 break;
  814 + case AUDIT_DIR:
  815 + if (strcmp(audit_tree_path(a->tree),
  816 + audit_tree_path(b->tree)))
  817 + return 1;
  818 + break;
798 819 case AUDIT_FILTERKEY:
799 820 /* both filterkeys exist based on above type compare */
800 821 if (strcmp(a->filterkey, b->filterkey))
... ... @@ -897,6 +918,14 @@
897 918 new->inode_f = old->inode_f;
898 919 new->watch = NULL;
899 920 new->field_count = old->field_count;
  921 + /*
  922 + * note that we are OK with not refcounting here; audit_match_tree()
  923 + * never dereferences tree and we can't get false positives there
  924 + * since we'd have to have rule gone from the list *and* removed
  925 + * before the chunks found by lookup had been allocated, i.e. before
  926 + * the beginning of list scan.
  927 + */
  928 + new->tree = old->tree;
900 929 memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
901 930  
902 931 /* deep copy this information, updating the se_rule fields, because
... ... @@ -1217,6 +1246,7 @@
1217 1246 struct audit_entry *e;
1218 1247 struct audit_field *inode_f = entry->rule.inode_f;
1219 1248 struct audit_watch *watch = entry->rule.watch;
  1249 + struct audit_tree *tree = entry->rule.tree;
1220 1250 struct nameidata *ndp = NULL, *ndw = NULL;
1221 1251 int h, err;
1222 1252 #ifdef CONFIG_AUDITSYSCALL
... ... @@ -1238,6 +1268,9 @@
1238 1268 mutex_unlock(&audit_filter_mutex);
1239 1269 if (e) {
1240 1270 err = -EEXIST;
  1271 + /* normally audit_add_tree_rule() will free it on failure */
  1272 + if (tree)
  1273 + audit_put_tree(tree);
1241 1274 goto error;
1242 1275 }
1243 1276  
... ... @@ -1259,6 +1292,13 @@
1259 1292 h = audit_hash_ino((u32)watch->ino);
1260 1293 list = &audit_inode_hash[h];
1261 1294 }
  1295 + if (tree) {
  1296 + err = audit_add_tree_rule(&entry->rule);
  1297 + if (err) {
  1298 + mutex_unlock(&audit_filter_mutex);
  1299 + goto error;
  1300 + }
  1301 + }
1262 1302  
1263 1303 if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
1264 1304 list_add_rcu(&entry->list, list);
... ... @@ -1292,6 +1332,7 @@
1292 1332 struct audit_entry *e;
1293 1333 struct audit_field *inode_f = entry->rule.inode_f;
1294 1334 struct audit_watch *watch, *tmp_watch = entry->rule.watch;
  1335 + struct audit_tree *tree = entry->rule.tree;
1295 1336 LIST_HEAD(inotify_list);
1296 1337 int h, ret = 0;
1297 1338 #ifdef CONFIG_AUDITSYSCALL
... ... @@ -1336,6 +1377,9 @@
1336 1377 }
1337 1378 }
1338 1379  
  1380 + if (e->rule.tree)
  1381 + audit_remove_tree_rule(&e->rule);
  1382 +
1339 1383 list_del_rcu(&e->list);
1340 1384 call_rcu(&e->rcu, audit_free_rule_rcu);
1341 1385  
... ... @@ -1354,6 +1398,8 @@
1354 1398 out:
1355 1399 if (tmp_watch)
1356 1400 audit_put_watch(tmp_watch); /* match initial get */
  1401 + if (tree)
  1402 + audit_put_tree(tree); /* that's the temporary one */
1357 1403  
1358 1404 return ret;
1359 1405 }
... ... @@ -1737,6 +1783,7 @@
1737 1783 {
1738 1784 struct audit_entry *entry, *n, *nentry;
1739 1785 struct audit_watch *watch;
  1786 + struct audit_tree *tree;
1740 1787 int i, err = 0;
1741 1788  
1742 1789 /* audit_filter_mutex synchronizes the writers */
... ... @@ -1748,6 +1795,7 @@
1748 1795 continue;
1749 1796  
1750 1797 watch = entry->rule.watch;
  1798 + tree = entry->rule.tree;
1751 1799 nentry = audit_dupe_rule(&entry->rule, watch);
1752 1800 if (unlikely(IS_ERR(nentry))) {
1753 1801 /* save the first error encountered for the
... ... @@ -1763,7 +1811,9 @@
1763 1811 list_add(&nentry->rule.rlist,
1764 1812 &watch->rules);
1765 1813 list_del(&entry->rule.rlist);
1766   - }
  1814 + } else if (tree)
  1815 + list_replace_init(&entry->rule.rlist,
  1816 + &nentry->rule.rlist);
1767 1817 list_replace_rcu(&entry->list, &nentry->list);
1768 1818 }
1769 1819 call_rcu(&entry->rcu, audit_free_rule_rcu);
... ... @@ -65,6 +65,7 @@
65 65 #include <linux/binfmts.h>
66 66 #include <linux/highmem.h>
67 67 #include <linux/syscalls.h>
  68 +#include <linux/inotify.h>
68 69  
69 70 #include "audit.h"
70 71  
... ... @@ -179,6 +180,11 @@
179 180 int pid_count;
180 181 };
181 182  
  183 +struct audit_tree_refs {
  184 + struct audit_tree_refs *next;
  185 + struct audit_chunk *c[31];
  186 +};
  187 +
182 188 /* The per-task audit context. */
183 189 struct audit_context {
184 190 int dummy; /* must be the first element */
... ... @@ -211,6 +217,9 @@
211 217 pid_t target_pid;
212 218 u32 target_sid;
213 219  
  220 + struct audit_tree_refs *trees, *first_trees;
  221 + int tree_count;
  222 +
214 223 #if AUDIT_DEBUG
215 224 int put_count;
216 225 int ino_count;
... ... @@ -265,6 +274,117 @@
265 274 }
266 275 }
267 276  
  277 +/*
  278 + * We keep a linked list of fixed-sized (31 pointer) arrays of audit_chunk *;
  279 + * ->first_trees points to its beginning, ->trees - to the current end of data.
  280 + * ->tree_count is the number of free entries in array pointed to by ->trees.
  281 + * Original condition is (NULL, NULL, 0); as soon as it grows we never revert to NULL,
  282 + * "empty" becomes (p, p, 31) afterwards. We don't shrink the list (and seriously,
  283 + * it's going to remain 1-element for almost any setup) until we free context itself.
  284 + * References in it _are_ dropped - at the same time we free/drop aux stuff.
  285 + */
  286 +
  287 +#ifdef CONFIG_AUDIT_TREE
  288 +static int put_tree_ref(struct audit_context *ctx, struct audit_chunk *chunk)
  289 +{
  290 + struct audit_tree_refs *p = ctx->trees;
  291 + int left = ctx->tree_count;
  292 + if (likely(left)) {
  293 + p->c[--left] = chunk;
  294 + ctx->tree_count = left;
  295 + return 1;
  296 + }
  297 + if (!p)
  298 + return 0;
  299 + p = p->next;
  300 + if (p) {
  301 + p->c[30] = chunk;
  302 + ctx->trees = p;
  303 + ctx->tree_count = 30;
  304 + return 1;
  305 + }
  306 + return 0;
  307 +}
  308 +
  309 +static int grow_tree_refs(struct audit_context *ctx)
  310 +{
  311 + struct audit_tree_refs *p = ctx->trees;
  312 + ctx->trees = kzalloc(sizeof(struct audit_tree_refs), GFP_KERNEL);
  313 + if (!ctx->trees) {
  314 + ctx->trees = p;
  315 + return 0;
  316 + }
  317 + if (p)
  318 + p->next = ctx->trees;
  319 + else
  320 + ctx->first_trees = ctx->trees;
  321 + ctx->tree_count = 31;
  322 + return 1;
  323 +}
  324 +#endif
  325 +
  326 +static void unroll_tree_refs(struct audit_context *ctx,
  327 + struct audit_tree_refs *p, int count)
  328 +{
  329 +#ifdef CONFIG_AUDIT_TREE
  330 + struct audit_tree_refs *q;
  331 + int n;
  332 + if (!p) {
  333 + /* we started with empty chain */
  334 + p = ctx->first_trees;
  335 + count = 31;
  336 + /* if the very first allocation has failed, nothing to do */
  337 + if (!p)
  338 + return;
  339 + }
  340 + n = count;
  341 + for (q = p; q != ctx->trees; q = q->next, n = 31) {
  342 + while (n--) {
  343 + audit_put_chunk(q->c[n]);
  344 + q->c[n] = NULL;
  345 + }
  346 + }
  347 + while (n-- > ctx->tree_count) {
  348 + audit_put_chunk(q->c[n]);
  349 + q->c[n] = NULL;
  350 + }
  351 + ctx->trees = p;
  352 + ctx->tree_count = count;
  353 +#endif
  354 +}
  355 +
  356 +static void free_tree_refs(struct audit_context *ctx)
  357 +{
  358 + struct audit_tree_refs *p, *q;
  359 + for (p = ctx->first_trees; p; p = q) {
  360 + q = p->next;
  361 + kfree(p);
  362 + }
  363 +}
  364 +
  365 +static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
  366 +{
  367 +#ifdef CONFIG_AUDIT_TREE
  368 + struct audit_tree_refs *p;
  369 + int n;
  370 + if (!tree)
  371 + return 0;
  372 + /* full ones */
  373 + for (p = ctx->first_trees; p != ctx->trees; p = p->next) {
  374 + for (n = 0; n < 31; n++)
  375 + if (audit_tree_match(p->c[n], tree))
  376 + return 1;
  377 + }
  378 + /* partial */
  379 + if (p) {
  380 + for (n = ctx->tree_count; n < 31; n++)
  381 + if (audit_tree_match(p->c[n], tree))
  382 + return 1;
  383 + }
  384 +#endif
  385 + return 0;
  386 +}
  387 +
268 388 /* Determine if any context name data matches a rule's watch data */
269 389 /* Compare a task_struct with an audit_rule. Return 1 on match, 0
270 390 * otherwise. */
... ... @@ -379,6 +499,10 @@
379 499 result = (name->dev == rule->watch->dev &&
380 500 name->ino == rule->watch->ino);
381 501 break;
  502 + case AUDIT_DIR:
  503 + if (ctx)
  504 + result = match_tree_refs(ctx, rule->tree);
  505 + break;
382 506 case AUDIT_LOGINUID:
383 507 result = 0;
384 508 if (ctx)
... ... @@ -727,6 +851,8 @@
727 851 context->name_count, count);
728 852 }
729 853 audit_free_names(context);
  854 + unroll_tree_refs(context, NULL, 0);
  855 + free_tree_refs(context);
730 856 audit_free_aux(context);
731 857 kfree(context->filterkey);
732 858 kfree(context);
... ... @@ -1270,6 +1396,7 @@
1270 1396 tsk->audit_context = new_context;
1271 1397 } else {
1272 1398 audit_free_names(context);
  1399 + unroll_tree_refs(context, NULL, 0);
1273 1400 audit_free_aux(context);
1274 1401 context->aux = NULL;
1275 1402 context->aux_pids = NULL;
... ... @@ -1281,6 +1408,95 @@
1281 1408 }
1282 1409 }
1283 1410  
  1411 +static inline void handle_one(const struct inode *inode)
  1412 +{
  1413 +#ifdef CONFIG_AUDIT_TREE
  1414 + struct audit_context *context;
  1415 + struct audit_tree_refs *p;
  1416 + struct audit_chunk *chunk;
  1417 + int count;
  1418 + if (likely(list_empty(&inode->inotify_watches)))
  1419 + return;
  1420 + context = current->audit_context;
  1421 + p = context->trees;
  1422 + count = context->tree_count;
  1423 + rcu_read_lock();
  1424 + chunk = audit_tree_lookup(inode);
  1425 + rcu_read_unlock();
  1426 + if (!chunk)
  1427 + return;
  1428 + if (likely(put_tree_ref(context, chunk)))
  1429 + return;
  1430 + if (unlikely(!grow_tree_refs(context))) {
  1431 + printk(KERN_WARNING "out of memory, audit has lost a tree reference");
  1432 + audit_set_auditable(context);
  1433 + audit_put_chunk(chunk);
  1434 + unroll_tree_refs(context, p, count);
  1435 + return;
  1436 + }
  1437 + put_tree_ref(context, chunk);
  1438 +#endif
  1439 +}
  1440 +
  1441 +static void handle_path(const struct dentry *dentry)
  1442 +{
  1443 +#ifdef CONFIG_AUDIT_TREE
  1444 + struct audit_context *context;
  1445 + struct audit_tree_refs *p;
  1446 + const struct dentry *d, *parent;
  1447 + struct audit_chunk *drop;
  1448 + unsigned long seq;
  1449 + int count;
  1450 +
  1451 + context = current->audit_context;
  1452 + p = context->trees;
  1453 + count = context->tree_count;
  1454 +retry:
  1455 + drop = NULL;
  1456 + d = dentry;
  1457 + rcu_read_lock();
  1458 + seq = read_seqbegin(&rename_lock);
  1459 + for(;;) {
  1460 + struct inode *inode = d->d_inode;
  1461 + if (inode && unlikely(!list_empty(&inode->inotify_watches))) {
  1462 + struct audit_chunk *chunk;
  1463 + chunk = audit_tree_lookup(inode);
  1464 + if (chunk) {
  1465 + if (unlikely(!put_tree_ref(context, chunk))) {
  1466 + drop = chunk;
  1467 + break;
  1468 + }
  1469 + }
  1470 + }
  1471 + parent = d->d_parent;
  1472 + if (parent == d)
  1473 + break;
  1474 + d = parent;
  1475 + }
  1476 + if (unlikely(read_seqretry(&rename_lock, seq) || drop)) { /* in this order */
  1477 + rcu_read_unlock();
  1478 + if (!drop) {
  1479 + /* just a race with rename */
  1480 + unroll_tree_refs(context, p, count);
  1481 + goto retry;
  1482 + }
  1483 + audit_put_chunk(drop);
  1484 + if (grow_tree_refs(context)) {
  1485 + /* OK, got more space */
  1486 + unroll_tree_refs(context, p, count);
  1487 + goto retry;
  1488 + }
  1489 + /* too bad */
  1490 + printk(KERN_WARNING
  1491 + "out of memory, audit has lost a tree reference");
  1492 + unroll_tree_refs(context, p, count);
  1493 + audit_set_auditable(context);
  1494 + return;
  1495 + }
  1496 + rcu_read_unlock();
  1497 +#endif
  1498 +}
  1499 +
1284 1500 /**
1285 1501 * audit_getname - add a name to the list
1286 1502 * @name: name to add
... ... @@ -1407,7 +1623,7 @@
1407 1623 {
1408 1624 int idx;
1409 1625 struct audit_context *context = current->audit_context;
1410   - const struct inode *inode = inode = dentry->d_inode;
  1626 + const struct inode *inode = dentry->d_inode;
1411 1627  
1412 1628 if (!context->in_syscall)
1413 1629 return;
... ... @@ -1427,6 +1643,7 @@
1427 1643 idx = context->name_count - 1;
1428 1644 context->names[idx].name = NULL;
1429 1645 }
  1646 + handle_path(dentry);
1430 1647 audit_copy_inode(&context->names[idx], inode);
1431 1648 }
1432 1649  
... ... @@ -1456,6 +1673,8 @@
1456 1673 if (!context->in_syscall)
1457 1674 return;
1458 1675  
  1676 + if (inode)
  1677 + handle_one(inode);
1459 1678 /* determine matching parent */
1460 1679 if (!dname)
1461 1680 goto add_names;