Blame view

kernel/audit_tree.c 23.9 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;
e61ce8673   Eric Paris   fsnotify: rename ...
27
  	struct fsnotify_mark mark;
74c3cbe33   Al Viro   [PATCH] audit: wa...
28
29
30
  	struct list_head trees;		/* with root here */
  	int dead;
  	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
39
40
41
  	struct rcu_head head;
  	struct node {
  		struct list_head list;
  		struct audit_tree *owner;
  		unsigned index;		/* index; upper bit indicates 'will prune' */
  	} owners[];
  };
  
  static LIST_HEAD(tree_list);
  static LIST_HEAD(prune_list);
f1aaf2622   Imre Palik   audit: move the t...
42
  static struct task_struct *prune_thread;
74c3cbe33   Al Viro   [PATCH] audit: wa...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  
  /*
   * One struct chunk is attached to each inode of interest.
   * We replace struct chunk on tagging/untagging.
   * 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.
   *
28a3a7eb3   Eric Paris   audit: reimplemen...
65
   * chunk is refcounted by embedded fsnotify_mark + .refs (non-zero refcount
8f7b0ba1c   Al Viro   Fix inotify watch...
66
   * of watch contributes 1 to .refs).
74c3cbe33   Al Viro   [PATCH] audit: wa...
67
68
69
70
71
72
   *
   * 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...
73
  static struct fsnotify_group *audit_tree_group;
74c3cbe33   Al Viro   [PATCH] audit: wa...
74
75
76
77
78
79
80
  
  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...
81
  		refcount_set(&tree->count, 1);
74c3cbe33   Al Viro   [PATCH] audit: wa...
82
83
84
85
86
87
88
89
90
91
92
93
94
  		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...
95
  	refcount_inc(&tree->count);
74c3cbe33   Al Viro   [PATCH] audit: wa...
96
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
97
98
  static inline void put_tree(struct audit_tree *tree)
  {
9d2378f8c   Elena Reshetova   audit: convert au...
99
  	if (refcount_dec_and_test(&tree->count))
3b097c469   Lai Jiangshan   audit_tree,rcu: C...
100
  		kfree_rcu(tree, head);
74c3cbe33   Al Viro   [PATCH] audit: wa...
101
102
103
104
105
106
107
  }
  
  /* 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...
108
  static void free_chunk(struct audit_chunk *chunk)
74c3cbe33   Al Viro   [PATCH] audit: wa...
109
  {
74c3cbe33   Al Viro   [PATCH] audit: wa...
110
111
112
113
114
115
116
117
  	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...
118
  void audit_put_chunk(struct audit_chunk *chunk)
74c3cbe33   Al Viro   [PATCH] audit: wa...
119
  {
8f7b0ba1c   Al Viro   Fix inotify watch...
120
121
  	if (atomic_long_dec_and_test(&chunk->refs))
  		free_chunk(chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
122
  }
8f7b0ba1c   Al Viro   Fix inotify watch...
123
  static void __put_chunk(struct rcu_head *rcu)
74c3cbe33   Al Viro   [PATCH] audit: wa...
124
  {
8f7b0ba1c   Al Viro   Fix inotify watch...
125
126
  	struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
  	audit_put_chunk(chunk);
74c3cbe33   Al Viro   [PATCH] audit: wa...
127
  }
e61ce8673   Eric Paris   fsnotify: rename ...
128
  static void audit_tree_destroy_watch(struct fsnotify_mark *entry)
28a3a7eb3   Eric Paris   audit: reimplemen...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  {
  	struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
  	call_rcu(&chunk->head, __put_chunk);
  }
  
  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;
  	}
054c636e5   Jan Kara   fsnotify: Move ->...
153
  	fsnotify_init_mark(&chunk->mark, audit_tree_group);
799b60145   Miklos Szeredi   audit: keep inode...
154
  	chunk->mark.mask = FS_IN_IGNORED;
28a3a7eb3   Eric Paris   audit: reimplemen...
155
156
  	return chunk;
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
157
158
159
  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...
160
161
  /* 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...
162
  {
f410ff655   Jan Kara   audit: Abstract h...
163
164
165
166
167
168
169
  	return (unsigned long)inode;
  }
  
  /*
   * Function to return search key in our hash from chunk. Key 0 is special and
   * should never be present in the hash.
   */
6b3f05d24   Jan Kara   fsnotify: Detach ...
170
  static unsigned long chunk_to_key(struct audit_chunk *chunk)
86ffe245c   Jan Kara   fsnotify: Move ob...
171
  {
6b3f05d24   Jan Kara   fsnotify: Detach ...
172
173
174
175
176
  	/*
  	 * We have a reference to the mark so it should be attached to a
  	 * connector.
  	 */
  	if (WARN_ON_ONCE(!chunk->mark.connector))
86ffe245c   Jan Kara   fsnotify: Move ob...
177
178
179
  		return 0;
  	return (unsigned long)chunk->mark.connector->inode;
  }
f410ff655   Jan Kara   audit: Abstract h...
180
181
182
  static inline struct list_head *chunk_hash(unsigned long key)
  {
  	unsigned long n = key / L1_CACHE_BYTES;
74c3cbe33   Al Viro   [PATCH] audit: wa...
183
184
  	return chunk_hash_heads + n % HASH_SIZE;
  }
