Blame view

kernel/audit_watch.c 14.5 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
62
  /* fsnotify handle. */
  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
120
121
122
123
  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);
  	}
  }
  
  void audit_remove_watch(struct audit_watch *watch)
  {
  	list_del(&watch->wlist);
e9fd702a5   Eric Paris   audit: convert au...
124
  	audit_put_parent(watch->parent);
cfcad62c7   Eric Paris   audit: seperate a...
125
126
127
128
129
130
131
132
  	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...
133
  int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
cfcad62c7   Eric Paris   audit: seperate a...
134
  {
ae7b8f410   Eric Paris   Audit: clean up t...
135
136
137
  	return (watch->ino != (unsigned long)-1) &&
  		(watch->ino == ino) &&
  		(watch->dev == dev);
cfcad62c7   Eric Paris   audit: seperate a...
138
139
140
141
142
  }
  
  /* Initialize a parent watch entry. */
  static struct audit_parent *audit_init_parent(struct nameidata *ndp)
  {
e9fd702a5   Eric Paris   audit: convert au...
143
  	struct inode *inode = ndp->path.dentry->d_inode;
cfcad62c7   Eric Paris   audit: seperate a...
144
  	struct audit_parent *parent;
e9fd702a5   Eric Paris   audit: convert au...
145
  	int ret;
cfcad62c7   Eric Paris   audit: seperate a...
146
147
148
149
150
151
  
  	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
  	if (unlikely(!parent))
  		return ERR_PTR(-ENOMEM);
  
  	INIT_LIST_HEAD(&parent->watches);
cfcad62c7   Eric Paris   audit: seperate a...
152

e9fd702a5   Eric Paris   audit: convert au...
153
154
  	fsnotify_init_mark(&parent->mark, audit_watch_free_mark);
  	parent->mark.mask = AUDIT_FS_WATCH;
5444e2981   Eric Paris   fsnotify: split g...
155
  	ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode, NULL, 0);
e9fd702a5   Eric Paris   audit: convert au...
156
  	if (ret < 0) {
ae7b8f410   Eric Paris   Audit: clean up t...
157
  		audit_free_parent(parent);
e9fd702a5   Eric Paris   audit: convert au...
158
  		return ERR_PTR(ret);
cfcad62c7   Eric Paris   audit: seperate a...
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
185
  	}
  
  	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...
186
  	if (!audit_watch_group)
cfcad62c7   Eric Paris   audit: seperate a...
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
223
  		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...
224
  	audit_get_parent(old->parent);
cfcad62c7   Eric Paris   audit: seperate a...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  	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);
  		audit_log_format(ab, "auid=%u ses=%u op=",
  				 audit_get_loginuid(current),
  				 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...
242
  		audit_log_key(ab, r->filterkey);
cfcad62c7   Eric Paris   audit: seperate a...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  		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...
258
259
  	/* Run all of the watches on this parent looking for the one that
  	 * matches the given dname */
cfcad62c7   Eric Paris   audit: seperate a...
260
261
262
263
264
265
  	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
  		if (audit_compare_dname_path(dname, owatch->path, NULL))
  			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...
266
  		if (invalidating && !audit_dummy_context())
cfcad62c7   Eric Paris   audit: seperate a...
267
  			audit_filter_inodes(current, current->audit_context);
ae7b8f410   Eric Paris   Audit: clean up t...
268
269
  		/* 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...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  		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...
284
  			nentry = audit_dupe_rule(&oentry->rule);
cfcad62c7   Eric Paris   audit: seperate a...
285
286
287
288
289
  			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...
290
291
292
293
294
295
296
297
298
  
  				/*
  				 * 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...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  				list_add(&nentry->rule.rlist, &nwatch->rules);
  				list_add_rcu(&nentry->list, &audit_inode_hash[h]);
  				list_replace(&oentry->rule.list,
  					     &nentry->rule.list);
  			}
  
  			audit_watch_log_rule_change(r, owatch, "updated rules");
  
  			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...
330
331
332
333
334
335
336
337
338
339
340
341
  	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);
  			audit_watch_log_rule_change(r, w, "remove rule");
  			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...
342

d07754412   Eric Paris   fsnotify: rename ...
343
  	fsnotify_destroy_mark(&parent->mark);
cfcad62c7   Eric Paris   audit: seperate a...
344
  }
cfcad62c7   Eric Paris   audit: seperate a...
345
  /* Get path information necessary for adding watches. */
35fe4d0b1   Eric Paris   Audit: move audit...
346
  static int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw)
