Blame view

kernel/audit_tree.c 25.7 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
74c3cbe33   Al Viro   [PATCH] audit: wa...
2
  #include "audit.h"
28a3a7eb3   Eric Paris   audit: reimplemen...
3
  #include <linux/fsnotify_backend.h>
74c3cbe33   Al Viro   [PATCH] audit: wa...
4
5
  #include <linux/namei.h>
  #include <linux/mount.h>
916d75761   Al Viro   Fix rule eviction...
6
  #include <linux/kthread.h>
9d2378f8c   Elena Reshetova   audit: convert au...
7
  #include <linux/refcount.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
8
  #include <linux/slab.h>
74c3cbe33   Al Viro   [PATCH] audit: wa...
9
10
11
12
13
  
  struct audit_tree;
  struct audit_chunk;
  
  struct audit_tree {
9d2378f8c   Elena Reshetova   audit: convert au...
14
  	refcount_t count;
74c3cbe33   Al Viro   [PATCH] audit: wa...
15
16
17
18
19
20
21
22
23
24
25
26
  	int goner;
  	struct audit_chunk *root;
  	struct list_head chunks;
  	struct list_head rules;
  	struct list_head list;
  	struct list_head same_root;
  	struct rcu_head head;
  	char pathname[];
  };
  
  struct audit_chunk {
  	struct list_head hash;
8d20d6e93   Jan Kara   audit: Embed key ...
27
  	unsigned long key;
5f5161300   Jan Kara   audit: Allocate f...
28
  	struct fsnotify_mark *mark;
74c3cbe33   Al Viro   [PATCH] audit: wa...
29
  	struct list_head trees;		/* with root here */
74c3cbe33   Al Viro   [PATCH] audit: wa...
30
  	int count;
8f7b0ba1c   Al Viro   Fix inotify watch...
31
  	atomic_long_t refs;
74c3cbe33   Al Viro   [PATCH] audit: wa...
32
33
34
35
36
37
38
  	struct rcu_head head;
  	struct node {
  		struct list_head list;
  		struct audit_tree *owner;
  		unsigned index;		/* index; upper bit indicates 'will prune' */
  	} owners[];
  };
5f5161300   Jan Kara   audit: Allocate f...
39
40
41
42
  struct audit_tree_mark {
  	struct fsnotify_mark mark;
  	struct audit_chunk *chunk;
  };
74c3cbe33   Al Viro   [PATCH] audit: wa...
43
44
  static LIST_HEAD(tree_list);
  static LIST_HEAD(prune_list);
f1aaf2622   Imre Palik   audit: move the t...
45
  static struct task_struct *prune_thread;
74c3cbe33   Al Viro   [PATCH] audit: wa...
46
47
  
  /*
83d23bc8a   Jan Kara   audit: Replace ch...
48
49
50
51
52
53
54
55
56
   * One struct chunk is attached to each inode of interest through
   * audit_tree_mark (fsnotify mark). We replace struct chunk on tagging /
   * untagging, the mark is stable as long as there is chunk attached. The
   * association between mark and chunk is protected by hash_lock and
   * audit_tree_group->mark_mutex. Thus as long as we hold
   * audit_tree_group->mark_mutex and check that the mark is alive by
   * FSNOTIFY_MARK_FLAG_ATTACHED flag check, we are sure the mark points to
   * the current chunk.
   *
74c3cbe33   Al Viro   [PATCH] audit: wa...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
   * Rules have pointer to struct audit_tree.
   * Rules have struct list_head rlist forming a list of rules over
   * the same tree.
   * References to struct chunk are collected at audit_inode{,_child}()
   * time and used in AUDIT_TREE rule matching.
   * These references are dropped at the same time we are calling
   * audit_free_names(), etc.
   *
   * Cyclic lists galore:
   * tree.chunks anchors chunk.owners[].list			hash_lock
   * tree.rules anchors rule.rlist				audit_filter_mutex
   * chunk.trees anchors tree.same_root				hash_lock
   * chunk.hash is a hash with middle bits of watch.inode as
   * a hash function.						RCU, hash_lock
   *
   * tree is refcounted; one reference for "some rules on rules_list refer to
   * it", one for each chunk with pointer to it.
   *
83d23bc8a   Jan Kara   audit: Replace ch...
75
76
77
78
79
80
   * chunk is refcounted by embedded .refs. Mark associated with the chunk holds
   * one chunk reference. This reference is dropped either when a mark is going
   * to be freed (corresponding inode goes away) or when chunk attached to the
   * mark gets replaced. This reference must be dropped using
   * audit_mark_put_chunk() to make sure the reference is dropped only after RCU
   * grace period as it protects RCU readers of the hash table.
74c3cbe33   Al Viro   [PATCH] audit: wa...
81
82
83
84
85
86
   *
   * node.index allows to get from node.list to containing chunk.
   * MSB of that sucker is stolen to mark taggings that we might have to
   * revert - several operations have very unpleasant cleanup logics and
   * that makes a difference.  Some.
   */
28a3a7eb3   Eric Paris   audit: reimplemen...
87
  static struct fsnotify_group *audit_tree_group;
5f5161300   Jan Kara   audit: Allocate f...
88
  static struct kmem_cache *audit_tree_mark_cachep __read_mostly;