28a3a7eb3   Eric Paris   audit: reimplemen...
185
  /* hash_lock & entry->lock is held by caller */
74c3cbe33   Al Viro   [PATCH] audit: wa...
186
187
  static void insert_hash(struct audit_chunk *chunk)
  {
6b3f05d24   Jan Kara   fsnotify: Detach ...
188
  	unsigned long key = chunk_to_key(chunk);
28a3a7eb3   Eric Paris   audit: reimplemen...
189
  	struct list_head *list;
43471d15d   Jan Kara   audit_tree: Use m...
190
  	if (!(chunk->mark.flags & FSNOTIFY_MARK_FLAG_ATTACHED))
28a3a7eb3   Eric Paris   audit: reimplemen...
191
  		return;
f410ff655   Jan Kara   audit: Abstract h...
192
  	list = chunk_hash(key);
74c3cbe33   Al Viro   [PATCH] audit: wa...
193
194
195
196
197
198
  	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...
199
200
  	unsigned long key = inode_to_key(inode);
  	struct list_head *list = chunk_hash(key);
6793a051f   Paul E. McKenney   [PATCH] list_for_...
201
  	struct audit_chunk *p;
74c3cbe33   Al Viro   [PATCH] audit: wa...
202

6793a051f   Paul E. McKenney   [PATCH] list_for_...
203
  	list_for_each_entry_rcu(p, list, hash) {
f410ff655   Jan Kara   audit: Abstract h...
204
  		if (chunk_to_key(p) == key) {
8f7b0ba1c   Al Viro   Fix inotify watch...
205
  			atomic_long_inc(&p->refs);
74c3cbe33   Al Viro   [PATCH] audit: wa...
206
207
208
209
210
  			return p;
  		}
  	}
  	return NULL;
  }
6f1b5d7af   Yaowei Bai   audit: audit_tree...
211
  bool audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
74c3cbe33   Al Viro   [PATCH] audit: wa...
212
213
214
215
  {
  	int n;
  	for (n = 0; n < chunk->count; n++)
  		if (chunk->owners[n].owner == tree)
6f1b5d7af   Yaowei Bai   audit: audit_tree...
216
217
  			return true;
  	return false;
74c3cbe33   Al Viro   [PATCH] audit: wa...
218
219
220
  }
  
  /* tagging and untagging inodes with trees */
8f7b0ba1c   Al Viro   Fix inotify watch...
221
222
223
224
225
226
227
228
  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]);
  }
  
  static void untag_chunk(struct node *p)