cfcad62c7   Eric Paris   audit: seperate a...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  {
  	struct nameidata *ndparent, *ndwatch;
  	int err;
  
  	ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL);
  	if (unlikely(!ndparent))
  		return -ENOMEM;
  
  	ndwatch = kmalloc(sizeof(*ndwatch), GFP_KERNEL);
  	if (unlikely(!ndwatch)) {
  		kfree(ndparent);
  		return -ENOMEM;
  	}
  
  	err = path_lookup(path, LOOKUP_PARENT, ndparent);
  	if (err) {
  		kfree(ndparent);
  		kfree(ndwatch);
  		return err;
  	}
  
  	err = path_lookup(path, 0, ndwatch);
  	if (err) {
  		kfree(ndwatch);
  		ndwatch = NULL;
  	}
  
  	*ndp = ndparent;
  	*ndw = ndwatch;
  
  	return 0;
  }
  
  /* Release resources used for watch path information. */
35fe4d0b1   Eric Paris   Audit: move audit...
381
  static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
cfcad62c7   Eric Paris   audit: seperate a...
382
383
384
385
386
387
388
389
390
391
  {
  	if (ndp) {
  		path_put(&ndp->path);
  		kfree(ndp);
  	}
  	if (ndw) {
  		path_put(&ndw->path);
  		kfree(ndw);
  	}
  }
e9fd702a5   Eric Paris   audit: convert au...
392
  /* Associate the given rule with an existing parent.
cfcad62c7   Eric Paris   audit: seperate a...
393
394
395
396
397
398
   * 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...
399
  	BUG_ON(!mutex_is_locked(&audit_filter_mutex));
cfcad62c7   Eric Paris   audit: seperate a...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  	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...
416
  		audit_get_parent(parent);
cfcad62c7   Eric Paris   audit: seperate a...
417
418
419
420
421
422
423
424
425
  		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...
426
  int audit_add_watch(struct audit_krule *krule, struct list_head **list)
cfcad62c7   Eric Paris   audit: seperate a...
427
428
  {
  	struct audit_watch *watch = krule->watch;
cfcad62c7   Eric Paris   audit: seperate a...
429
  	struct audit_parent *parent;
35fe4d0b1   Eric Paris   Audit: move audit...
430
  	struct nameidata *ndp = NULL, *ndw = NULL;
ae7b8f410   Eric Paris   Audit: clean up t...
431
  	int h, ret = 0;
cfcad62c7   Eric Paris   audit: seperate a...
432

35fe4d0b1   Eric Paris   Audit: move audit...
433
434
435
436
437
438
439
440
441
  	mutex_unlock(&audit_filter_mutex);
  
  	/* Avoid calling path_lookup under audit_filter_mutex. */
  	ret = audit_get_nd(watch->path, &ndp, &ndw);
  	if (ret) {
  		/* caller expects mutex locked */
  		mutex_lock(&audit_filter_mutex);
  		goto error;
  	}
e118e9c56   Eric Paris   audit: redo audit...
442
  	mutex_lock(&audit_filter_mutex);
cfcad62c7   Eric Paris   audit: seperate a...
443
444
445
446
447
  	/* update watch filter fields */
  	if (ndw) {
  		watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
  		watch->ino = ndw->path.dentry->d_inode->i_ino;
  	}
e118e9c56   Eric Paris   audit: redo audit...
448
  	/* either find an old parent or attach a new one */
e9fd702a5   Eric Paris   audit: convert au...
449
450
  	parent = audit_find_parent(ndp->path.dentry->d_inode);
  	if (!parent) {
cfcad62c7   Eric Paris   audit: seperate a...
451
452
  		parent = audit_init_parent(ndp);
  		if (IS_ERR(parent)) {
35fe4d0b1   Eric Paris   Audit: move audit...
453
454
  			ret = PTR_ERR(parent);
  			goto error;
cfcad62c7   Eric Paris   audit: seperate a...
455
  		}
e9fd702a5   Eric Paris   audit: convert au...
456
  	}
cfcad62c7   Eric Paris   audit: seperate a...
457

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

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

ae7b8f410   Eric Paris   Audit: clean up t...
463
464
  	h = audit_hash_ino((u32)watch->ino);
  	*list = &audit_inode_hash[h];
35fe4d0b1   Eric Paris   Audit: move audit...
465
466
  error:
  	audit_put_nd(ndp, ndw);		/* NULL args OK */
cfcad62c7   Eric Paris   audit: seperate a...
467
  	return ret;
35fe4d0b1   Eric Paris   Audit: move audit...
468

cfcad62c7   Eric Paris   audit: seperate a...
469
  }
a05fb6cc5   Eric Paris   audit: do not get...
470
  void audit_remove_watch_rule(struct audit_krule *krule)