74c3cbe33   Al Viro   [PATCH] audit: wa...
89
90
91
92
93
94
95
  
  static struct audit_tree *alloc_tree(const char *s)
  {
  	struct audit_tree *tree;
  
  	tree = kmalloc(sizeof(struct audit_tree) + strlen(s) + 1, GFP_KERNEL);
  	if (tree) {
9d2378f8c   Elena Reshetova   audit: convert au...
96
  		refcount_set(&tree->count, 1);
74c3cbe33   Al Viro   [PATCH] audit: wa...
97
98
99
100
101
102
103
104
105
106
107
108
109
  		tree->goner = 0;
  		INIT_LIST_HEAD(&tree->chunks);
  		INIT_LIST_HEAD(&tree->rules);
  		INIT_LIST_HEAD(&tree->list);
  		INIT_LIST_HEAD(&tree->same_root);
  		tree->root = NULL;
  		strcpy(tree->pathname, s);
  	}
  	return tree;
  }
  
  static inline void get_tree(struct audit_tree *tree)
  {
9d2378f8c   Elena Reshetova   audit: convert au...
110
  	refcount_inc(&tree->count);
74c3cbe33   Al Viro   [PATCH] audit: wa...
111
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
112
113
  static inline void put_tree(struct audit_tree *tree)
  {
9d2378f8c   Elena Reshetova   audit: convert au...
114
  	if (refcount_dec_and_test(&tree->count))
3b097c469   Lai Jiangshan   audit_tree,rcu: C...
115
  		kfree_rcu(tree, head);
74c3cbe33   Al Viro   [PATCH] audit: wa...
116
117
118
119
120
121
122
  }
  
  /* to avoid bringing the entire thing in audit.h */
  const char *audit_tree_path(struct audit_tree *tree)
  {
  	return tree->pathname;
  }
8f7b0ba1c   Al Viro   Fix inotify watch...
123
  static void free_chunk(struct audit_chunk *chunk)
74c3cbe33   Al Viro   [PATCH] audit: wa...
124
  {
74c3cbe33   Al Viro   [PATCH] audit: wa...
125
126
127
128
129
130
131
132
  	int i;
  
  	for (i = 0; i < chunk->count; i++) {
  		if (chunk->owners[i].owner)
  			put_tree(chunk->owners[i].owner);
  	}
  	kfree(chunk);
  }
8f7b0ba1c   Al Viro   Fix inotify watch...
133
  void audit_put_chunk(struct audit_chunk *chunk)
74c3cbe33   Al Viro   [PATCH] audit: wa...
134
  {
8f7b0ba1c   Al Viro   Fix inotify watch...
135
136
  	if (atomic_long_dec_and_test(&chunk->refs))
  		free_chunk(chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
137
  }
8f7b0ba1c   Al Viro   Fix inotify watch...
138
  static void __put_chunk(struct rcu_head *rcu)
74c3cbe33   Al Viro   [PATCH] audit: wa...
139
  {
8f7b0ba1c   Al Viro   Fix inotify watch...
140
141
  	struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
  	audit_put_chunk(chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
142
  }
a8375713f   Jan Kara   audit: Provide he...
143
144
145
146
147
148
149
150
151
  /*
   * Drop reference to the chunk that was held by the mark. This is the reference
   * that gets dropped after we've removed the chunk from the hash table and we
   * use it to make sure chunk cannot be freed before RCU grace period expires.
   */
  static void audit_mark_put_chunk(struct audit_chunk *chunk)
  {
  	call_rcu(&chunk->head, __put_chunk);
  }
f905c2fc3   Jan Kara   audit: Use 'mark'...
152
  static inline struct audit_tree_mark *audit_mark(struct fsnotify_mark *mark)
5f5161300   Jan Kara   audit: Allocate f...
153
  {
f905c2fc3   Jan Kara   audit: Use 'mark'...
154
  	return container_of(mark, struct audit_tree_mark, mark);
5f5161300   Jan Kara   audit: Allocate f...
155
156
157
158
159
160
  }
  
  static struct audit_chunk *mark_chunk(struct fsnotify_mark *mark)
  {
  	return audit_mark(mark)->chunk;
  }
f905c2fc3   Jan Kara   audit: Use 'mark'...
161
  static void audit_tree_destroy_watch(struct fsnotify_mark *mark)
28a3a7eb3   Eric Paris   audit: reimplemen...
162
  {
f905c2fc3   Jan Kara   audit: Use 'mark'...
163
  	kmem_cache_free(audit_tree_mark_cachep, audit_mark(mark));
5f5161300   Jan Kara   audit: Allocate f...
164
165
166
167
168
169
170
171
172
173
174
175
  }
  
  static struct fsnotify_mark *alloc_mark(void)
  {
  	struct audit_tree_mark *amark;
  
  	amark = kmem_cache_zalloc(audit_tree_mark_cachep, GFP_KERNEL);
  	if (!amark)
  		return NULL;
  	fsnotify_init_mark(&amark->mark, audit_tree_group);
  	amark->mark.mask = FS_IN_IGNORED;
  	return &amark->mark;
28a3a7eb3   Eric Paris   audit: reimplemen...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  }
  
  static struct audit_chunk *alloc_chunk(int count)
  {
  	struct audit_chunk *chunk;
  	size_t size;
  	int i;
  
  	size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
  	chunk = kzalloc(size, GFP_KERNEL);
  	if (!chunk)
  		return NULL;
  
  	INIT_LIST_HEAD(&chunk->hash);
  	INIT_LIST_HEAD(&chunk->trees);
  	chunk->count = count;
  	atomic_long_set(&chunk->refs, 1);
  	for (i = 0; i < count; i++) {
  		INIT_LIST_HEAD(&chunk->owners[i].list);
  		chunk->owners[i].index = i;
  	}
28a3a7eb3   Eric Paris   audit: reimplemen...
197
198
  	return chunk;
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
199
200
201
  enum {HASH_SIZE = 128};
  static struct list_head chunk_hash_heads[HASH_SIZE];
  static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock);
f410ff655   Jan Kara   audit: Abstract h...
202
203
  /* Function to return search key in our hash from inode. */
  static unsigned long inode_to_key(const struct inode *inode)
74c3cbe33   Al Viro   [PATCH] audit: wa...
204
  {
36f10f55f   Amir Goldstein   fsnotify: let con...
205
206
  	/* Use address pointed to by connector->obj as the key */
  	return (unsigned long)&inode->i_fsnotify_marks;
f410ff655   Jan Kara   audit: Abstract h...
207
  }
f410ff655   Jan Kara   audit: Abstract h...
208
209
210
  static inline struct list_head *chunk_hash(unsigned long key)
  {
  	unsigned long n = key / L1_CACHE_BYTES;
74c3cbe33   Al Viro   [PATCH] audit: wa...
211
212
  	return chunk_hash_heads + n % HASH_SIZE;
  }
f905c2fc3   Jan Kara   audit: Use 'mark'...
213
  /* hash_lock & mark->group->mark_mutex is held by caller */
74c3cbe33   Al Viro   [PATCH] audit: wa...
214
215
  static void insert_hash(struct audit_chunk *chunk)
  {
28a3a7eb3   Eric Paris   audit: reimplemen...
216
  	struct list_head *list;
1635e5722   Jan Kara   audit: Make hash ...
217
218
219
220
221
222
  	/*
  	 * Make sure chunk is fully initialized before making it visible in the
  	 * hash. Pairs with a data dependency barrier in READ_ONCE() in
  	 * audit_tree_lookup().
  	 */
  	smp_wmb();
8d20d6e93   Jan Kara   audit: Embed key ...
223
224
  	WARN_ON_ONCE(!chunk->key);
  	list = chunk_hash(chunk->key);
74c3cbe33   Al Viro   [PATCH] audit: wa...
225
226
227
228
229
230
  	list_add_rcu(&chunk->hash, list);
  }
  
  /* called under rcu_read_lock */
  struct audit_chunk *audit_tree_lookup(const struct inode *inode)
  {
f410ff655   Jan Kara   audit: Abstract h...
231
232
  	unsigned long key = inode_to_key(inode);
  	struct list_head *list = chunk_hash(key);
6793a051f   Paul E. McKenney   [PATCH] list_for_...
233
  	struct audit_chunk *p;
74c3cbe33   Al Viro   [PATCH] audit: wa...
234

6793a051f   Paul E. McKenney   [PATCH] list_for_...
235
  	list_for_each_entry_rcu(p, list, hash) {
1635e5722   Jan Kara   audit: Make hash ...
236
237
238
239
240
  		/*
  		 * We use a data dependency barrier in READ_ONCE() to make sure
  		 * the chunk we see is fully initialized.
  		 */
  		if (READ_ONCE(p->key) == key) {
8f7b0ba1c   Al Viro   Fix inotify watch...
241
  			atomic_long_inc(&p->refs);
74c3cbe33   Al Viro   [PATCH] audit: wa...
242
243
244
245
246
  			return p;
  		}
  	}
  	return NULL;
  }
6f1b5d7af   Yaowei Bai   audit: audit_tree...
247
  bool audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
74c3cbe33   Al Viro   [PATCH] audit: wa...
248
249
250
251
  {
  	int n;
  	for (n = 0; n < chunk->count; n++)
  		if (chunk->owners[n].owner == tree)
6f1b5d7af   Yaowei Bai   audit: audit_tree...
252
253
  			return true;
  	return false;
74c3cbe33   Al Viro   [PATCH] audit: wa...
254
255
256
  }
  
  /* tagging and untagging inodes with trees */
8f7b0ba1c   Al Viro   Fix inotify watch...
257
258
259
260
261
262
  static struct audit_chunk *find_chunk(struct node *p)
  {
  	int index = p->index & ~(1U<<31);
  	p -= index;
  	return container_of(p, struct audit_chunk, owners[0]);
  }
f905c2fc3   Jan Kara   audit: Use 'mark'...
263
  static void replace_mark_chunk(struct fsnotify_mark *mark,
83d23bc8a   Jan Kara   audit: Replace ch...
264
265
266
267
268
  			       struct audit_chunk *chunk)
  {
  	struct audit_chunk *old;
  
  	assert_spin_locked(&hash_lock);
f905c2fc3   Jan Kara   audit: Use 'mark'...
269
270
  	old = mark_chunk(mark);
  	audit_mark(mark)->chunk = chunk;
83d23bc8a   Jan Kara   audit: Replace ch...
271
  	if (chunk)
f905c2fc3   Jan Kara   audit: Use 'mark'...
272
  		chunk->mark = mark;
83d23bc8a   Jan Kara   audit: Replace ch...
273
274
275
  	if (old)
  		old->mark = NULL;
  }
c22fcde77   Jan Kara   audit: Drop all u...
276
  static void replace_chunk(struct audit_chunk *new, struct audit_chunk *old)
d31b326d3   Jan Kara   audit: Factor out...
277
278
279
280
281
282
283
284
285
  {
  	struct audit_tree *owner;
  	int i, j;
  
  	new->key = old->key;
  	list_splice_init(&old->trees, &new->trees);
  	list_for_each_entry(owner, &new->trees, same_root)
  		owner->root = new;
  	for (i = j = 0; j < old->count; i++, j++) {
c22fcde77   Jan Kara   audit: Drop all u...
286
  		if (!old->owners[j].owner) {
d31b326d3   Jan Kara   audit: Factor out...
287
288
289
290
291
292
293
294
295
296
297
  			i--;
  			continue;
  		}
  		owner = old->owners[j].owner;
  		new->owners[i].owner = owner;
  		new->owners[i].index = old->owners[j].index - j + i;
  		if (!owner) /* result of earlier fallback */
  			continue;
  		get_tree(owner);
  		list_replace_init(&old->owners[j].list, &new->owners[i].list);
  	}
83d23bc8a   Jan Kara   audit: Replace ch...
298
  	replace_mark_chunk(old->mark, new);
d31b326d3   Jan Kara   audit: Factor out...
299
300
301
302
303
304
305
306
  	/*
  	 * Make sure chunk is fully initialized before making it visible in the
  	 * hash. Pairs with a data dependency barrier in READ_ONCE() in
  	 * audit_tree_lookup().
  	 */
  	smp_wmb();
  	list_replace_rcu(&old->hash, &new->hash);
  }
49a4ee7d9   Jan Kara   audit: Guarantee ...
307
308
309
310
311
312
313
314
315
316
317
318
  static void remove_chunk_node(struct audit_chunk *chunk, struct node *p)
  {
  	struct audit_tree *owner = p->owner;
  
  	if (owner->root == chunk) {
  		list_del_init(&owner->same_root);
  		owner->root = NULL;
  	}
  	list_del_init(&p->list);
  	p->owner = NULL;
  	put_tree(owner);
  }
c22fcde77   Jan Kara   audit: Drop all u...
319
320
321
322
323
324
325
326
327
328
  static int chunk_count_trees(struct audit_chunk *chunk)
  {
  	int i;
  	int ret = 0;
  
  	for (i = 0; i < chunk->count; i++)
  		if (chunk->owners[i].owner)
  			ret++;
  	return ret;
  }
f905c2fc3   Jan Kara   audit: Use 'mark'...
329
  static void untag_chunk(struct audit_chunk *chunk, struct fsnotify_mark *mark)
74c3cbe33   Al Viro   [PATCH] audit: wa...
330
  {
8432c7006   Jan Kara   audit: Simplify l...
331
  	struct audit_chunk *new;
c22fcde77   Jan Kara   audit: Drop all u...
332
  	int size;
74c3cbe33   Al Viro   [PATCH] audit: wa...
333

8432c7006   Jan Kara   audit: Simplify l...
334
  	mutex_lock(&audit_tree_group->mark_mutex);
6b3f05d24   Jan Kara   fsnotify: Detach ...
335
  	/*
83d23bc8a   Jan Kara   audit: Replace ch...
336
337
  	 * mark_mutex stabilizes chunk attached to the mark so we can check
  	 * whether it didn't change while we've dropped hash_lock.
6b3f05d24   Jan Kara   fsnotify: Detach ...
338
  	 */
f905c2fc3   Jan Kara   audit: Use 'mark'...
339
340
  	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) ||
  	    mark_chunk(mark) != chunk)
8432c7006   Jan Kara   audit: Simplify l...
341
  		goto out_mutex;
74c3cbe33   Al Viro   [PATCH] audit: wa...
342

c22fcde77   Jan Kara   audit: Drop all u...
343
  	size = chunk_count_trees(chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
344
  	if (!size) {
74c3cbe33   Al Viro   [PATCH] audit: wa...
345
346
  		spin_lock(&hash_lock);
  		list_del_init(&chunk->trees);
74c3cbe33   Al Viro   [PATCH] audit: wa...
347
  		list_del_rcu(&chunk->hash);
f905c2fc3   Jan Kara   audit: Use 'mark'...
348
  		replace_mark_chunk(mark, NULL);
74c3cbe33   Al Viro   [PATCH] audit: wa...
349
  		spin_unlock(&hash_lock);
f905c2fc3   Jan Kara   audit: Use 'mark'...
350
  		fsnotify_detach_mark(mark);
8432c7006   Jan Kara   audit: Simplify l...
351
  		mutex_unlock(&audit_tree_group->mark_mutex);
83d23bc8a   Jan Kara   audit: Replace ch...
352
  		audit_mark_put_chunk(chunk);
f905c2fc3   Jan Kara   audit: Use 'mark'...
353
  		fsnotify_free_mark(mark);
8432c7006   Jan Kara   audit: Simplify l...
354
  		return;
74c3cbe33   Al Viro   [PATCH] audit: wa...
355
  	}
c22fcde77   Jan Kara   audit: Drop all u...
356
  	new = alloc_chunk(size);
74c3cbe33   Al Viro   [PATCH] audit: wa...
357
  	if (!new)
49a4ee7d9   Jan Kara   audit: Guarantee ...
358
  		goto out_mutex;
f7a998a94   Al Viro   in untag_chunk() ...
359

74c3cbe33   Al Viro   [PATCH] audit: wa...
360
  	spin_lock(&hash_lock);
1635e5722   Jan Kara   audit: Make hash ...
361
  	/*
d31b326d3   Jan Kara   audit: Factor out...
362
363
  	 * This has to go last when updating chunk as once replace_chunk() is
  	 * called, new RCU readers can see the new chunk.
1635e5722   Jan Kara   audit: Make hash ...
364
  	 */
c22fcde77   Jan Kara   audit: Drop all u...
365
  	replace_chunk(new, chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
366
  	spin_unlock(&hash_lock);
8432c7006   Jan Kara   audit: Simplify l...
367
  	mutex_unlock(&audit_tree_group->mark_mutex);
83d23bc8a   Jan Kara   audit: Replace ch...
368
  	audit_mark_put_chunk(chunk);
8432c7006   Jan Kara   audit: Simplify l...
369
  	return;
74c3cbe33   Al Viro   [PATCH] audit: wa...
370

49a4ee7d9   Jan Kara   audit: Guarantee ...
371
  out_mutex:
8432c7006   Jan Kara   audit: Simplify l...
372
  	mutex_unlock(&audit_tree_group->mark_mutex);
74c3cbe33   Al Viro   [PATCH] audit: wa...
373
  }
a5789b07b   Jan Kara   audit: Fix possib...
374
  /* Call with group->mark_mutex held, releases it */
74c3cbe33   Al Viro   [PATCH] audit: wa...
375
376
  static int create_chunk(struct inode *inode, struct audit_tree *tree)
  {
f905c2fc3   Jan Kara   audit: Use 'mark'...
377
  	struct fsnotify_mark *mark;
74c3cbe33   Al Viro   [PATCH] audit: wa...
378
  	struct audit_chunk *chunk = alloc_chunk(1);
a5789b07b   Jan Kara   audit: Fix possib...
379
380
381
  
  	if (!chunk) {
  		mutex_unlock(&audit_tree_group->mark_mutex);
74c3cbe33   Al Viro   [PATCH] audit: wa...
382
  		return -ENOMEM;
a5789b07b   Jan Kara   audit: Fix possib...
383
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
384

f905c2fc3   Jan Kara   audit: Use 'mark'...
385
386
  	mark = alloc_mark();
  	if (!mark) {
83d23bc8a   Jan Kara   audit: Replace ch...
387
388
389
390
  		mutex_unlock(&audit_tree_group->mark_mutex);
  		kfree(chunk);
  		return -ENOMEM;
  	}
f905c2fc3   Jan Kara   audit: Use 'mark'...
391
  	if (fsnotify_add_inode_mark_locked(mark, inode, 0)) {
a5789b07b   Jan Kara   audit: Fix possib...
392
  		mutex_unlock(&audit_tree_group->mark_mutex);
f905c2fc3   Jan Kara   audit: Use 'mark'...
393
  		fsnotify_put_mark(mark);
83d23bc8a   Jan Kara   audit: Replace ch...
394
  		kfree(chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
395
396
  		return -ENOSPC;
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
397
398
399
  	spin_lock(&hash_lock);
  	if (tree->goner) {
  		spin_unlock(&hash_lock);
f905c2fc3   Jan Kara   audit: Use 'mark'...
400
  		fsnotify_detach_mark(mark);
a5789b07b   Jan Kara   audit: Fix possib...
401
  		mutex_unlock(&audit_tree_group->mark_mutex);
f905c2fc3   Jan Kara   audit: Use 'mark'...
402
403
  		fsnotify_free_mark(mark);
  		fsnotify_put_mark(mark);
83d23bc8a   Jan Kara   audit: Replace ch...
404
  		kfree(chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
405
406
  		return 0;
  	}
f905c2fc3   Jan Kara   audit: Use 'mark'...
407
  	replace_mark_chunk(mark, chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
408
409
410
411
412
413
414
415
  	chunk->owners[0].index = (1U << 31);
  	chunk->owners[0].owner = tree;
  	get_tree(tree);
  	list_add(&chunk->owners[0].list, &tree->chunks);
  	if (!tree->root) {
  		tree->root = chunk;
  		list_add(&tree->same_root, &chunk->trees);
  	}
8d20d6e93   Jan Kara   audit: Embed key ...
416
  	chunk->key = inode_to_key(inode);
1635e5722   Jan Kara   audit: Make hash ...
417
418
419
420
  	/*
  	 * Inserting into the hash table has to go last as once we do that RCU
  	 * readers can see the chunk.
  	 */
74c3cbe33   Al Viro   [PATCH] audit: wa...
421
422
  	insert_hash(chunk);
  	spin_unlock(&hash_lock);
a5789b07b   Jan Kara   audit: Fix possib...
423
  	mutex_unlock(&audit_tree_group->mark_mutex);
83d23bc8a   Jan Kara   audit: Replace ch...
424
425
426
427
428
  	/*
  	 * Drop our initial reference. When mark we point to is getting freed,
  	 * we get notification through ->freeing_mark callback and cleanup
  	 * chunk pointing to this mark.
  	 */
f905c2fc3   Jan Kara   audit: Use 'mark'...
429
  	fsnotify_put_mark(mark);
74c3cbe33   Al Viro   [PATCH] audit: wa...
430
431
432
433
434
435
  	return 0;
  }
  
  /* the first tagged inode becomes root of tree */
  static int tag_chunk(struct inode *inode, struct audit_tree *tree)
  {
f905c2fc3   Jan Kara   audit: Use 'mark'...
436
  	struct fsnotify_mark *mark;
74c3cbe33   Al Viro   [PATCH] audit: wa...
437
438
439
  	struct audit_chunk *chunk, *old;
  	struct node *p;
  	int n;
a5789b07b   Jan Kara   audit: Fix possib...
440
  	mutex_lock(&audit_tree_group->mark_mutex);
f905c2fc3   Jan Kara   audit: Use 'mark'...
441
442
  	mark = fsnotify_find_mark(&inode->i_fsnotify_marks, audit_tree_group);
  	if (!mark)
74c3cbe33   Al Viro   [PATCH] audit: wa...
443
  		return create_chunk(inode, tree);
83d23bc8a   Jan Kara   audit: Replace ch...
444
445
446
447
448
  	/*
  	 * Found mark is guaranteed to be attached and mark_mutex protects mark
  	 * from getting detached and thus it makes sure there is chunk attached
  	 * to the mark.
  	 */
74c3cbe33   Al Viro   [PATCH] audit: wa...
449
450
  	/* are we already there? */
  	spin_lock(&hash_lock);
f905c2fc3   Jan Kara   audit: Use 'mark'...
451
  	old = mark_chunk(mark);
74c3cbe33   Al Viro   [PATCH] audit: wa...
452
453
454
  	for (n = 0; n < old->count; n++) {
  		if (old->owners[n].owner == tree) {
  			spin_unlock(&hash_lock);
a5789b07b   Jan Kara   audit: Fix possib...
455
  			mutex_unlock(&audit_tree_group->mark_mutex);
f905c2fc3   Jan Kara   audit: Use 'mark'...
456
  			fsnotify_put_mark(mark);
74c3cbe33   Al Viro   [PATCH] audit: wa...
457
458
459
460
461
462
  			return 0;
  		}
  	}
  	spin_unlock(&hash_lock);
  
  	chunk = alloc_chunk(old->count + 1);
b4c30aad3   Al Viro   fix more leaks in...
463
  	if (!chunk) {
a5789b07b   Jan Kara   audit: Fix possib...
464
  		mutex_unlock(&audit_tree_group->mark_mutex);
f905c2fc3   Jan Kara   audit: Use 'mark'...
465
  		fsnotify_put_mark(mark);
74c3cbe33   Al Viro   [PATCH] audit: wa...
466
  		return -ENOMEM;
b4c30aad3   Al Viro   fix more leaks in...
467
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
468

74c3cbe33   Al Viro   [PATCH] audit: wa...
469
470
471
  	spin_lock(&hash_lock);
  	if (tree->goner) {
  		spin_unlock(&hash_lock);
a5789b07b   Jan Kara   audit: Fix possib...
472
  		mutex_unlock(&audit_tree_group->mark_mutex);
f905c2fc3   Jan Kara   audit: Use 'mark'...
473
  		fsnotify_put_mark(mark);
83d23bc8a   Jan Kara   audit: Replace ch...
474
  		kfree(chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
475
476
  		return 0;
  	}
d31b326d3   Jan Kara   audit: Factor out...
477
  	p = &chunk->owners[chunk->count - 1];
74c3cbe33   Al Viro   [PATCH] audit: wa...
478
479
480
481
  	p->index = (chunk->count - 1) | (1U<<31);
  	p->owner = tree;
  	get_tree(tree);
  	list_add(&p->list, &tree->chunks);
74c3cbe33   Al Viro   [PATCH] audit: wa...
482
483
484
485
  	if (!tree->root) {
  		tree->root = chunk;
  		list_add(&tree->same_root, &chunk->trees);
  	}
1635e5722   Jan Kara   audit: Make hash ...
486
  	/*
d31b326d3   Jan Kara   audit: Factor out...
487
488
  	 * This has to go last when updating chunk as once replace_chunk() is
  	 * called, new RCU readers can see the new chunk.
1635e5722   Jan Kara   audit: Make hash ...
489
  	 */
c22fcde77   Jan Kara   audit: Drop all u...
490
  	replace_chunk(chunk, old);
74c3cbe33   Al Viro   [PATCH] audit: wa...
491
  	spin_unlock(&hash_lock);
a5789b07b   Jan Kara   audit: Fix possib...
492
  	mutex_unlock(&audit_tree_group->mark_mutex);
f905c2fc3   Jan Kara   audit: Use 'mark'...
493
  	fsnotify_put_mark(mark); /* pair to fsnotify_find_mark */
83d23bc8a   Jan Kara   audit: Replace ch...
494
  	audit_mark_put_chunk(old);
74c3cbe33   Al Viro   [PATCH] audit: wa...
495
496
  	return 0;
  }
9e36a5d49   Richard Guy Briggs   audit: hand taken...
497
498
  static void audit_tree_log_remove_rule(struct audit_context *context,
  				       struct audit_krule *rule)
0644ec0cc   Kees Cook   audit: catch poss...
499
500
  {
  	struct audit_buffer *ab;
65a8766f5   Richard Guy Briggs   audit: check audi...
501
502
  	if (!audit_enabled)
  		return;
9e36a5d49   Richard Guy Briggs   audit: hand taken...
503
  	ab = audit_log_start(context, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
0644ec0cc   Kees Cook   audit: catch poss...
504
505
  	if (unlikely(!ab))
  		return;
d0a3f18a7   Paul Moore   audit: minimize o...
506
  	audit_log_format(ab, "op=remove_rule dir=");
0644ec0cc   Kees Cook   audit: catch poss...
507
508
509
510
511
  	audit_log_untrustedstring(ab, rule->tree->pathname);
  	audit_log_key(ab, rule->filterkey);
  	audit_log_format(ab, " list=%d res=1", rule->listnr);
  	audit_log_end(ab);
  }
9e36a5d49   Richard Guy Briggs   audit: hand taken...
512
  static void kill_rules(struct audit_context *context, struct audit_tree *tree)
74c3cbe33   Al Viro   [PATCH] audit: wa...
513
514
515
  {
  	struct audit_krule *rule, *next;
  	struct audit_entry *entry;
74c3cbe33   Al Viro   [PATCH] audit: wa...
516
517
518
519
520
521
522
  
  	list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
  		entry = container_of(rule, struct audit_entry, rule);
  
  		list_del_init(&rule->rlist);
  		if (rule->tree) {
  			/* not a half-baked one */
9e36a5d49   Richard Guy Briggs   audit: hand taken...
523
  			audit_tree_log_remove_rule(context, rule);
34d99af52   Richard Guy Briggs   audit: implement ...
524
525
  			if (entry->rule.exe)
  				audit_remove_mark(entry->rule.exe);
74c3cbe33   Al Viro   [PATCH] audit: wa...
526
527
  			rule->tree = NULL;
  			list_del_rcu(&entry->list);
e45aa212e   Al Viro   audit rules order...
528
  			list_del(&entry->rule.list);
74c3cbe33   Al Viro   [PATCH] audit: wa...
529
530
531
532
533
534
  			call_rcu(&entry->rcu, audit_free_rule_rcu);
  		}
  	}
  }
  
  /*
8432c7006   Jan Kara   audit: Simplify l...
535
536
537
   * Remove tree from chunks. If 'tagged' is set, remove tree only from tagged
   * chunks. The function expects tagged chunks are all at the beginning of the
   * chunks list.
74c3cbe33   Al Viro   [PATCH] audit: wa...
538
   */
8432c7006   Jan Kara   audit: Simplify l...
539
  static void prune_tree_chunks(struct audit_tree *victim, bool tagged)
74c3cbe33   Al Viro   [PATCH] audit: wa...
540
541
542
543
  {
  	spin_lock(&hash_lock);
  	while (!list_empty(&victim->chunks)) {
  		struct node *p;
8432c7006   Jan Kara   audit: Simplify l...
544
545
546
547
548
549
550
551
552
553
  		struct audit_chunk *chunk;
  		struct fsnotify_mark *mark;
  
  		p = list_first_entry(&victim->chunks, struct node, list);
  		/* have we run out of marked? */
  		if (tagged && !(p->index & (1U<<31)))
  			break;
  		chunk = find_chunk(p);
  		mark = chunk->mark;
  		remove_chunk_node(chunk, p);
83d23bc8a   Jan Kara   audit: Replace ch...
554
555
556
  		/* Racing with audit_tree_freeing_mark()? */
  		if (!mark)
  			continue;
8432c7006   Jan Kara   audit: Simplify l...
557
558
  		fsnotify_get_mark(mark);
  		spin_unlock(&hash_lock);
74c3cbe33   Al Viro   [PATCH] audit: wa...
559

8432c7006   Jan Kara   audit: Simplify l...
560
561
  		untag_chunk(chunk, mark);
  		fsnotify_put_mark(mark);
74c3cbe33   Al Viro   [PATCH] audit: wa...
562

8432c7006   Jan Kara   audit: Simplify l...
563
  		spin_lock(&hash_lock);
74c3cbe33   Al Viro   [PATCH] audit: wa...
564
565
566
567
  	}
  	spin_unlock(&hash_lock);
  	put_tree(victim);
  }
8432c7006   Jan Kara   audit: Simplify l...
568
569
570
571
572
573
574
  /*
   * finish killing struct audit_tree
   */
  static void prune_one(struct audit_tree *victim)
  {
  	prune_tree_chunks(victim, false);
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  /* trim the uncommitted chunks from tree */
  
  static void trim_marked(struct audit_tree *tree)
  {
  	struct list_head *p, *q;
  	spin_lock(&hash_lock);
  	if (tree->goner) {
  		spin_unlock(&hash_lock);
  		return;
  	}
  	/* reorder */
  	for (p = tree->chunks.next; p != &tree->chunks; p = q) {
  		struct node *node = list_entry(p, struct node, list);
  		q = p->next;
  		if (node->index & (1U<<31)) {
  			list_del_init(p);
  			list_add(p, &tree->chunks);
  		}
  	}
8432c7006   Jan Kara   audit: Simplify l...
594
  	spin_unlock(&hash_lock);
74c3cbe33   Al Viro   [PATCH] audit: wa...
595

8432c7006   Jan Kara   audit: Simplify l...
596
  	prune_tree_chunks(tree, true);
74c3cbe33   Al Viro   [PATCH] audit: wa...
597

8432c7006   Jan Kara   audit: Simplify l...
598
  	spin_lock(&hash_lock);
74c3cbe33   Al Viro   [PATCH] audit: wa...
599
600
601
602
  	if (!tree->root && !tree->goner) {
  		tree->goner = 1;
  		spin_unlock(&hash_lock);
  		mutex_lock(&audit_filter_mutex);
9e36a5d49   Richard Guy Briggs   audit: hand taken...
603
  		kill_rules(audit_context(), tree);
74c3cbe33   Al Viro   [PATCH] audit: wa...
604
605
606
607
608
609
610
  		list_del_init(&tree->list);
  		mutex_unlock(&audit_filter_mutex);
  		prune_one(tree);
  	} else {
  		spin_unlock(&hash_lock);
  	}
  }
916d75761   Al Viro   Fix rule eviction...
611
  static void audit_schedule_prune(void);
74c3cbe33   Al Viro   [PATCH] audit: wa...
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
  /* called with audit_filter_mutex */
  int audit_remove_tree_rule(struct audit_krule *rule)
  {
  	struct audit_tree *tree;
  	tree = rule->tree;
  	if (tree) {
  		spin_lock(&hash_lock);
  		list_del_init(&rule->rlist);
  		if (list_empty(&tree->rules) && !tree->goner) {
  			tree->root = NULL;
  			list_del_init(&tree->same_root);
  			tree->goner = 1;
  			list_move(&tree->list, &prune_list);
  			rule->tree = NULL;
  			spin_unlock(&hash_lock);
  			audit_schedule_prune();
  			return 1;
  		}
  		rule->tree = NULL;
  		spin_unlock(&hash_lock);
  		return 1;
  	}
  	return 0;
  }
1f707137b   Al Viro   new helper: itera...
636
637
  static int compare_root(struct vfsmount *mnt, void *arg)
  {
f410ff655   Jan Kara   audit: Abstract h...
638
639
  	return inode_to_key(d_backing_inode(mnt->mnt_root)) ==
  	       (unsigned long)arg;
1f707137b   Al Viro   new helper: itera...
640
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
641
642
643
644
645
646
647
648
  void audit_trim_trees(void)
  {
  	struct list_head cursor;
  
  	mutex_lock(&audit_filter_mutex);
  	list_add(&cursor, &tree_list);
  	while (cursor.next != &tree_list) {
  		struct audit_tree *tree;
98bc993f9   Al Viro   [PATCH] get rid o...
649
  		struct path path;
74c3cbe33   Al Viro   [PATCH] audit: wa...
650
651
  		struct vfsmount *root_mnt;
  		struct node *node;
74c3cbe33   Al Viro   [PATCH] audit: wa...
652
653
654
655
656
657
658
  		int err;
  
  		tree = container_of(cursor.next, struct audit_tree, list);
  		get_tree(tree);
  		list_del(&cursor);
  		list_add(&cursor, &tree->list);
  		mutex_unlock(&audit_filter_mutex);
98bc993f9   Al Viro   [PATCH] get rid o...
659
  		err = kern_path(tree->pathname, 0, &path);
74c3cbe33   Al Viro   [PATCH] audit: wa...
660
661
  		if (err)
  			goto skip_it;
589ff870e   Al Viro   Switch collect_mo...
662
  		root_mnt = collect_mounts(&path);
98bc993f9   Al Viro   [PATCH] get rid o...
663
  		path_put(&path);
be34d1a3b   David Howells   VFS: Make clone_m...
664
  		if (IS_ERR(root_mnt))
74c3cbe33   Al Viro   [PATCH] audit: wa...
665
  			goto skip_it;
74c3cbe33   Al Viro   [PATCH] audit: wa...
666
667
  		spin_lock(&hash_lock);
  		list_for_each_entry(node, &tree->chunks, list) {
28a3a7eb3   Eric Paris   audit: reimplemen...
668
  			struct audit_chunk *chunk = find_chunk(node);
25985edce   Lucas De Marchi   Fix common misspe...
669
  			/* this could be NULL if the watch is dying else where... */
74c3cbe33   Al Viro   [PATCH] audit: wa...
670
  			node->index |= 1U<<31;
f410ff655   Jan Kara   audit: Abstract h...
671
  			if (iterate_mounts(compare_root,
8d20d6e93   Jan Kara   audit: Embed key ...
672
  					   (void *)(chunk->key),
f410ff655   Jan Kara   audit: Abstract h...
673
  					   root_mnt))
1f707137b   Al Viro   new helper: itera...
674
  				node->index &= ~(1U<<31);
74c3cbe33   Al Viro   [PATCH] audit: wa...
675
676
677
  		}
  		spin_unlock(&hash_lock);
  		trim_marked(tree);
74c3cbe33   Al Viro   [PATCH] audit: wa...
678
679
  		drop_collected_mounts(root_mnt);
  skip_it:
12b2f117f   Chen Gang   kernel/audit_tree...
680
  		put_tree(tree);
74c3cbe33   Al Viro   [PATCH] audit: wa...
681
682
683
684
685
  		mutex_lock(&audit_filter_mutex);
  	}
  	list_del(&cursor);
  	mutex_unlock(&audit_filter_mutex);
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
686
687
688
689
690
  int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
  {
  
  	if (pathname[0] != '/' ||
  	    rule->listnr != AUDIT_FILTER_EXIT ||
5af75d8d5   Al Viro   audit: validate c...
691
  	    op != Audit_equal ||
74c3cbe33   Al Viro   [PATCH] audit: wa...
692
693
694
695
696
697
698
699
700
701
702
703
  	    rule->inode_f || rule->watch || rule->tree)
  		return -EINVAL;
  	rule->tree = alloc_tree(pathname);
  	if (!rule->tree)
  		return -ENOMEM;
  	return 0;
  }
  
  void audit_put_tree(struct audit_tree *tree)
  {
  	put_tree(tree);
  }
1f707137b   Al Viro   new helper: itera...
704
705
  static int tag_mount(struct vfsmount *mnt, void *arg)
  {
3b362157b   David Howells   VFS: audit: d_bac...
706
  	return tag_chunk(d_backing_inode(mnt->mnt_root), arg);
1f707137b   Al Viro   new helper: itera...
707
  }
f1aaf2622   Imre Palik   audit: move the t...
708
709
710
711
712
713
714
  /*
   * That gets run when evict_chunk() ends up needing to kill audit_tree.
   * Runs from a separate thread.
   */
  static int prune_tree_thread(void *unused)
  {
  	for (;;) {
0bf676d1f   Jiri Slaby   audit: cleanup pr...
715
716
  		if (list_empty(&prune_list)) {
  			set_current_state(TASK_INTERRUPTIBLE);
f1aaf2622   Imre Palik   audit: move the t...
717
  			schedule();
0bf676d1f   Jiri Slaby   audit: cleanup pr...
718
  		}
f1aaf2622   Imre Palik   audit: move the t...
719

ce423631c   Paul Moore   audit: track the ...
720
  		audit_ctl_lock();
f1aaf2622   Imre Palik   audit: move the t...
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  		mutex_lock(&audit_filter_mutex);
  
  		while (!list_empty(&prune_list)) {
  			struct audit_tree *victim;
  
  			victim = list_entry(prune_list.next,
  					struct audit_tree, list);
  			list_del_init(&victim->list);
  
  			mutex_unlock(&audit_filter_mutex);
  
  			prune_one(victim);
  
  			mutex_lock(&audit_filter_mutex);
  		}
  
  		mutex_unlock(&audit_filter_mutex);
ce423631c   Paul Moore   audit: track the ...
738
  		audit_ctl_unlock();
f1aaf2622   Imre Palik   audit: move the t...
739
740
741
742
743
744
745
746
  	}
  	return 0;
  }
  
  static int audit_launch_prune(void)
  {
  	if (prune_thread)
  		return 0;
0bf676d1f   Jiri Slaby   audit: cleanup pr...
747
  	prune_thread = kthread_run(prune_tree_thread, NULL,
f1aaf2622   Imre Palik   audit: move the t...
748
749
750
751
752
  				"audit_prune_tree");
  	if (IS_ERR(prune_thread)) {
  		pr_err("cannot start thread audit_prune_tree");
  		prune_thread = NULL;
  		return -ENOMEM;
f1aaf2622   Imre Palik   audit: move the t...
753
  	}
0bf676d1f   Jiri Slaby   audit: cleanup pr...
754
  	return 0;
f1aaf2622   Imre Palik   audit: move the t...
755
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
756
757
758
759
  /* called with audit_filter_mutex */
  int audit_add_tree_rule(struct audit_krule *rule)
  {
  	struct audit_tree *seed = rule->tree, *tree;
98bc993f9   Al Viro   [PATCH] get rid o...
760
  	struct path path;
1f707137b   Al Viro   new helper: itera...
761
  	struct vfsmount *mnt;
74c3cbe33   Al Viro   [PATCH] audit: wa...
762
  	int err;
736f3203a   Chen Gang   kernel/audit_tree...
763
  	rule->tree = NULL;
74c3cbe33   Al Viro   [PATCH] audit: wa...
764
765
766
767
768
769
770
771
772
773
774
775
776
  	list_for_each_entry(tree, &tree_list, list) {
  		if (!strcmp(seed->pathname, tree->pathname)) {
  			put_tree(seed);
  			rule->tree = tree;
  			list_add(&rule->rlist, &tree->rules);
  			return 0;
  		}
  	}
  	tree = seed;
  	list_add(&tree->list, &tree_list);
  	list_add(&rule->rlist, &tree->rules);
  	/* do not set rule->tree yet */
  	mutex_unlock(&audit_filter_mutex);
f1aaf2622   Imre Palik   audit: move the t...
777
778
779
780
781
  	if (unlikely(!prune_thread)) {
  		err = audit_launch_prune();
  		if (err)
  			goto Err;
  	}
98bc993f9   Al Viro   [PATCH] get rid o...
782
  	err = kern_path(tree->pathname, 0, &path);
74c3cbe33   Al Viro   [PATCH] audit: wa...
783
784
  	if (err)
  		goto Err;
589ff870e   Al Viro   Switch collect_mo...
785
  	mnt = collect_mounts(&path);
98bc993f9   Al Viro   [PATCH] get rid o...
786
  	path_put(&path);
be34d1a3b   David Howells   VFS: Make clone_m...
787
788
  	if (IS_ERR(mnt)) {
  		err = PTR_ERR(mnt);
74c3cbe33   Al Viro   [PATCH] audit: wa...
789
790
  		goto Err;
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
791
792
  
  	get_tree(tree);
1f707137b   Al Viro   new helper: itera...
793
  	err = iterate_mounts(tag_mount, tree, mnt);
74c3cbe33   Al Viro   [PATCH] audit: wa...
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
  	drop_collected_mounts(mnt);
  
  	if (!err) {
  		struct node *node;
  		spin_lock(&hash_lock);
  		list_for_each_entry(node, &tree->chunks, list)
  			node->index &= ~(1U<<31);
  		spin_unlock(&hash_lock);
  	} else {
  		trim_marked(tree);
  		goto Err;
  	}
  
  	mutex_lock(&audit_filter_mutex);
  	if (list_empty(&rule->rlist)) {
  		put_tree(tree);
  		return -ENOENT;
  	}
  	rule->tree = tree;
  	put_tree(tree);
  
  	return 0;
  Err:
  	mutex_lock(&audit_filter_mutex);
  	list_del_init(&tree->list);
  	list_del_init(&tree->rules);
  	put_tree(tree);
  	return err;
  }
  
  int audit_tag_tree(char *old, char *new)
  {
  	struct list_head cursor, barrier;
  	int failed = 0;
2096f759a   Al Viro   New helper: path_...
828
  	struct path path1, path2;
74c3cbe33   Al Viro   [PATCH] audit: wa...
829
  	struct vfsmount *tagged;
74c3cbe33   Al Viro   [PATCH] audit: wa...
830
  	int err;
2096f759a   Al Viro   New helper: path_...
831
  	err = kern_path(new, 0, &path2);
74c3cbe33   Al Viro   [PATCH] audit: wa...
832
833
  	if (err)
  		return err;
2096f759a   Al Viro   New helper: path_...
834
835
  	tagged = collect_mounts(&path2);
  	path_put(&path2);
be34d1a3b   David Howells   VFS: Make clone_m...
836
837
  	if (IS_ERR(tagged))
  		return PTR_ERR(tagged);
74c3cbe33   Al Viro   [PATCH] audit: wa...
838

2096f759a   Al Viro   New helper: path_...
839
  	err = kern_path(old, 0, &path1);
74c3cbe33   Al Viro   [PATCH] audit: wa...
840
841
842
843
  	if (err) {
  		drop_collected_mounts(tagged);
  		return err;
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
844

74c3cbe33   Al Viro   [PATCH] audit: wa...
845
846
847
848
849
850
  	mutex_lock(&audit_filter_mutex);
  	list_add(&barrier, &tree_list);
  	list_add(&cursor, &barrier);
  
  	while (cursor.next != &tree_list) {
  		struct audit_tree *tree;
2096f759a   Al Viro   New helper: path_...
851
  		int good_one = 0;
74c3cbe33   Al Viro   [PATCH] audit: wa...
852
853
854
855
856
857
  
  		tree = container_of(cursor.next, struct audit_tree, list);
  		get_tree(tree);
  		list_del(&cursor);
  		list_add(&cursor, &tree->list);
  		mutex_unlock(&audit_filter_mutex);
2096f759a   Al Viro   New helper: path_...
858
859
860
861
  		err = kern_path(tree->pathname, 0, &path2);
  		if (!err) {
  			good_one = path_is_under(&path1, &path2);
  			path_put(&path2);
74c3cbe33   Al Viro   [PATCH] audit: wa...
862
  		}
2096f759a   Al Viro   New helper: path_...
863
  		if (!good_one) {
74c3cbe33   Al Viro   [PATCH] audit: wa...
864
865
866
867
  			put_tree(tree);
  			mutex_lock(&audit_filter_mutex);
  			continue;
  		}
74c3cbe33   Al Viro   [PATCH] audit: wa...
868

1f707137b   Al Viro   new helper: itera...
869
  		failed = iterate_mounts(tag_mount, tree, tagged);
74c3cbe33   Al Viro   [PATCH] audit: wa...
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
  		if (failed) {
  			put_tree(tree);
  			mutex_lock(&audit_filter_mutex);
  			break;
  		}
  
  		mutex_lock(&audit_filter_mutex);
  		spin_lock(&hash_lock);
  		if (!tree->goner) {
  			list_del(&tree->list);
  			list_add(&tree->list, &tree_list);
  		}
  		spin_unlock(&hash_lock);
  		put_tree(tree);
  	}
  
  	while (barrier.prev != &tree_list) {
  		struct audit_tree *tree;
  
  		tree = container_of(barrier.prev, struct audit_tree, list);
  		get_tree(tree);
  		list_del(&tree->list);
  		list_add(&tree->list, &barrier);
  		mutex_unlock(&audit_filter_mutex);
  
  		if (!failed) {
  			struct node *node;
  			spin_lock(&hash_lock);
  			list_for_each_entry(node, &tree->chunks, list)
  				node->index &= ~(1U<<31);
  			spin_unlock(&hash_lock);
  		} else {
  			trim_marked(tree);
  		}
  
  		put_tree(tree);
  		mutex_lock(&audit_filter_mutex);
  	}
  	list_del(&barrier);
  	list_del(&cursor);
74c3cbe33   Al Viro   [PATCH] audit: wa...
910
  	mutex_unlock(&audit_filter_mutex);
2096f759a   Al Viro   New helper: path_...
911
  	path_put(&path1);
74c3cbe33   Al Viro   [PATCH] audit: wa...
912
913
914
  	drop_collected_mounts(tagged);
  	return failed;
  }
916d75761   Al Viro   Fix rule eviction...
915
916
917
  
  static void audit_schedule_prune(void)
  {
f1aaf2622   Imre Palik   audit: move the t...
918
  	wake_up_process(prune_thread);
916d75761   Al Viro   Fix rule eviction...
919
920
921
922
923
924
  }
  
  /*
   * ... and that one is done if evict_chunk() decides to delay until the end
   * of syscall.  Runs synchronously.
   */
9e36a5d49   Richard Guy Briggs   audit: hand taken...
925
  void audit_kill_trees(struct audit_context *context)
916d75761   Al Viro   Fix rule eviction...
926
  {
9e36a5d49   Richard Guy Briggs   audit: hand taken...
927
  	struct list_head *list = &context->killed_trees;
ce423631c   Paul Moore   audit: track the ...
928
  	audit_ctl_lock();
916d75761   Al Viro   Fix rule eviction...
929
930
931
932
933
934
  	mutex_lock(&audit_filter_mutex);
  
  	while (!list_empty(list)) {
  		struct audit_tree *victim;
  
  		victim = list_entry(list->next, struct audit_tree, list);
9e36a5d49   Richard Guy Briggs   audit: hand taken...
935
  		kill_rules(context, victim);
916d75761   Al Viro   Fix rule eviction...
936
937
938
939
940
941
942
943
944
945
  		list_del_init(&victim->list);
  
  		mutex_unlock(&audit_filter_mutex);
  
  		prune_one(victim);
  
  		mutex_lock(&audit_filter_mutex);
  	}
  
  	mutex_unlock(&audit_filter_mutex);
ce423631c   Paul Moore   audit: track the ...
946
  	audit_ctl_unlock();
74c3cbe33   Al Viro   [PATCH] audit: wa...
947
948
949
950
951
  }
  
  /*
   *  Here comes the stuff asynchronous to auditctl operations
   */
74c3cbe33   Al Viro   [PATCH] audit: wa...
952
953
954
  static void evict_chunk(struct audit_chunk *chunk)
  {
  	struct audit_tree *owner;
916d75761   Al Viro   Fix rule eviction...
955
956
  	struct list_head *postponed = audit_killed_trees();
  	int need_prune = 0;
74c3cbe33   Al Viro   [PATCH] audit: wa...
957
  	int n;
74c3cbe33   Al Viro   [PATCH] audit: wa...
958
959
960
961
962
963
964
965
966
  	mutex_lock(&audit_filter_mutex);
  	spin_lock(&hash_lock);
  	while (!list_empty(&chunk->trees)) {
  		owner = list_entry(chunk->trees.next,
  				   struct audit_tree, same_root);
  		owner->goner = 1;
  		owner->root = NULL;
  		list_del_init(&owner->same_root);
  		spin_unlock(&hash_lock);
916d75761   Al Viro   Fix rule eviction...
967
  		if (!postponed) {
9e36a5d49   Richard Guy Briggs   audit: hand taken...
968
  			kill_rules(audit_context(), owner);
916d75761   Al Viro   Fix rule eviction...
969
970
971
972
973
  			list_move(&owner->list, &prune_list);
  			need_prune = 1;
  		} else {
  			list_move(&owner->list, postponed);
  		}
74c3cbe33   Al Viro   [PATCH] audit: wa...
974
975
976
977
978
979
  		spin_lock(&hash_lock);
  	}
  	list_del_rcu(&chunk->hash);
  	for (n = 0; n < chunk->count; n++)
  		list_del_init(&chunk->owners[n].list);
  	spin_unlock(&hash_lock);
f1aaf2622   Imre Palik   audit: move the t...
980
  	mutex_unlock(&audit_filter_mutex);
916d75761   Al Viro   Fix rule eviction...
981
982
  	if (need_prune)
  		audit_schedule_prune();
74c3cbe33   Al Viro   [PATCH] audit: wa...
983
  }
3a9b16b40   Eric Paris   fsnotify: send fs...
984
  static int audit_tree_handle_event(struct fsnotify_group *group,
7053aee26   Jan Kara   fsnotify: do not ...
985
  				   struct inode *to_tell,
3cd5eca8d   Al Viro   fsnotify: constif...
986
  				   u32 mask, const void *data, int data_type,
e43e9c339   Al Viro   fsnotify: switch ...
987
  				   const struct qstr *file_name, u32 cookie,
9385a84d7   Jan Kara   fsnotify: Pass fs...
988
  				   struct fsnotify_iter_info *iter_info)
74c3cbe33   Al Viro   [PATCH] audit: wa...
989
  {
83c4c4b0a   Jan Kara   fsnotify: remove ...
990
  	return 0;
28a3a7eb3   Eric Paris   audit: reimplemen...
991
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
992

f905c2fc3   Jan Kara   audit: Use 'mark'...
993
994
  static void audit_tree_freeing_mark(struct fsnotify_mark *mark,
  				    struct fsnotify_group *group)
28a3a7eb3   Eric Paris   audit: reimplemen...
995
  {
83d23bc8a   Jan Kara   audit: Replace ch...
996
  	struct audit_chunk *chunk;
28a3a7eb3   Eric Paris   audit: reimplemen...
997

f905c2fc3   Jan Kara   audit: Use 'mark'...
998
  	mutex_lock(&mark->group->mark_mutex);
83d23bc8a   Jan Kara   audit: Replace ch...
999
  	spin_lock(&hash_lock);
f905c2fc3   Jan Kara   audit: Use 'mark'...
1000
1001
  	chunk = mark_chunk(mark);
  	replace_mark_chunk(mark, NULL);
83d23bc8a   Jan Kara   audit: Replace ch...
1002
  	spin_unlock(&hash_lock);
f905c2fc3   Jan Kara   audit: Use 'mark'...
1003
  	mutex_unlock(&mark->group->mark_mutex);
83d23bc8a   Jan Kara   audit: Replace ch...
1004
1005
1006
1007
  	if (chunk) {
  		evict_chunk(chunk);
  		audit_mark_put_chunk(chunk);
  	}
b3e8692b4   Miklos Szeredi   audit: clean up r...
1008
1009
1010
1011
1012
  
  	/*
  	 * We are guaranteed to have at least one reference to the mark from
  	 * either the inode or the caller of fsnotify_destroy_mark().
  	 */
f905c2fc3   Jan Kara   audit: Use 'mark'...
1013
  	BUG_ON(refcount_read(&mark->refcnt) < 1);
74c3cbe33   Al Viro   [PATCH] audit: wa...
1014
  }
28a3a7eb3   Eric Paris   audit: reimplemen...
1015
1016
  static const struct fsnotify_ops audit_tree_ops = {
  	.handle_event = audit_tree_handle_event,
28a3a7eb3   Eric Paris   audit: reimplemen...
1017
  	.freeing_mark = audit_tree_freeing_mark,
054c636e5   Jan Kara   fsnotify: Move ->...
1018
  	.free_mark = audit_tree_destroy_watch,
74c3cbe33   Al Viro   [PATCH] audit: wa...
1019
1020
1021
1022
1023
  };
  
  static int __init audit_tree_init(void)
  {
  	int i;
5f5161300   Jan Kara   audit: Allocate f...
1024
  	audit_tree_mark_cachep = KMEM_CACHE(audit_tree_mark, SLAB_PANIC);
0d2e2a1d0   Eric Paris   fsnotify: drop ma...
1025
  	audit_tree_group = fsnotify_alloc_group(&audit_tree_ops);
28a3a7eb3   Eric Paris   audit: reimplemen...
1026
1027
  	if (IS_ERR(audit_tree_group))
  		audit_panic("cannot initialize fsnotify group for rectree watches");
74c3cbe33   Al Viro   [PATCH] audit: wa...
1028
1029
1030
1031
1032
1033
1034
  
  	for (i = 0; i < HASH_SIZE; i++)
  		INIT_LIST_HEAD(&chunk_hash_heads[i]);
  
  	return 0;
  }
  __initcall(audit_tree_init);