74c3cbe33   Al Viro   [PATCH] audit: wa...
229
  {
8f7b0ba1c   Al Viro   Fix inotify watch...
230
  	struct audit_chunk *chunk = find_chunk(p);
e61ce8673   Eric Paris   fsnotify: rename ...
231
  	struct fsnotify_mark *entry = &chunk->mark;
f7a998a94   Al Viro   in untag_chunk() ...
232
  	struct audit_chunk *new = NULL;
74c3cbe33   Al Viro   [PATCH] audit: wa...
233
234
235
  	struct audit_tree *owner;
  	int size = chunk->count - 1;
  	int i, j;
28a3a7eb3   Eric Paris   audit: reimplemen...
236
  	fsnotify_get_mark(entry);
8f7b0ba1c   Al Viro   Fix inotify watch...
237
238
  
  	spin_unlock(&hash_lock);
f7a998a94   Al Viro   in untag_chunk() ...
239
240
  	if (size)
  		new = alloc_chunk(size);
be29d20f3   Jan Kara   audit: Fix sleep ...
241
  	mutex_lock(&entry->group->mark_mutex);
28a3a7eb3   Eric Paris   audit: reimplemen...
242
  	spin_lock(&entry->lock);
6b3f05d24   Jan Kara   fsnotify: Detach ...
243
244
245
246
  	/*
  	 * mark_mutex protects mark from getting detached and thus also from
  	 * mark->connector->inode getting NULL.
  	 */
43471d15d   Jan Kara   audit_tree: Use m...
247
  	if (chunk->dead || !(entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) {
28a3a7eb3   Eric Paris   audit: reimplemen...
248
  		spin_unlock(&entry->lock);
be29d20f3   Jan Kara   audit: Fix sleep ...
249
  		mutex_unlock(&entry->group->mark_mutex);
f7a998a94   Al Viro   in untag_chunk() ...
250
  		if (new)
7b1293234   Jan Kara   fsnotify: Add gro...
251
  			fsnotify_put_mark(&new->mark);
8f7b0ba1c   Al Viro   Fix inotify watch...
252
  		goto out;
74c3cbe33   Al Viro   [PATCH] audit: wa...
253
254
255
256
257
258
259
260
261
262
263
264
265
  	}
  
  	owner = p->owner;
  
  	if (!size) {
  		chunk->dead = 1;
  		spin_lock(&hash_lock);
  		list_del_init(&chunk->trees);
  		if (owner->root == chunk)
  			owner->root = NULL;
  		list_del_init(&p->list);
  		list_del_rcu(&chunk->hash);
  		spin_unlock(&hash_lock);
28a3a7eb3   Eric Paris   audit: reimplemen...
266
  		spin_unlock(&entry->lock);
be29d20f3   Jan Kara   audit: Fix sleep ...
267
  		mutex_unlock(&entry->group->mark_mutex);
e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
268
  		fsnotify_destroy_mark(entry, audit_tree_group);
8f7b0ba1c   Al Viro   Fix inotify watch...
269
  		goto out;
74c3cbe33   Al Viro   [PATCH] audit: wa...
270
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
271
272
  	if (!new)
  		goto Fallback;
f7a998a94   Al Viro   in untag_chunk() ...
273

7b1293234   Jan Kara   fsnotify: Add gro...
274
  	if (fsnotify_add_mark_locked(&new->mark, entry->connector->inode,
be29d20f3   Jan Kara   audit: Fix sleep ...
275
  				     NULL, 1)) {
0fe33aae0   Miklos Szeredi   audit: don't free...
276
  		fsnotify_put_mark(&new->mark);
74c3cbe33   Al Viro   [PATCH] audit: wa...
277
278
279
280
281
282
283
284
285
286
  		goto Fallback;
  	}
  
  	chunk->dead = 1;
  	spin_lock(&hash_lock);
  	list_replace_init(&chunk->trees, &new->trees);
  	if (owner->root == chunk) {
  		list_del_init(&owner->same_root);
  		owner->root = NULL;
  	}
6f5d51148   Al Viro   fix braindamage i...
287
  	for (i = j = 0; j <= size; i++, j++) {
74c3cbe33   Al Viro   [PATCH] audit: wa...
288
289
290
291
292
293
294
295
296
297
298
299
  		struct audit_tree *s;
  		if (&chunk->owners[j] == p) {
  			list_del_init(&p->list);
  			i--;
  			continue;
  		}
  		s = chunk->owners[j].owner;
  		new->owners[i].owner = s;
  		new->owners[i].index = chunk->owners[j].index - j + i;
  		if (!s) /* result of earlier fallback */
  			continue;
  		get_tree(s);
6f5d51148   Al Viro   fix braindamage i...
300
  		list_replace_init(&chunk->owners[j].list, &new->owners[i].list);
74c3cbe33   Al Viro   [PATCH] audit: wa...
301
302
303
304
305
306
  	}
  
  	list_replace_rcu(&chunk->hash, &new->hash);
  	list_for_each_entry(owner, &new->trees, same_root)
  		owner->root = new;
  	spin_unlock(&hash_lock);
28a3a7eb3   Eric Paris   audit: reimplemen...
307
  	spin_unlock(&entry->lock);
be29d20f3   Jan Kara   audit: Fix sleep ...
308
  	mutex_unlock(&entry->group->mark_mutex);
e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
309
  	fsnotify_destroy_mark(entry, audit_tree_group);
b3e8692b4   Miklos Szeredi   audit: clean up r...
310
  	fsnotify_put_mark(&new->mark);	/* drop initial reference */
8f7b0ba1c   Al Viro   Fix inotify watch...
311
  	goto out;
74c3cbe33   Al Viro   [PATCH] audit: wa...
312
313
314
315
316
317
318
319
320
321
322
323
  
  Fallback:
  	// do the best we can
  	spin_lock(&hash_lock);
  	if (owner->root == chunk) {
  		list_del_init(&owner->same_root);
  		owner->root = NULL;
  	}
  	list_del_init(&p->list);
  	p->owner = NULL;
  	put_tree(owner);
  	spin_unlock(&hash_lock);
28a3a7eb3   Eric Paris   audit: reimplemen...
324
  	spin_unlock(&entry->lock);
be29d20f3   Jan Kara   audit: Fix sleep ...
325
  	mutex_unlock(&entry->group->mark_mutex);
8f7b0ba1c   Al Viro   Fix inotify watch...
326
  out:
28a3a7eb3   Eric Paris   audit: reimplemen...
327
  	fsnotify_put_mark(entry);
8f7b0ba1c   Al Viro   Fix inotify watch...
328
  	spin_lock(&hash_lock);
74c3cbe33   Al Viro   [PATCH] audit: wa...
329
330
331
332
  }
  
  static int create_chunk(struct inode *inode, struct audit_tree *tree)
  {
e61ce8673   Eric Paris   fsnotify: rename ...
333
  	struct fsnotify_mark *entry;
74c3cbe33   Al Viro   [PATCH] audit: wa...
334
335
336
  	struct audit_chunk *chunk = alloc_chunk(1);
  	if (!chunk)
  		return -ENOMEM;
28a3a7eb3   Eric Paris   audit: reimplemen...
337
  	entry = &chunk->mark;
7b1293234   Jan Kara   fsnotify: Add gro...
338
  	if (fsnotify_add_mark(entry, inode, NULL, 0)) {
0fe33aae0   Miklos Szeredi   audit: don't free...
339
  		fsnotify_put_mark(entry);
74c3cbe33   Al Viro   [PATCH] audit: wa...
340
341
  		return -ENOSPC;
  	}
28a3a7eb3   Eric Paris   audit: reimplemen...
342
  	spin_lock(&entry->lock);
74c3cbe33   Al Viro   [PATCH] audit: wa...
343
344
345
346
  	spin_lock(&hash_lock);
  	if (tree->goner) {
  		spin_unlock(&hash_lock);
  		chunk->dead = 1;
28a3a7eb3   Eric Paris   audit: reimplemen...
347
  		spin_unlock(&entry->lock);
e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
348
  		fsnotify_destroy_mark(entry, audit_tree_group);
28a3a7eb3   Eric Paris   audit: reimplemen...
349
  		fsnotify_put_mark(entry);
74c3cbe33   Al Viro   [PATCH] audit: wa...
350
351
352
353
354
355
356
357
358
359
360
361
  		return 0;
  	}
  	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);
  	}
  	insert_hash(chunk);
  	spin_unlock(&hash_lock);
28a3a7eb3   Eric Paris   audit: reimplemen...
362
  	spin_unlock(&entry->lock);
b3e8692b4   Miklos Szeredi   audit: clean up r...
363
  	fsnotify_put_mark(entry);	/* drop initial reference */
74c3cbe33   Al Viro   [PATCH] audit: wa...
364
365
366
367
368
369
  	return 0;
  }
  
  /* the first tagged inode becomes root of tree */
  static int tag_chunk(struct inode *inode, struct audit_tree *tree)
  {
e61ce8673   Eric Paris   fsnotify: rename ...
370
  	struct fsnotify_mark *old_entry, *chunk_entry;
74c3cbe33   Al Viro   [PATCH] audit: wa...
371
372
373
374
  	struct audit_tree *owner;
  	struct audit_chunk *chunk, *old;
  	struct node *p;
  	int n;
b1362edfe   Jan Kara   fsnotify: Remove ...
375
376
  	old_entry = fsnotify_find_mark(&inode->i_fsnotify_marks,
  				       audit_tree_group);
28a3a7eb3   Eric Paris   audit: reimplemen...
377
  	if (!old_entry)
74c3cbe33   Al Viro   [PATCH] audit: wa...
378
  		return create_chunk(inode, tree);
28a3a7eb3   Eric Paris   audit: reimplemen...
379
  	old = container_of(old_entry, struct audit_chunk, mark);
74c3cbe33   Al Viro   [PATCH] audit: wa...
380
381
382
383
384
385
  
  	/* are we already there? */
  	spin_lock(&hash_lock);
  	for (n = 0; n < old->count; n++) {
  		if (old->owners[n].owner == tree) {
  			spin_unlock(&hash_lock);
28a3a7eb3   Eric Paris   audit: reimplemen...
386
  			fsnotify_put_mark(old_entry);
74c3cbe33   Al Viro   [PATCH] audit: wa...
387
388
389
390
391
392
  			return 0;
  		}
  	}
  	spin_unlock(&hash_lock);
  
  	chunk = alloc_chunk(old->count + 1);
b4c30aad3   Al Viro   fix more leaks in...
393
  	if (!chunk) {
28a3a7eb3   Eric Paris   audit: reimplemen...
394
  		fsnotify_put_mark(old_entry);
74c3cbe33   Al Viro   [PATCH] audit: wa...
395
  		return -ENOMEM;
b4c30aad3   Al Viro   fix more leaks in...
396
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
397

28a3a7eb3   Eric Paris   audit: reimplemen...
398
  	chunk_entry = &chunk->mark;
be29d20f3   Jan Kara   audit: Fix sleep ...
399
  	mutex_lock(&old_entry->group->mark_mutex);
28a3a7eb3   Eric Paris   audit: reimplemen...
400
  	spin_lock(&old_entry->lock);
6b3f05d24   Jan Kara   fsnotify: Detach ...
401
402
403
404
  	/*
  	 * mark_mutex protects mark from getting detached and thus also from
  	 * mark->connector->inode getting NULL.
  	 */
43471d15d   Jan Kara   audit_tree: Use m...
405
  	if (!(old_entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) {
28a3a7eb3   Eric Paris   audit: reimplemen...
406
407
  		/* old_entry is being shot, lets just lie */
  		spin_unlock(&old_entry->lock);
be29d20f3   Jan Kara   audit: Fix sleep ...
408
  		mutex_unlock(&old_entry->group->mark_mutex);
28a3a7eb3   Eric Paris   audit: reimplemen...
409
  		fsnotify_put_mark(old_entry);
7b1293234   Jan Kara   fsnotify: Add gro...
410
  		fsnotify_put_mark(&chunk->mark);
28a3a7eb3   Eric Paris   audit: reimplemen...
411
412
  		return -ENOENT;
  	}
7b1293234   Jan Kara   fsnotify: Add gro...
413
  	if (fsnotify_add_mark_locked(chunk_entry,
86ffe245c   Jan Kara   fsnotify: Move ob...
414
  			     old_entry->connector->inode, NULL, 1)) {
28a3a7eb3   Eric Paris   audit: reimplemen...
415
  		spin_unlock(&old_entry->lock);
be29d20f3   Jan Kara   audit: Fix sleep ...
416
  		mutex_unlock(&old_entry->group->mark_mutex);
0fe33aae0   Miklos Szeredi   audit: don't free...
417
  		fsnotify_put_mark(chunk_entry);
28a3a7eb3   Eric Paris   audit: reimplemen...
418
  		fsnotify_put_mark(old_entry);
74c3cbe33   Al Viro   [PATCH] audit: wa...
419
420
  		return -ENOSPC;
  	}
28a3a7eb3   Eric Paris   audit: reimplemen...
421
422
423
  
  	/* even though we hold old_entry->lock, this is safe since chunk_entry->lock could NEVER have been grabbed before */
  	spin_lock(&chunk_entry->lock);
74c3cbe33   Al Viro   [PATCH] audit: wa...
424
  	spin_lock(&hash_lock);
28a3a7eb3   Eric Paris   audit: reimplemen...
425
426
  
  	/* we now hold old_entry->lock, chunk_entry->lock, and hash_lock */
74c3cbe33   Al Viro   [PATCH] audit: wa...
427
428
429
  	if (tree->goner) {
  		spin_unlock(&hash_lock);
  		chunk->dead = 1;
28a3a7eb3   Eric Paris   audit: reimplemen...
430
431
  		spin_unlock(&chunk_entry->lock);
  		spin_unlock(&old_entry->lock);
be29d20f3   Jan Kara   audit: Fix sleep ...
432
  		mutex_unlock(&old_entry->group->mark_mutex);
28a3a7eb3   Eric Paris   audit: reimplemen...
433

e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
434
  		fsnotify_destroy_mark(chunk_entry, audit_tree_group);
28a3a7eb3   Eric Paris   audit: reimplemen...
435
436
437
  
  		fsnotify_put_mark(chunk_entry);
  		fsnotify_put_mark(old_entry);
74c3cbe33   Al Viro   [PATCH] audit: wa...
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
  		return 0;
  	}
  	list_replace_init(&old->trees, &chunk->trees);
  	for (n = 0, p = chunk->owners; n < old->count; n++, p++) {
  		struct audit_tree *s = old->owners[n].owner;
  		p->owner = s;
  		p->index = old->owners[n].index;
  		if (!s) /* result of fallback in untag */
  			continue;
  		get_tree(s);
  		list_replace_init(&old->owners[n].list, &p->list);
  	}
  	p->index = (chunk->count - 1) | (1U<<31);
  	p->owner = tree;
  	get_tree(tree);
  	list_add(&p->list, &tree->chunks);
  	list_replace_rcu(&old->hash, &chunk->hash);
  	list_for_each_entry(owner, &chunk->trees, same_root)
  		owner->root = chunk;
  	old->dead = 1;
  	if (!tree->root) {
  		tree->root = chunk;
  		list_add(&tree->same_root, &chunk->trees);
  	}
  	spin_unlock(&hash_lock);
28a3a7eb3   Eric Paris   audit: reimplemen...
463
464
  	spin_unlock(&chunk_entry->lock);
  	spin_unlock(&old_entry->lock);
be29d20f3   Jan Kara   audit: Fix sleep ...
465
  	mutex_unlock(&old_entry->group->mark_mutex);
e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
466
  	fsnotify_destroy_mark(old_entry, audit_tree_group);
b3e8692b4   Miklos Szeredi   audit: clean up r...
467
  	fsnotify_put_mark(chunk_entry);	/* drop initial reference */
28a3a7eb3   Eric Paris   audit: reimplemen...
468
  	fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */
74c3cbe33   Al Viro   [PATCH] audit: wa...
469
470
  	return 0;
  }
2991dd2b0   Richard Guy Briggs   audit: rename aud...
471
  static void audit_tree_log_remove_rule(struct audit_krule *rule)
0644ec0cc   Kees Cook   audit: catch poss...
472
473
474
475
476
477
  {
  	struct audit_buffer *ab;
  
  	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
  	if (unlikely(!ab))
  		return;
c1e8f06d7   Steve Grubb   audit: fix format...
478
  	audit_log_format(ab, "op=remove_rule");
0644ec0cc   Kees Cook   audit: catch poss...
479
480
481
482
483
484
  	audit_log_format(ab, " dir=");
  	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);
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
485
486
487
488
  static void kill_rules(struct audit_tree *tree)
  {
  	struct audit_krule *rule, *next;
  	struct audit_entry *entry;
74c3cbe33   Al Viro   [PATCH] audit: wa...
489
490
491
492
493
494
495
  
  	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 */
2991dd2b0   Richard Guy Briggs   audit: rename aud...
496
  			audit_tree_log_remove_rule(rule);
34d99af52   Richard Guy Briggs   audit: implement ...
497
498
  			if (entry->rule.exe)
  				audit_remove_mark(entry->rule.exe);
74c3cbe33   Al Viro   [PATCH] audit: wa...
499
500
  			rule->tree = NULL;
  			list_del_rcu(&entry->list);
e45aa212e   Al Viro   audit rules order...
501
  			list_del(&entry->rule.list);
74c3cbe33   Al Viro   [PATCH] audit: wa...
502
503
504
505
506
507
508
509
510
511
512
513
514
  			call_rcu(&entry->rcu, audit_free_rule_rcu);
  		}
  	}
  }
  
  /*
   * finish killing struct audit_tree
   */
  static void prune_one(struct audit_tree *victim)
  {
  	spin_lock(&hash_lock);
  	while (!list_empty(&victim->chunks)) {
  		struct node *p;
74c3cbe33   Al Viro   [PATCH] audit: wa...
515
516
  
  		p = list_entry(victim->chunks.next, struct node, list);
74c3cbe33   Al Viro   [PATCH] audit: wa...
517

8f7b0ba1c   Al Viro   Fix inotify watch...
518
  		untag_chunk(p);
74c3cbe33   Al Viro   [PATCH] audit: wa...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  	}
  	spin_unlock(&hash_lock);
  	put_tree(victim);
  }
  
  /* 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);
  		}
  	}
  
  	while (!list_empty(&tree->chunks)) {
  		struct node *node;
74c3cbe33   Al Viro   [PATCH] audit: wa...
546
547
548
549
550
551
  
  		node = list_entry(tree->chunks.next, struct node, list);
  
  		/* have we run out of marked? */
  		if (!(node->index & (1U<<31)))
  			break;
