Blame view

kernel/audit_watch.c 14.2 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
  {
15a9155fe   Al Viro   fix race in audit...
347
348
  	struct nameidata nd;
  	struct dentry *d;
cfcad62c7   Eric Paris   audit: seperate a...
349
  	int err;
c9c6cac0c   Al Viro   kill path_lookup()
350
  	err = kern_path_parent(watch->path, &nd);
15a9155fe   Al Viro   fix race in audit...
351
352
  	if (err)
  		return err;
cfcad62c7   Eric Paris   audit: seperate a...
353

15a9155fe   Al Viro   fix race in audit...
354
355
356
  	if (nd.last_type != LAST_NORM) {
  		path_put(&nd.path);
  		return -EINVAL;
cfcad62c7   Eric Paris   audit: seperate a...
357
  	}
15a9155fe   Al Viro   fix race in audit...
358
359
360
361
362
363
  	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
  	d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
  	if (IS_ERR(d)) {
  		mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
  		path_put(&nd.path);
  		return PTR_ERR(d);
cfcad62c7   Eric Paris   audit: seperate a...
364
  	}
15a9155fe   Al Viro   fix race in audit...
365
366
367
368
  	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...
369
  	}
15a9155fe   Al Viro   fix race in audit...
370
  	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
cfcad62c7   Eric Paris   audit: seperate a...
371

15a9155fe   Al Viro   fix race in audit...
372
373
  	*parent = nd.path;
  	dput(d);
cfcad62c7   Eric Paris   audit: seperate a...
374
375
  	return 0;
  }
e9fd702a5   Eric Paris   audit: convert au...
376
  /* Associate the given rule with an existing parent.
cfcad62c7   Eric Paris   audit: seperate a...
377
378
379
380
381
382
   * 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...
383
  	BUG_ON(!mutex_is_locked(&audit_filter_mutex));
cfcad62c7   Eric Paris   audit: seperate a...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
  	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...
400
  		audit_get_parent(parent);
cfcad62c7   Eric Paris   audit: seperate a...
401
402
403
404
405
406
407
408
409
  		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...
410
  int audit_add_watch(struct audit_krule *krule, struct list_head **list)
cfcad62c7   Eric Paris   audit: seperate a...
411
412
  {
  	struct audit_watch *watch = krule->watch;
cfcad62c7   Eric Paris   audit: seperate a...
413
  	struct audit_parent *parent;
15a9155fe   Al Viro   fix race in audit...
414
  	struct path parent_path;
ae7b8f410   Eric Paris   Audit: clean up t...
415
  	int h, ret = 0;
cfcad62c7   Eric Paris   audit: seperate a...
416

35fe4d0b1   Eric Paris   Audit: move audit...
417
418
419
  	mutex_unlock(&audit_filter_mutex);
  
  	/* Avoid calling path_lookup under audit_filter_mutex. */
15a9155fe   Al Viro   fix race in audit...
420
  	ret = audit_get_nd(watch, &parent_path);
35fe4d0b1   Eric Paris   Audit: move audit...
421

15a9155fe   Al Viro   fix race in audit...
422
  	/* caller expects mutex locked */
e118e9c56   Eric Paris   audit: redo audit...
423
  	mutex_lock(&audit_filter_mutex);
15a9155fe   Al Viro   fix race in audit...
424
425
  	if (ret)
  		return ret;
cfcad62c7   Eric Paris   audit: seperate a...
426

e118e9c56   Eric Paris   audit: redo audit...
427
  	/* either find an old parent or attach a new one */
15a9155fe   Al Viro   fix race in audit...
428
  	parent = audit_find_parent(parent_path.dentry->d_inode);
e9fd702a5   Eric Paris   audit: convert au...
429
  	if (!parent) {
15a9155fe   Al Viro   fix race in audit...
430
  		parent = audit_init_parent(&parent_path);
cfcad62c7   Eric Paris   audit: seperate a...
431
  		if (IS_ERR(parent)) {
35fe4d0b1   Eric Paris   Audit: move audit...
432
433
  			ret = PTR_ERR(parent);
  			goto error;
cfcad62c7   Eric Paris   audit: seperate a...
434
  		}
e9fd702a5   Eric Paris   audit: convert au...
435
  	}
cfcad62c7   Eric Paris   audit: seperate a...
436

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

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

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

4cd76a479   Eric Paris   audit: use the ma...
485
  	BUG_ON(group != audit_watch_group);
e9fd702a5   Eric Paris   audit: convert au...
486
487
  
  	switch (event->data_type) {
2069601b3   Linus Torvalds   Revert "fsnotify:...
488
489
  	case (FSNOTIFY_EVENT_PATH):
  		inode = event->path.dentry->d_inode;
e9fd702a5   Eric Paris   audit: convert au...
490
491
492
493
494
495
496
497
498
  		break;
  	case (FSNOTIFY_EVENT_INODE):
  		inode = event->inode;
  		break;
  	default:
  		BUG();
  		inode = NULL;
  		break;
  	};
cfcad62c7   Eric Paris   audit: seperate a...
499

e9fd702a5   Eric Paris   audit: convert au...
500
  	if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
ae7b8f410   Eric Paris   Audit: clean up t...
501
  		audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
e9fd702a5   Eric Paris   audit: convert au...
502
  	else if (mask & (FS_DELETE|FS_MOVED_FROM))
cfcad62c7   Eric Paris   audit: seperate a...
503
  		audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
e9fd702a5   Eric Paris   audit: convert au...
504
  	else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
cfcad62c7   Eric Paris   audit: seperate a...
505
  		audit_remove_parent_watches(parent);
e9fd702a5   Eric Paris   audit: convert au...
506
507
508
  
  	return 0;
  }
e9fd702a5   Eric Paris   audit: convert au...
509
510
511
512
  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...
513
  	.freeing_mark = 	NULL,
e9fd702a5   Eric Paris   audit: convert au...
514
  	.free_event_priv = 	NULL,
cfcad62c7   Eric Paris   audit: seperate a...
515
516
517
518
  };
  
  static int __init audit_watch_init(void)
  {
0d2e2a1d0   Eric Paris   fsnotify: drop ma...
519
  	audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
e9fd702a5   Eric Paris   audit: convert au...
520
521
522
523
  	if (IS_ERR(audit_watch_group)) {
  		audit_watch_group = NULL;
  		audit_panic("cannot create audit fsnotify group");
  	}
cfcad62c7   Eric Paris   audit: seperate a...
524
525
  	return 0;
  }
1a3aedbce   Eric Paris   Audit: audit watc...
526
  device_initcall(audit_watch_init);