Blame view

kernel/audit_watch.c 13.6 KB
cfcad62c7   Eric Paris   audit: seperate a...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /* audit_watch.c -- watching inodes
   *
   * Copyright 2003-2009 Red Hat, Inc.
   * Copyright 2005 Hewlett-Packard Development Company, L.P.
   * Copyright 2005 IBM Corporation
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  #include <linux/kernel.h>
  #include <linux/audit.h>
  #include <linux/kthread.h>
  #include <linux/mutex.h>
  #include <linux/fs.h>
e9fd702a5   Eric Paris   audit: convert au...
27
  #include <linux/fsnotify_backend.h>
cfcad62c7   Eric Paris   audit: seperate a...
28
29
30
  #include <linux/namei.h>
  #include <linux/netlink.h>
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
31
  #include <linux/slab.h>
cfcad62c7   Eric Paris   audit: seperate a...
32
33
34
35
36
37
  #include <linux/security.h>
  #include "audit.h"
  
  /*
   * Reference counting:
   *
e9fd702a5   Eric Paris   audit: convert au...
38
   * audit_parent: lifetime is from audit_init_parent() to receipt of an FS_IGNORED
cfcad62c7   Eric Paris   audit: seperate a...
39
40
41
42
43
44
45
46
47
48
   * 	event.  Each audit_watch holds a reference to its associated parent.
   *
   * audit_watch: if added to lists, lifetime is from audit_init_watch() to
   * 	audit_remove_watch().  Additionally, an audit_watch may exist
   * 	temporarily to assist in searching existing filter data.  Each
   * 	audit_krule holds a reference to its associated watch.
   */
  
  struct audit_watch {
  	atomic_t		count;	/* reference count */
cfcad62c7   Eric Paris   audit: seperate a...
49
  	dev_t			dev;	/* associated superblock device */
e08b061ec   Eric Paris   Audit: reorganize...
50
  	char			*path;	/* insertion path */
cfcad62c7   Eric Paris   audit: seperate a...
51
52
53
  	unsigned long		ino;	/* associated inode number */
  	struct audit_parent	*parent; /* associated parent */
  	struct list_head	wlist;	/* entry in parent->watches list */
ae7b8f410   Eric Paris   Audit: clean up t...
54
  	struct list_head	rules;	/* anchor for krule->rlist */
cfcad62c7   Eric Paris   audit: seperate a...
55
56
57
  };
  
  struct audit_parent {
ae7b8f410   Eric Paris   Audit: clean up t...
58
  	struct list_head	watches; /* anchor for audit_watch->wlist */
e61ce8673   Eric Paris   fsnotify: rename ...
59
  	struct fsnotify_mark mark; /* fsnotify mark on the inode */
cfcad62c7   Eric Paris   audit: seperate a...
60
  };
e9fd702a5   Eric Paris   audit: convert au...
61
  /* fsnotify handle. */
b8800aa5d   Stephen Hemminger   audit: make funct...
62
  static struct fsnotify_group *audit_watch_group;
cfcad62c7   Eric Paris   audit: seperate a...
63

e9fd702a5   Eric Paris   audit: convert au...
64
65
66
  /* fsnotify events we care about. */
  #define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
  			FS_MOVE_SELF | FS_EVENT_ON_CHILD)
cfcad62c7   Eric Paris   audit: seperate a...
67

ae7b8f410   Eric Paris   Audit: clean up t...
68
69
70
71
72
  static void audit_free_parent(struct audit_parent *parent)
  {
  	WARN_ON(!list_empty(&parent->watches));
  	kfree(parent);
  }
e61ce8673   Eric Paris   fsnotify: rename ...
73
  static void audit_watch_free_mark(struct fsnotify_mark *entry)