8f7b0ba1c   Al Viro   Fix inotify watch...
552
  		untag_chunk(node);
74c3cbe33   Al Viro   [PATCH] audit: wa...
553
554
555
556
557
558
559
560
561
562
563
564
565
  	}
  	if (!tree->root && !tree->goner) {
  		tree->goner = 1;
  		spin_unlock(&hash_lock);
  		mutex_lock(&audit_filter_mutex);
  		kill_rules(tree);
  		list_del_init(&tree->list);
  		mutex_unlock(&audit_filter_mutex);
  		prune_one(tree);
  	} else {
  		spin_unlock(&hash_lock);
  	}
  }
916d75761   Al Viro   Fix rule eviction...
566
  static void audit_schedule_prune(void);
74c3cbe33   Al Viro   [PATCH] audit: wa...
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
  /* 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...
591
592
  static int compare_root(struct vfsmount *mnt, void *arg)
  {
f410ff655   Jan Kara   audit: Abstract h...
593
594
  	return inode_to_key(d_backing_inode(mnt->mnt_root)) ==
  	       (unsigned long)arg;
1f707137b   Al Viro   new helper: itera...
595
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
596
597
598
599
600
601
602
603
  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...
604
  		struct path path;
74c3cbe33   Al Viro   [PATCH] audit: wa...
605
606
  		struct vfsmount *root_mnt;
  		struct node *node;
74c3cbe33   Al Viro   [PATCH] audit: wa...
607
608
609
610
611
612
613
  		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...
614
  		err = kern_path(tree->pathname, 0, &path);
74c3cbe33   Al Viro   [PATCH] audit: wa...
615
616
  		if (err)
  			goto skip_it;
589ff870e   Al Viro   Switch collect_mo...
617
  		root_mnt = collect_mounts(&path);
98bc993f9   Al Viro   [PATCH] get rid o...
618
  		path_put(&path);
be34d1a3b   David Howells   VFS: Make clone_m...
619
  		if (IS_ERR(root_mnt))
74c3cbe33   Al Viro   [PATCH] audit: wa...
620
  			goto skip_it;
74c3cbe33   Al Viro   [PATCH] audit: wa...
621
622
  		spin_lock(&hash_lock);
  		list_for_each_entry(node, &tree->chunks, list) {
28a3a7eb3   Eric Paris   audit: reimplemen...
623
  			struct audit_chunk *chunk = find_chunk(node);
25985edce   Lucas De Marchi   Fix common misspe...
624
  			/* this could be NULL if the watch is dying else where... */
