Blame view

kernel/audit_watch.c 13.8 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
235
236
237
238
239
240
  	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...
241
  		audit_log_key(ab, r->filterkey);
cfcad62c7   Eric Paris   audit: seperate a...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  		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...
257
258
  	/* Run all of the watches on this parent looking for the one that
  	 * matches the given dname */
cfcad62c7   Eric Paris   audit: seperate a...
259
260
261
262
263
264
  	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...
265
  		if (invalidating && !audit_dummy_context())
cfcad62c7   Eric Paris   audit: seperate a...
266
  			audit_filter_inodes(current, current->audit_context);
ae7b8f410   Eric Paris   Audit: clean up t...
267
268
  		/* 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...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  		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...
283
  			nentry = audit_dupe_rule(&oentry->rule);
cfcad62c7   Eric Paris   audit: seperate a...
284
285
286
287
288
  			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...
289
290
291
292
293
294
295
296
297
  
  				/*
  				 * 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...
298
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
  				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...
329
330
331
332
333
334
335
336
337
338
339
340
  	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...
341

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

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

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

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

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

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

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

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

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