cfcad62c7   Eric Paris   audit: seperate a...
74
75
  {
  	struct audit_parent *parent;
e9fd702a5   Eric Paris   audit: convert au...
76
  	parent = container_of(entry, struct audit_parent, mark);
ae7b8f410   Eric Paris   Audit: clean up t...
77
  	audit_free_parent(parent);
cfcad62c7   Eric Paris   audit: seperate a...
78
  }
e9fd702a5   Eric Paris   audit: convert au...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  static void audit_get_parent(struct audit_parent *parent)
  {
  	if (likely(parent))
  		fsnotify_get_mark(&parent->mark);
  }
  
  static void audit_put_parent(struct audit_parent *parent)
  {
  	if (likely(parent))
  		fsnotify_put_mark(&parent->mark);
  }
  
  /*
   * Find and return the audit_parent on the given inode.  If found a reference
   * is taken on this parent.
   */
  static inline struct audit_parent *audit_find_parent(struct inode *inode)
  {
  	struct audit_parent *parent = NULL;
e61ce8673   Eric Paris   fsnotify: rename ...
98
  	struct fsnotify_mark *entry;
e9fd702a5   Eric Paris   audit: convert au...
99

5444e2981   Eric Paris   fsnotify: split g...
100
  	entry = fsnotify_find_inode_mark(audit_watch_group, inode);
e9fd702a5   Eric Paris   audit: convert au...
101
102
103
104
105
  	if (entry)
  		parent = container_of(entry, struct audit_parent, mark);
  
  	return parent;
  }
cfcad62c7   Eric Paris   audit: seperate a...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  void audit_get_watch(struct audit_watch *watch)
  {
  	atomic_inc(&watch->count);
  }
  
  void audit_put_watch(struct audit_watch *watch)
  {
  	if (atomic_dec_and_test(&watch->count)) {
  		WARN_ON(watch->parent);
  		WARN_ON(!list_empty(&watch->rules));
  		kfree(watch->path);
  		kfree(watch);
  	}
  }
b8800aa5d   Stephen Hemminger   audit: make funct...
120
  static void audit_remove_watch(struct audit_watch *watch)
cfcad62c7   Eric Paris   audit: seperate a...
121
122
  {
  	list_del(&watch->wlist);
e9fd702a5   Eric Paris   audit: convert au...
123
  	audit_put_parent(watch->parent);
cfcad62c7   Eric Paris   audit: seperate a...
124
125
126
127
128
129
130
131
  	watch->parent = NULL;
  	audit_put_watch(watch); /* match initial get */
  }
  
  char *audit_watch_path(struct audit_watch *watch)
  {
  	return watch->path;
  }
ae7b8f410   Eric Paris   Audit: clean up t...
132
  int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
cfcad62c7   Eric Paris   audit: seperate a...
133
  {
ae7b8f410   Eric Paris   Audit: clean up t...
134
135
136
  	return (watch->ino != (unsigned long)-1) &&
  		(watch->ino == ino) &&
  		(watch->dev == dev);
cfcad62c7   Eric Paris   audit: seperate a...
137
138
139
  }
  
  /* Initialize a parent watch entry. */
15a9155fe   Al Viro   fix race in audit...
140
  static struct audit_parent *audit_init_parent(struct path *path)
cfcad62c7   Eric Paris   audit: seperate a...
141
  {
15a9155fe   Al Viro   fix race in audit...
142
  	struct inode *inode = path->dentry->d_inode;
cfcad62c7   Eric Paris   audit: seperate a...
143
  	struct audit_parent *parent;
e9fd702a5   Eric Paris   audit: convert au...
144
  	int ret;
cfcad62c7   Eric Paris   audit: seperate a...
145
146
147
148
149
150
  
  	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
  	if (unlikely(!parent))
  		return ERR_PTR(-ENOMEM);
  
  	INIT_LIST_HEAD(&parent->watches);
cfcad62c7   Eric Paris   audit: seperate a...
151

e9fd702a5   Eric Paris   audit: convert au...
152
153
  	fsnotify_init_mark(&parent->mark, audit_watch_free_mark);
  	parent->mark.mask = AUDIT_FS_WATCH;
5444e2981   Eric Paris   fsnotify: split g...
154
  	ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode, NULL, 0);