74c3cbe33   Al Viro   [PATCH] audit: wa...
625
  			node->index |= 1U<<31;
f410ff655   Jan Kara   audit: Abstract h...
626
627
628
  			if (iterate_mounts(compare_root,
  					   (void *)chunk_to_key(chunk),
  					   root_mnt))
1f707137b   Al Viro   new helper: itera...
629
  				node->index &= ~(1U<<31);
74c3cbe33   Al Viro   [PATCH] audit: wa...
630
631
632
  		}
  		spin_unlock(&hash_lock);
  		trim_marked(tree);
74c3cbe33   Al Viro   [PATCH] audit: wa...
633
634
  		drop_collected_mounts(root_mnt);
  skip_it:
12b2f117f   Chen Gang   kernel/audit_tree...
635
  		put_tree(tree);
74c3cbe33   Al Viro   [PATCH] audit: wa...
636
637
638
639
640
  		mutex_lock(&audit_filter_mutex);
  	}
  	list_del(&cursor);
  	mutex_unlock(&audit_filter_mutex);
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
641
642
643
644
645
  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...
646
  	    op != Audit_equal ||
74c3cbe33   Al Viro   [PATCH] audit: wa...
647
648
649
650
651
652
653
654
655
656
657
658
  	    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...
659
660
  static int tag_mount(struct vfsmount *mnt, void *arg)
  {
3b362157b   David Howells   VFS: audit: d_bac...
661
  	return tag_chunk(d_backing_inode(mnt->mnt_root), arg);
1f707137b   Al Viro   new helper: itera...
662
  }
