Blame view

kernel/audit_watch.c 13.9 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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  				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...
332
333
334
335
336
337
338
339
340
341
342
343
  	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...
344

e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
345
  	fsnotify_destroy_mark(&parent->mark, audit_watch_group);
cfcad62c7   Eric Paris   audit: seperate a...
346
  }
cfcad62c7   Eric Paris   audit: seperate a...
347
  /* Get path information necessary for adding watches. */
15a9155fe   Al Viro   fix race in audit...
348
  static int audit_get_nd(struct audit_watch *watch, struct path *parent)
cfcad62c7   Eric Paris   audit: seperate a...
349
  {
79714f72d   Al Viro   get rid of kern_p...
350
351
  	struct dentry *d = kern_path_locked(watch->path, parent);
  	if (IS_ERR(d))
15a9155fe   Al Viro   fix race in audit...
352
  		return PTR_ERR(d);
79714f72d   Al Viro   get rid of kern_p...
353
  	mutex_unlock(&parent->dentry->d_inode->i_mutex);
15a9155fe   Al Viro   fix race in audit...
354
355
356
357
  	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...
358
  	}
15a9155fe   Al Viro   fix race in audit...
359
  	dput(d);
cfcad62c7   Eric Paris   audit: seperate a...
360
361
  	return 0;
  }
e9fd702a5   Eric Paris   audit: convert au...
362
  /* Associate the given rule with an existing parent.
cfcad62c7   Eric Paris   audit: seperate a...
363
364
365
366
367
368
   * 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...
369
  	BUG_ON(!mutex_is_locked(&audit_filter_mutex));
cfcad62c7   Eric Paris   audit: seperate a...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  	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...
386
  		audit_get_parent(parent);
cfcad62c7   Eric Paris   audit: seperate a...
387
388
389
390
391
392
393
394
395
  		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...
396
  int audit_add_watch(struct audit_krule *krule, struct list_head **list)
cfcad62c7   Eric Paris   audit: seperate a...
397
398
  {
  	struct audit_watch *watch = krule->watch;
cfcad62c7   Eric Paris   audit: seperate a...
399
  	struct audit_parent *parent;
15a9155fe   Al Viro   fix race in audit...
400
  	struct path parent_path;
ae7b8f410   Eric Paris   Audit: clean up t...
401
  	int h, ret = 0;
cfcad62c7   Eric Paris   audit: seperate a...
402

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

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

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

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

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

ae7b8f410   Eric Paris   Audit: clean up t...
428
429
  	h = audit_hash_ino((u32)watch->ino);
  	*list = &audit_inode_hash[h];
35fe4d0b1   Eric Paris   Audit: move audit...
430
  error:
15a9155fe   Al Viro   fix race in audit...
431
  	path_put(&parent_path);
cfcad62c7   Eric Paris   audit: seperate a...
432
433
  	return ret;
  }
a05fb6cc5   Eric Paris   audit: do not get...
434
  void audit_remove_watch_rule(struct audit_krule *krule)
cfcad62c7   Eric Paris   audit: seperate a...
435
436
437
438
439
440
441
442
443
444
  {
  	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...
445
  			audit_get_parent(parent);
e2a29943e   Lino Sanfilippo   fsnotify: pass gr...
446
  			fsnotify_destroy_mark(&parent->mark, audit_watch_group);
a05fb6cc5   Eric Paris   audit: do not get...
447
  			audit_put_parent(parent);
cfcad62c7   Eric Paris   audit: seperate a...
448
449
450
  		}
  	}
  }
7b0a04fbf   Eric Paris   fsnotify: provide...
451
  static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode,
1968f5eed   Eric Paris   fanotify: use bot...
452
  					  struct fsnotify_mark *inode_mark,
ce8f76fb7   Eric Paris   fsnotify: pass bo...
453
  					  struct fsnotify_mark *vfsmount_mark,
3a9b16b40   Eric Paris   fsnotify: send fs...
454
  					  __u32 mask, void *data, int data_type)
cfcad62c7   Eric Paris   audit: seperate a...
455
  {
2612abb51   Eric Paris   fsnotify: cleanup...
456
         return true;
e9fd702a5   Eric Paris   audit: convert au...
457
458
459
  }
  
  /* Update watch data in audit rules based on fsnotify events. */
3a9b16b40   Eric Paris   fsnotify: send fs...
460
  static int audit_watch_handle_event(struct fsnotify_group *group,
ce8f76fb7   Eric Paris   fsnotify: pass bo...
461
462
  				    struct fsnotify_mark *inode_mark,
  				    struct fsnotify_mark *vfsmount_mark,
3a9b16b40   Eric Paris   fsnotify: send fs...
463
  				    struct fsnotify_event *event)
e9fd702a5   Eric Paris   audit: convert au...
464
465
466
467
  {
  	struct inode *inode;
  	__u32 mask = event->mask;
  	const char *dname = event->file_name;
cfcad62c7   Eric Paris   audit: seperate a...
468
  	struct audit_parent *parent;
ce8f76fb7   Eric Paris   fsnotify: pass bo...
469
  	parent = container_of(inode_mark, struct audit_parent, mark);
e9fd702a5   Eric Paris   audit: convert au...
470

4cd76a479   Eric Paris   audit: use the ma...
471
  	BUG_ON(group != audit_watch_group);
e9fd702a5   Eric Paris   audit: convert au...
472
473
  
  	switch (event->data_type) {
2069601b3   Linus Torvalds   Revert "fsnotify:...
474
475
  	case (FSNOTIFY_EVENT_PATH):
  		inode = event->path.dentry->d_inode;
e9fd702a5   Eric Paris   audit: convert au...
476
477
478
479
480
481
482
483
484
  		break;
  	case (FSNOTIFY_EVENT_INODE):
  		inode = event->inode;
  		break;
  	default:
  		BUG();
  		inode = NULL;
  		break;
  	};
cfcad62c7   Eric Paris   audit: seperate a...
485

e9fd702a5   Eric Paris   audit: convert au...
486
  	if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
ae7b8f410   Eric Paris   Audit: clean up t...
487
  		audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
e9fd702a5   Eric Paris   audit: convert au...
488
  	else if (mask & (FS_DELETE|FS_MOVED_FROM))
cfcad62c7   Eric Paris   audit: seperate a...
489
  		audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
e9fd702a5   Eric Paris   audit: convert au...
490
  	else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
cfcad62c7   Eric Paris   audit: seperate a...
491
  		audit_remove_parent_watches(parent);
e9fd702a5   Eric Paris   audit: convert au...
492
493
494
  
  	return 0;
  }
e9fd702a5   Eric Paris   audit: convert au...
495
496
497
498
  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...
499
  	.freeing_mark = 	NULL,
e9fd702a5   Eric Paris   audit: convert au...
500
  	.free_event_priv = 	NULL,
cfcad62c7   Eric Paris   audit: seperate a...
501
502
503
504
  };
  
  static int __init audit_watch_init(void)
  {
0d2e2a1d0   Eric Paris   fsnotify: drop ma...
505
  	audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
e9fd702a5   Eric Paris   audit: convert au...
506
507
508
509
  	if (IS_ERR(audit_watch_group)) {
  		audit_watch_group = NULL;
  		audit_panic("cannot create audit fsnotify group");
  	}
cfcad62c7   Eric Paris   audit: seperate a...
510
511
  	return 0;
  }
1a3aedbce   Eric Paris   Audit: audit watc...
512
  device_initcall(audit_watch_init);