e9fd702a5   Eric Paris   audit: convert au...
155
  	if (ret < 0) {
ae7b8f410   Eric Paris   Audit: clean up t...
156
  		audit_free_parent(parent);
e9fd702a5   Eric Paris   audit: convert au...
157
  		return ERR_PTR(ret);
cfcad62c7   Eric Paris   audit: seperate a...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  	}
  
  	return parent;
  }
  
  /* Initialize a watch entry. */
  static struct audit_watch *audit_init_watch(char *path)
  {
  	struct audit_watch *watch;
  
  	watch = kzalloc(sizeof(*watch), GFP_KERNEL);
  	if (unlikely(!watch))
  		return ERR_PTR(-ENOMEM);
  
  	INIT_LIST_HEAD(&watch->rules);
  	atomic_set(&watch->count, 1);
  	watch->path = path;
  	watch->dev = (dev_t)-1;
  	watch->ino = (unsigned long)-1;
  
  	return watch;
  }
  
  /* Translate a watch string to kernel respresentation. */
  int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
  {
  	struct audit_watch *watch;
e9fd702a5   Eric Paris   audit: convert au...
185
  	if (!audit_watch_group)
cfcad62c7   Eric Paris   audit: seperate a...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  		return -EOPNOTSUPP;
  
  	if (path[0] != '/' || path[len-1] == '/' ||
  	    krule->listnr != AUDIT_FILTER_EXIT ||
  	    op != Audit_equal ||
  	    krule->inode_f || krule->watch || krule->tree)
  		return -EINVAL;
  
  	watch = audit_init_watch(path);
  	if (IS_ERR(watch))
  		return PTR_ERR(watch);
  
  	audit_get_watch(watch);
  	krule->watch = watch;
  
  	return 0;
  }
  
  /* Duplicate the given audit watch.  The new watch's rules list is initialized
   * to an empty list and wlist is undefined. */
  static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
  {
  	char *path;
  	struct audit_watch *new;
  
  	path = kstrdup(old->path, GFP_KERNEL);
  	if (unlikely(!path))
  		return ERR_PTR(-ENOMEM);
  
  	new = audit_init_watch(path);
  	if (IS_ERR(new)) {
  		kfree(path);
  		goto out;
  	}
  
  	new->dev = old->dev;
  	new->ino = old->ino;
e9fd702a5   Eric Paris   audit: convert au...
223
  	audit_get_parent(old->parent);
cfcad62c7   Eric Paris   audit: seperate a...
224
225
226
227
228
229
230
231
232
233
234
  	new->parent = old->parent;
  
  out:
  	return new;
  }
  
  static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watch *w, char *op)
  {
  	if (audit_enabled) {
  		struct audit_buffer *ab;
  		ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
0644ec0cc   Kees Cook   audit: catch poss...
235
236
  		if (unlikely(!ab))
  			return;
cfcad62c7   Eric Paris   audit: seperate a...
237
  		audit_log_format(ab, "auid=%u ses=%u op=",
e1760bd5f   Eric W. Biederman   userns: Convert t...
238
  				 from_kuid(&init_user_ns, audit_get_loginuid(current)),
cfcad62c7   Eric Paris   audit: seperate a...
239
240
241
242
  				 audit_get_sessionid(current));
  		audit_log_string(ab, op);
  		audit_log_format(ab, " path=");
  		audit_log_untrustedstring(ab, w->path);
9d9609851   Eric Paris   Audit: clean up a...
243
  		audit_log_key(ab, r->filterkey);
cfcad62c7   Eric Paris   audit: seperate a...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  		audit_log_format(ab, " list=%d res=1", r->listnr);
  		audit_log_end(ab);
  	}
  }
  
  /* Update inode info in audit rules based on filesystem event. */
  static void audit_update_watch(struct audit_parent *parent,
  			       const char *dname, dev_t dev,
  			       unsigned long ino, unsigned invalidating)
  {
  	struct audit_watch *owatch, *nwatch, *nextw;
  	struct audit_krule *r, *nextr;
  	struct audit_entry *oentry, *nentry;
  
  	mutex_lock(&audit_filter_mutex);
ae7b8f410   Eric Paris   Audit: clean up t...
259
260
  	/* Run all of the watches on this parent looking for the one that
  	 * matches the given dname */
cfcad62c7   Eric Paris   audit: seperate a...
261
  	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
e3d6b07b8   Jeff Layton   audit: optimize a...
262
263
  		if (audit_compare_dname_path(dname, owatch->path,
  					     AUDIT_NAME_FULL))
cfcad62c7   Eric Paris   audit: seperate a...
264
265
266
267
  			continue;
  
  		/* If the update involves invalidating rules, do the inode-based
  		 * filtering now, so we don't omit records. */
ae7b8f410   Eric Paris   Audit: clean up t...
268
  		if (invalidating && !audit_dummy_context())
cfcad62c7   Eric Paris   audit: seperate a...
269
  			audit_filter_inodes(current, current->audit_context);
ae7b8f410   Eric Paris   Audit: clean up t...
270
271
  		/* updating ino will likely change which audit_hash_list we
  		 * are on so we need a new watch for the new list */
cfcad62c7   Eric Paris   audit: seperate a...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  		nwatch = audit_dupe_watch(owatch);
  		if (IS_ERR(nwatch)) {
  			mutex_unlock(&audit_filter_mutex);
  			audit_panic("error updating watch, skipping");
  			return;
  		}
  		nwatch->dev = dev;
  		nwatch->ino = ino;
  
  		list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
  
  			oentry = container_of(r, struct audit_entry, rule);
  			list_del(&oentry->rule.rlist);
  			list_del_rcu(&oentry->list);
ae7b8f410   Eric Paris   Audit: clean up t...
286
  			nentry = audit_dupe_rule(&oentry->rule);
cfcad62c7   Eric Paris   audit: seperate a...
287
288
289
290
291
  			if (IS_ERR(nentry)) {
  				list_del(&oentry->rule.list);
  				audit_panic("error updating watch, removing");
  			} else {
  				int h = audit_hash_ino((u32)ino);
ae7b8f410   Eric Paris   Audit: clean up t...
292
293
294
295
296
297
298
299
300
  
  				/*
  				 * nentry->rule.watch == oentry->rule.watch so
  				 * we must drop that reference and set it to our
  				 * new watch.
  				 */
  				audit_put_watch(nentry->rule.watch);
  				audit_get_watch(nwatch);
  				nentry->rule.watch = nwatch;
cfcad62c7   Eric Paris   audit: seperate a...
301
302
303
304
305
  				list_add(&nentry->rule.rlist, &nwatch->rules);
  				list_add_rcu(&nentry->list, &audit_inode_hash[h]);
  				list_replace(&oentry->rule.list,
  					     &nentry->rule.list);
  			}
e7df61f4d   Burn Alting   audit: invalid op...
306
  			audit_watch_log_rule_change(r, owatch, "updated_rules");
cfcad62c7   Eric Paris   audit: seperate a...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  
  			call_rcu(&oentry->rcu, audit_free_rule_rcu);
  		}
  
  		audit_remove_watch(owatch);
  		goto add_watch_to_parent; /* event applies to a single watch */
  	}
  	mutex_unlock(&audit_filter_mutex);
  	return;
  
  add_watch_to_parent:
  	list_add(&nwatch->wlist, &parent->watches);
  	mutex_unlock(&audit_filter_mutex);
  	return;
  }
  
  /* Remove all watches & rules associated with a parent that is going away. */
  static void audit_remove_parent_watches(struct audit_parent *parent)
  {
  	struct audit_watch *w, *nextw;
  	struct audit_krule *r, *nextr;
  	struct audit_entry *e;
  
  	mutex_lock(&audit_filter_mutex);
cfcad62c7   Eric Paris   audit: seperate a...
331
332
333
  	list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
  		list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
  			e = container_of(r, struct audit_entry, rule);
e7df61f4d   Burn Alting   audit: invalid op...
334
  			audit_watch_log_rule_change(r, w, "remove_rule");
cfcad62c7   Eric Paris   audit: seperate a...
335
336
337
338
339
340
341
342
  			list_del(&r->rlist);
  			list_del(&r->list);
  			list_del_rcu(&e->list);
  			call_rcu(&e->rcu, audit_free_rule_rcu);
  		}
  		audit_remove_watch(w);
  	}
  	mutex_unlock(&audit_filter_mutex);