f1aaf2622   Imre Palik   audit: move the t...
663
664
665
666
667
668
669
  /*
   * 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...
670
671
  		if (list_empty(&prune_list)) {
  			set_current_state(TASK_INTERRUPTIBLE);
f1aaf2622   Imre Palik   audit: move the t...
672
  			schedule();
0bf676d1f   Jiri Slaby   audit: cleanup pr...
673
  		}
f1aaf2622   Imre Palik   audit: move the t...
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
  
  		mutex_lock(&audit_cmd_mutex);
  		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);
  		mutex_unlock(&audit_cmd_mutex);
  	}
  	return 0;
  }
  
  static int audit_launch_prune(void)
  {
  	if (prune_thread)
  		return 0;
0bf676d1f   Jiri Slaby   audit: cleanup pr...
702
  	prune_thread = kthread_run(prune_tree_thread, NULL,
f1aaf2622   Imre Palik   audit: move the t...
703
704
705
706
707
  				"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...
708
  	}
0bf676d1f   Jiri Slaby   audit: cleanup pr...
709
  	return 0;
f1aaf2622   Imre Palik   audit: move the t...
710
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
711
712
713
714
  /* 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...
715
  	struct path path;
1f707137b   Al Viro   new helper: itera...
716
  	struct vfsmount *mnt;
74c3cbe33   Al Viro   [PATCH] audit: wa...
717
  	int err;
736f3203a   Chen Gang   kernel/audit_tree...
718
  	rule->tree = NULL;
74c3cbe33   Al Viro   [PATCH] audit: wa...
719
720
721
722
723
724
725
726
727
728
729
730
731
  	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...
732
733
734
735
736
  	if (unlikely(!prune_thread)) {
  		err = audit_launch_prune();
  		if (err)
  			goto Err;
  	}
98bc993f9   Al Viro   [PATCH] get rid o...
737
  	err = kern_path(tree->pathname, 0, &path);
74c3cbe33   Al Viro   [PATCH] audit: wa...
738
739
  	if (err)
  		goto Err;
589ff870e   Al Viro   Switch collect_mo...
740
  	mnt = collect_mounts(&path);
98bc993f9   Al Viro   [PATCH] get rid o...
741
  	path_put(&path);
be34d1a3b   David Howells   VFS: Make clone_m...
742
743
  	if (IS_ERR(mnt)) {
  		err = PTR_ERR(mnt);
74c3cbe33   Al Viro   [PATCH] audit: wa...
744
745
  		goto Err;
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
746
747
  
  	get_tree(tree);
1f707137b   Al Viro   new helper: itera...
748
  	err = iterate_mounts(tag_mount, tree, mnt);
74c3cbe33   Al Viro   [PATCH] audit: wa...
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
  	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_...
783
  	struct path path1, path2;
74c3cbe33   Al Viro   [PATCH] audit: wa...
784
  	struct vfsmount *tagged;
74c3cbe33   Al Viro   [PATCH] audit: wa...
785
  	int err;
2096f759a   Al Viro   New helper: path_...
786
  	err = kern_path(new, 0, &path2);
74c3cbe33   Al Viro   [PATCH] audit: wa...
787
788
  	if (err)
  		return err;
2096f759a   Al Viro   New helper: path_...
789
790
  	tagged = collect_mounts(&path2);
  	path_put(&path2);
be34d1a3b   David Howells   VFS: Make clone_m...
791
792
  	if (IS_ERR(tagged))
  		return PTR_ERR(tagged);
74c3cbe33   Al Viro   [PATCH] audit: wa...
793

2096f759a   Al Viro   New helper: path_...
794
  	err = kern_path(old, 0, &path1);
74c3cbe33   Al Viro   [PATCH] audit: wa...
795
796
797
798
  	if (err) {
  		drop_collected_mounts(tagged);
  		return err;
  	}
74c3cbe33   Al Viro   [PATCH] audit: wa...
799

74c3cbe33   Al Viro   [PATCH] audit: wa...
800
801
802
803
804
805
  	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_...
806
  		int good_one = 0;
74c3cbe33   Al Viro   [PATCH] audit: wa...
807
808
809
810
811
812
  
  		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_...
813
814
815
816
  		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...
817
  		}
2096f759a   Al Viro   New helper: path_...
818
  		if (!good_one) {
74c3cbe33   Al Viro   [PATCH] audit: wa...
819
820
821
822
  			put_tree(tree);
  			mutex_lock(&audit_filter_mutex);
  			continue;
  		}
74c3cbe33   Al Viro   [PATCH] audit: wa...
823

1f707137b   Al Viro   new helper: itera...
824
  		failed = iterate_mounts(tag_mount, tree, tagged);
74c3cbe33   Al Viro   [PATCH] audit: wa...
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
  		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...
865
  	mutex_unlock(&audit_filter_mutex);
2096f759a   Al Viro   New helper: path_...
866
  	path_put(&path1);
74c3cbe33   Al Viro   [PATCH] audit: wa...
867
868
869
  	drop_collected_mounts(tagged);
  	return failed;
  }
916d75761   Al Viro   Fix rule eviction...
870
871
872
  
  static void audit_schedule_prune(void)
  {
f1aaf2622   Imre Palik   audit: move the t...
873
  	wake_up_process(prune_thread);
916d75761   Al Viro   Fix rule eviction...
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
  }
  
  /*
   * ... and that one is done if evict_chunk() decides to delay until the end
   * of syscall.  Runs synchronously.
   */
  void audit_kill_trees(struct list_head *list)
  {
  	mutex_lock(&audit_cmd_mutex);
  	mutex_lock(&audit_filter_mutex);
  
  	while (!list_empty(list)) {
  		struct audit_tree *victim;
  
  		victim = list_entry(list->next, struct audit_tree, list);
  		kill_rules(victim);
  		list_del_init(&victim->list);
  
  		mutex_unlock(&audit_filter_mutex);
  
  		prune_one(victim);
  
  		mutex_lock(&audit_filter_mutex);
  	}
  
  	mutex_unlock(&audit_filter_mutex);
  	mutex_unlock(&audit_cmd_mutex);
74c3cbe33   Al Viro   [PATCH] audit: wa...
901
902
903
904
905
  }
  
  /*
   *  Here comes the stuff asynchronous to auditctl operations
   */