cfcad62c7   Eric Paris   audit: seperate a...
471
472
473
474
475
476
477
478
479
480
  {
  	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...
481
  			audit_get_parent(parent);
d07754412   Eric Paris   fsnotify: rename ...
482
  			fsnotify_destroy_mark(&parent->mark);
a05fb6cc5   Eric Paris   audit: do not get...
483
  			audit_put_parent(parent);
cfcad62c7   Eric Paris   audit: seperate a...
484
485
486
  		}
  	}
  }
7b0a04fbf   Eric Paris   fsnotify: provide...
487
  static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode,
1968f5eed   Eric Paris   fanotify: use bot...
488
  					  struct fsnotify_mark *inode_mark,
ce8f76fb7   Eric Paris   fsnotify: pass bo...
489
  					  struct fsnotify_mark *vfsmount_mark,
3a9b16b40   Eric Paris   fsnotify: send fs...
490
  					  __u32 mask, void *data, int data_type)
cfcad62c7   Eric Paris   audit: seperate a...
491
  {
2612abb51   Eric Paris   fsnotify: cleanup...
492
         return true;
e9fd702a5   Eric Paris   audit: convert au...
493
494
495
  }
  
  /* Update watch data in audit rules based on fsnotify events. */
3a9b16b40   Eric Paris   fsnotify: send fs...
496
  static int audit_watch_handle_event(struct fsnotify_group *group,
ce8f76fb7   Eric Paris   fsnotify: pass bo...
497
498
  				    struct fsnotify_mark *inode_mark,
  				    struct fsnotify_mark *vfsmount_mark,
3a9b16b40   Eric Paris   fsnotify: send fs...
499
  				    struct fsnotify_event *event)
e9fd702a5   Eric Paris   audit: convert au...
500
501
502
503
  {
  	struct inode *inode;
  	__u32 mask = event->mask;
  	const char *dname = event->file_name;
cfcad62c7   Eric Paris   audit: seperate a...
504
  	struct audit_parent *parent;
ce8f76fb7   Eric Paris   fsnotify: pass bo...
505
  	parent = container_of(inode_mark, struct audit_parent, mark);
e9fd702a5   Eric Paris   audit: convert au...
506

4cd76a479   Eric Paris   audit: use the ma...
507
  	BUG_ON(group != audit_watch_group);
e9fd702a5   Eric Paris   audit: convert au...
508
509
  
  	switch (event->data_type) {
2069601b3   Linus Torvalds   Revert "fsnotify:...
510
511
  	case (FSNOTIFY_EVENT_PATH):
  		inode = event->path.dentry->d_inode;
e9fd702a5   Eric Paris   audit: convert au...
512
513
514
515
516
517
518
519
520
  		break;
  	case (FSNOTIFY_EVENT_INODE):
  		inode = event->inode;
  		break;
  	default:
  		BUG();
  		inode = NULL;
  		break;
  	};
cfcad62c7   Eric Paris   audit: seperate a...
521

e9fd702a5   Eric Paris   audit: convert au...
522
  	if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
ae7b8f410   Eric Paris   Audit: clean up t...
523
  		audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
e9fd702a5   Eric Paris   audit: convert au...
524
  	else if (mask & (FS_DELETE|FS_MOVED_FROM))
cfcad62c7   Eric Paris   audit: seperate a...
525
  		audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
e9fd702a5   Eric Paris   audit: convert au...
526
  	else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
cfcad62c7   Eric Paris   audit: seperate a...
527
  		audit_remove_parent_watches(parent);
e9fd702a5   Eric Paris   audit: convert au...
528
529
530
  
  	return 0;
  }
e9fd702a5   Eric Paris   audit: convert au...
531
532
533
534
  static const struct fsnotify_ops audit_watch_fsnotify_ops = {
  	.should_send_event = 	audit_watch_should_send_event,
  	.handle_event = 	audit_watch_handle_event,
  	.free_group_priv = 	NULL,
e118e9c56   Eric Paris   audit: redo audit...
535
  	.freeing_mark = 	NULL,
e9fd702a5   Eric Paris   audit: convert au...
536
  	.free_event_priv = 	NULL,
cfcad62c7   Eric Paris   audit: seperate a...
537
538
539
540
  };
  
  static int __init audit_watch_init(void)
  {
0d2e2a1d0   Eric Paris   fsnotify: drop ma...
541
  	audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
e9fd702a5   Eric Paris   audit: convert au...
542
543
544
545
  	if (IS_ERR(audit_watch_group)) {
  		audit_watch_group = NULL;
  		audit_panic("cannot create audit fsnotify group");
  	}
cfcad62c7   Eric Paris   audit: seperate a...
546
547
  	return 0;
  }
1a3aedbce   Eric Paris   Audit: audit watc...
548
  device_initcall(audit_watch_init);