e9fd702a5   Eric Paris   audit: convert au...
343

e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
344
  	fsnotify_destroy_mark(&parent->mark, audit_watch_group);
cfcad62c7   Eric Paris   audit: seperate a...
345
  }
cfcad62c7   Eric Paris   audit: seperate a...
346
  /* Get path information necessary for adding watches. */
15a9155fe   Al Viro   fix race in audit...
347
  static int audit_get_nd(struct audit_watch *watch, struct path *parent)
cfcad62c7   Eric Paris   audit: seperate a...
348
  {
79714f72d   Al Viro   get rid of kern_p...
349
350
  	struct dentry *d = kern_path_locked(watch->path, parent);
  	if (IS_ERR(d))
15a9155fe   Al Viro   fix race in audit...
351
  		return PTR_ERR(d);
79714f72d   Al Viro   get rid of kern_p...
352
  	mutex_unlock(&parent->dentry->d_inode->i_mutex);
15a9155fe   Al Viro   fix race in audit...
353
354
355
356
  	if (d->d_inode) {
  		/* update watch filter fields */
  		watch->dev = d->d_inode->i_sb->s_dev;
  		watch->ino = d->d_inode->i_ino;
cfcad62c7   Eric Paris   audit: seperate a...
357
  	}
15a9155fe   Al Viro   fix race in audit...
358
  	dput(d);
cfcad62c7   Eric Paris   audit: seperate a...
359
360
  	return 0;
  }