74c3cbe33   Al Viro   [PATCH] audit: wa...
906
907
908
  static void evict_chunk(struct audit_chunk *chunk)
  {
  	struct audit_tree *owner;
916d75761   Al Viro   Fix rule eviction...
909
910
  	struct list_head *postponed = audit_killed_trees();
  	int need_prune = 0;
74c3cbe33   Al Viro   [PATCH] audit: wa...
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
  	int n;
  
  	if (chunk->dead)
  		return;
  
  	chunk->dead = 1;
  	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...
926
927
928
929
930
931
932
  		if (!postponed) {
  			kill_rules(owner);
  			list_move(&owner->list, &prune_list);
  			need_prune = 1;
  		} else {
  			list_move(&owner->list, postponed);
  		}
74c3cbe33   Al Viro   [PATCH] audit: wa...
933
934
935
936
937
938
  		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...
939
  	mutex_unlock(&audit_filter_mutex);
916d75761   Al Viro   Fix rule eviction...
940
941
  	if (need_prune)
  		audit_schedule_prune();
74c3cbe33   Al Viro   [PATCH] audit: wa...
942
  }
3a9b16b40   Eric Paris   fsnotify: send fs...
943
  static int audit_tree_handle_event(struct fsnotify_group *group,
7053aee26   Jan Kara   fsnotify: do not ...
944
  				   struct inode *to_tell,
ce8f76fb7   Eric Paris   fsnotify: pass bo...
945
  				   struct fsnotify_mark *inode_mark,
7053aee26   Jan Kara   fsnotify: do not ...
946
  				   struct fsnotify_mark *vfsmount_mark,
3cd5eca8d   Al Viro   fsnotify: constif...
947
  				   u32 mask, const void *data, int data_type,
9385a84d7   Jan Kara   fsnotify: Pass fs...
948
949
  				   const unsigned char *file_name, u32 cookie,
  				   struct fsnotify_iter_info *iter_info)