e9fd702a5   Eric Paris   audit: convert au...
361
  /* Associate the given rule with an existing parent.
cfcad62c7   Eric Paris   audit: seperate a...
362
363
364
365
366
367
   * Caller must hold audit_filter_mutex. */
  static void audit_add_to_parent(struct audit_krule *krule,
  				struct audit_parent *parent)
  {
  	struct audit_watch *w, *watch = krule->watch;
  	int watch_found = 0;
e9fd702a5   Eric Paris   audit: convert au...
368
  	BUG_ON(!mutex_is_locked(&audit_filter_mutex));
cfcad62c7   Eric Paris   audit: seperate a...
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  	list_for_each_entry(w, &parent->watches, wlist) {
  		if (strcmp(watch->path, w->path))
  			continue;
  
  		watch_found = 1;
  
  		/* put krule's and initial refs to temporary watch */
  		audit_put_watch(watch);
  		audit_put_watch(watch);
  
  		audit_get_watch(w);
  		krule->watch = watch = w;
  		break;
  	}
  
  	if (!watch_found) {
e9fd702a5   Eric Paris   audit: convert au...
385
  		audit_get_parent(parent);
cfcad62c7   Eric Paris   audit: seperate a...
386
387
388
389
390
391
392
393
394
  		watch->parent = parent;
  
  		list_add(&watch->wlist, &parent->watches);
  	}
  	list_add(&krule->rlist, &watch->rules);
  }
  
  /* Find a matching watch entry, or add this one.
   * Caller must hold audit_filter_mutex. */
ae7b8f410   Eric Paris   Audit: clean up t...
395
  int audit_add_watch(struct audit_krule *krule, struct list_head **list)
cfcad62c7   Eric Paris   audit: seperate a...
396
397
  {
  	struct audit_watch *watch = krule->watch;
cfcad62c7   Eric Paris   audit: seperate a...
398
  	struct audit_parent *parent;
15a9155fe   Al Viro   fix race in audit...
399
  	struct path parent_path;
ae7b8f410   Eric Paris   Audit: clean up t...
400
  	int h, ret = 0;
cfcad62c7   Eric Paris   audit: seperate a...
401

35fe4d0b1   Eric Paris   Audit: move audit...
402
403
404
  	mutex_unlock(&audit_filter_mutex);
  
  	/* Avoid calling path_lookup under audit_filter_mutex. */
15a9155fe   Al Viro   fix race in audit...
405
  	ret = audit_get_nd(watch, &parent_path);
35fe4d0b1   Eric Paris   Audit: move audit...
406

15a9155fe   Al Viro   fix race in audit...
407
  	/* caller expects mutex locked */
e118e9c56   Eric Paris   audit: redo audit...
408
  	mutex_lock(&audit_filter_mutex);
15a9155fe   Al Viro   fix race in audit...
409
410
  	if (ret)
  		return ret;
cfcad62c7   Eric Paris   audit: seperate a...
411

e118e9c56   Eric Paris   audit: redo audit...
412
  	/* either find an old parent or attach a new one */
15a9155fe   Al Viro   fix race in audit...
413
  	parent = audit_find_parent(parent_path.dentry->d_inode);
e9fd702a5   Eric Paris   audit: convert au...
414
  	if (!parent) {
15a9155fe   Al Viro   fix race in audit...
415
  		parent = audit_init_parent(&parent_path);
cfcad62c7   Eric Paris   audit: seperate a...
416
  		if (IS_ERR(parent)) {
35fe4d0b1   Eric Paris   Audit: move audit...
417
418
  			ret = PTR_ERR(parent);
  			goto error;
cfcad62c7   Eric Paris   audit: seperate a...
419
  		}
e9fd702a5   Eric Paris   audit: convert au...
420
  	}
cfcad62c7   Eric Paris   audit: seperate a...
421

e118e9c56   Eric Paris   audit: redo audit...
422
  	audit_add_to_parent(krule, parent);
cfcad62c7   Eric Paris   audit: seperate a...
423

e9fd702a5   Eric Paris   audit: convert au...
424
425
  	/* match get in audit_find_parent or audit_init_parent */
  	audit_put_parent(parent);
35fe4d0b1   Eric Paris   Audit: move audit...
426

ae7b8f410   Eric Paris   Audit: clean up t...
427
428
  	h = audit_hash_ino((u32)watch->ino);
  	*list = &audit_inode_hash[h];
35fe4d0b1   Eric Paris   Audit: move audit...
429
  error:
15a9155fe   Al Viro   fix race in audit...
430
  	path_put(&parent_path);
cfcad62c7   Eric Paris   audit: seperate a...
431
432
  	return ret;
  }
a05fb6cc5   Eric Paris   audit: do not get...
433
  void audit_remove_watch_rule(struct audit_krule *krule)
cfcad62c7   Eric Paris   audit: seperate a...
434
435
436
437
438
439
440
441
442
443
  {
  	struct audit_watch *watch = krule->watch;
  	struct audit_parent *parent = watch->parent;
  
  	list_del(&krule->rlist);
  
  	if (list_empty(&watch->rules)) {
  		audit_remove_watch(watch);
  
  		if (list_empty(&parent->watches)) {
e9fd702a5   Eric Paris   audit: convert au...
444
  			audit_get_parent(parent);
e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
445
  			fsnotify_destroy_mark(&parent->mark, audit_watch_group);
a05fb6cc5   Eric Paris   audit: do not get...
446
  			audit_put_parent(parent);
cfcad62c7   Eric Paris   audit: seperate a...
447
448
449
  		}
  	}
  }