74c3cbe33   Al Viro   [PATCH] audit: wa...
950
  {
83c4c4b0a   Jan Kara   fsnotify: remove ...
951
  	return 0;
28a3a7eb3   Eric Paris   audit: reimplemen...
952
  }
74c3cbe33   Al Viro   [PATCH] audit: wa...
953

e61ce8673   Eric Paris   fsnotify: rename ...
954
  static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group)
28a3a7eb3   Eric Paris   audit: reimplemen...
955
956
957
958
  {
  	struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
  
  	evict_chunk(chunk);
b3e8692b4   Miklos Szeredi   audit: clean up r...
959
960
961
962
963
964
  
  	/*
  	 * We are guaranteed to have at least one reference to the mark from
  	 * either the inode or the caller of fsnotify_destroy_mark().
  	 */
  	BUG_ON(atomic_read(&entry->refcnt) < 1);
74c3cbe33   Al Viro   [PATCH] audit: wa...
965
  }
28a3a7eb3   Eric Paris   audit: reimplemen...
966
967
  static const struct fsnotify_ops audit_tree_ops = {
  	.handle_event = audit_tree_handle_event,
28a3a7eb3   Eric Paris   audit: reimplemen...
968
  	.freeing_mark = audit_tree_freeing_mark,
054c636e5   Jan Kara   fsnotify: Move ->...
969
  	.free_mark = audit_tree_destroy_watch,
74c3cbe33   Al Viro   [PATCH] audit: wa...
970
971
972
973
974
  };
  
  static int __init audit_tree_init(void)
  {
  	int i;
0d2e2a1d0   Eric Paris   fsnotify: drop ma...
975
  	audit_tree_group = fsnotify_alloc_group(&audit_tree_ops);
28a3a7eb3   Eric Paris   audit: reimplemen...
976
977
  	if (IS_ERR(audit_tree_group))
  		audit_panic("cannot initialize fsnotify group for rectree watches");
74c3cbe33   Al Viro   [PATCH] audit: wa...
978
979
980
981
982
983
984
  
  	for (i = 0; i < HASH_SIZE; i++)
  		INIT_LIST_HEAD(&chunk_hash_heads[i]);
  
  	return 0;
  }
  __initcall(audit_tree_init);