e9fd702a5   Eric Paris   audit: convert au...
450
  /* Update watch data in audit rules based on fsnotify events. */
3a9b16b40   Eric Paris   fsnotify: send fs...
451
  static int audit_watch_handle_event(struct fsnotify_group *group,
7053aee26   Jan Kara   fsnotify: do not ...
452
  				    struct inode *to_tell,
ce8f76fb7   Eric Paris   fsnotify: pass bo...
453
454
  				    struct fsnotify_mark *inode_mark,
  				    struct fsnotify_mark *vfsmount_mark,
7053aee26   Jan Kara   fsnotify: do not ...
455
  				    u32 mask, void *data, int data_type,
45a22f4c1   Jan Kara   inotify: Fix repo...
456
  				    const unsigned char *dname, u32 cookie)
e9fd702a5   Eric Paris   audit: convert au...
457
458
  {
  	struct inode *inode;
cfcad62c7   Eric Paris   audit: seperate a...
459
  	struct audit_parent *parent;
ce8f76fb7   Eric Paris   fsnotify: pass bo...
460
  	parent = container_of(inode_mark, struct audit_parent, mark);
e9fd702a5   Eric Paris   audit: convert au...
461

4cd76a479   Eric Paris   audit: use the ma...
462
  	BUG_ON(group != audit_watch_group);
e9fd702a5   Eric Paris   audit: convert au...
463

7053aee26   Jan Kara   fsnotify: do not ...
464
  	switch (data_type) {
2069601b3   Linus Torvalds   Revert "fsnotify:...
465
  	case (FSNOTIFY_EVENT_PATH):
7053aee26   Jan Kara   fsnotify: do not ...
466
  		inode = ((struct path *)data)->dentry->d_inode;
e9fd702a5   Eric Paris   audit: convert au...
467
468
  		break;
  	case (FSNOTIFY_EVENT_INODE):
7053aee26   Jan Kara   fsnotify: do not ...
469
  		inode = (struct inode *)data;
e9fd702a5   Eric Paris   audit: convert au...
470
471
472
473
474
475
  		break;
  	default:
  		BUG();
  		inode = NULL;
  		break;
  	};
cfcad62c7   Eric Paris   audit: seperate a...
476

e9fd702a5   Eric Paris   audit: convert au...
477
  	if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
ae7b8f410   Eric Paris   Audit: clean up t...
478
  		audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
e9fd702a5   Eric Paris   audit: convert au...
479
  	else if (mask & (FS_DELETE|FS_MOVED_FROM))
cfcad62c7   Eric Paris   audit: seperate a...
480
  		audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
e9fd702a5   Eric Paris   audit: convert au...
481
  	else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
cfcad62c7   Eric Paris   audit: seperate a...
482
  		audit_remove_parent_watches(parent);
e9fd702a5   Eric Paris   audit: convert au...
483
484
485
  
  	return 0;
  }
e9fd702a5   Eric Paris   audit: convert au...
486
  static const struct fsnotify_ops audit_watch_fsnotify_ops = {
e9fd702a5   Eric Paris   audit: convert au...
487
  	.handle_event = 	audit_watch_handle_event,
cfcad62c7   Eric Paris   audit: seperate a...
488
489
490
491
  };
  
  static int __init audit_watch_init(void)
  {
0d2e2a1d0   Eric Paris   fsnotify: drop ma...
492
  	audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
e9fd702a5   Eric Paris   audit: convert au...
493
494
495
496
  	if (IS_ERR(audit_watch_group)) {
  		audit_watch_group = NULL;
  		audit_panic("cannot create audit fsnotify group");
  	}
cfcad62c7   Eric Paris   audit: seperate a...
497
498
  	return 0;
  }
1a3aedbce   Eric Paris   Audit: audit watc...
499
  device_initcall(audit_watch_init);