aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/audit_watch.c
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 20:12:04 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:58:16 -0400
commite118e9c5638bbe877aa26b5cd2fd223cc24cdc8a (patch)
treee57559daadac89686a3523e9f55c5a61315e05bf /kernel/audit_watch.c
parente9fd702a58c49dbb14481dca88dad44758da393a (diff)
audit: redo audit watch locking and refcnt in light of fsnotify
fsnotify can handle mutexes to be held across all fsnotify operations since it deals strickly in spinlocks. This can simplify and reduce some of the audit_filter_mutex taking and dropping. Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'kernel/audit_watch.c')
-rw-r--r--kernel/audit_watch.c45
1 files changed, 5 insertions, 40 deletions
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index ff5be849473d..da66197e3abc 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -58,23 +58,11 @@ struct audit_parent {
58 struct list_head ilist; /* tmp list used to free parents */ 58 struct list_head ilist; /* tmp list used to free parents */
59 struct list_head watches; /* anchor for audit_watch->wlist */ 59 struct list_head watches; /* anchor for audit_watch->wlist */
60 struct fsnotify_mark_entry mark; /* fsnotify mark on the inode */ 60 struct fsnotify_mark_entry mark; /* fsnotify mark on the inode */
61 unsigned flags; /* status flags */
62}; 61};
63 62
64/* fsnotify handle. */ 63/* fsnotify handle. */
65struct fsnotify_group *audit_watch_group; 64struct fsnotify_group *audit_watch_group;
66 65
67/*
68 * audit_parent status flags:
69 *
70 * AUDIT_PARENT_INVALID - set anytime rules/watches are auto-removed due to
71 * a filesystem event to ensure we're adding audit watches to a valid parent.
72 * Technically not needed for FS_DELETE_SELF or FS_UNMOUNT events, as we cannot
73 * receive them while we have nameidata, but must be used for FS_MOVE_SELF which
74 * we can receive while holding nameidata.
75 */
76#define AUDIT_PARENT_INVALID 0x001
77
78/* fsnotify events we care about. */ 66/* fsnotify events we care about. */
79#define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\ 67#define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
80 FS_MOVE_SELF | FS_EVENT_ON_CHILD) 68 FS_MOVE_SELF | FS_EVENT_ON_CHILD)
@@ -171,12 +159,9 @@ static struct audit_parent *audit_init_parent(struct nameidata *ndp)
171 return ERR_PTR(-ENOMEM); 159 return ERR_PTR(-ENOMEM);
172 160
173 INIT_LIST_HEAD(&parent->watches); 161 INIT_LIST_HEAD(&parent->watches);
174 parent->flags = 0;
175 162
176 fsnotify_init_mark(&parent->mark, audit_watch_free_mark); 163 fsnotify_init_mark(&parent->mark, audit_watch_free_mark);
177 parent->mark.mask = AUDIT_FS_WATCH; 164 parent->mark.mask = AUDIT_FS_WATCH;
178 /* grab a ref so fsnotify mark hangs around until we take audit_filter_mutex */
179 audit_get_parent(parent);
180 ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode); 165 ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode);
181 if (ret < 0) { 166 if (ret < 0) {
182 audit_free_parent(parent); 167 audit_free_parent(parent);
@@ -355,7 +340,6 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
355 struct audit_entry *e; 340 struct audit_entry *e;
356 341
357 mutex_lock(&audit_filter_mutex); 342 mutex_lock(&audit_filter_mutex);
358 parent->flags |= AUDIT_PARENT_INVALID;
359 list_for_each_entry_safe(w, nextw, &parent->watches, wlist) { 343 list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
360 list_for_each_entry_safe(r, nextr, &w->rules, rlist) { 344 list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
361 e = container_of(r, struct audit_entry, rule); 345 e = container_of(r, struct audit_entry, rule);
@@ -487,35 +471,25 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
487 goto error; 471 goto error;
488 } 472 }
489 473
474 mutex_lock(&audit_filter_mutex);
475
490 /* update watch filter fields */ 476 /* update watch filter fields */
491 if (ndw) { 477 if (ndw) {
492 watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev; 478 watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
493 watch->ino = ndw->path.dentry->d_inode->i_ino; 479 watch->ino = ndw->path.dentry->d_inode->i_ino;
494 } 480 }
495 481
496 /* The audit_filter_mutex must not be held during inotify calls because 482 /* either find an old parent or attach a new one */
497 * we hold it during inotify event callback processing. If an existing
498 * inotify watch is found, inotify_find_watch() grabs a reference before
499 * returning.
500 */
501 parent = audit_find_parent(ndp->path.dentry->d_inode); 483 parent = audit_find_parent(ndp->path.dentry->d_inode);
502 if (!parent) { 484 if (!parent) {
503 parent = audit_init_parent(ndp); 485 parent = audit_init_parent(ndp);
504 if (IS_ERR(parent)) { 486 if (IS_ERR(parent)) {
505 /* caller expects mutex locked */
506 mutex_lock(&audit_filter_mutex);
507 ret = PTR_ERR(parent); 487 ret = PTR_ERR(parent);
508 goto error; 488 goto error;
509 } 489 }
510 } 490 }
511 491
512 mutex_lock(&audit_filter_mutex); 492 audit_add_to_parent(krule, parent);
513
514 /* parent was moved before we took audit_filter_mutex */
515 if (parent->flags & AUDIT_PARENT_INVALID)
516 ret = -ENOENT;
517 else
518 audit_add_to_parent(krule, parent);
519 493
520 /* match get in audit_find_parent or audit_init_parent */ 494 /* match get in audit_find_parent or audit_init_parent */
521 audit_put_parent(parent); 495 audit_put_parent(parent);
@@ -613,20 +587,11 @@ static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotif
613 return 0; 587 return 0;
614} 588}
615 589
616static void audit_watch_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group)
617{
618 struct audit_parent *parent;
619
620 parent = container_of(entry, struct audit_parent, mark);
621 /* taken from audit_handle_ievent & FS_IGNORED please figure out what I match... */
622 audit_put_parent(parent);
623}
624
625static const struct fsnotify_ops audit_watch_fsnotify_ops = { 590static const struct fsnotify_ops audit_watch_fsnotify_ops = {
626 .should_send_event = audit_watch_should_send_event, 591 .should_send_event = audit_watch_should_send_event,
627 .handle_event = audit_watch_handle_event, 592 .handle_event = audit_watch_handle_event,
628 .free_group_priv = NULL, 593 .free_group_priv = NULL,
629 .freeing_mark = audit_watch_freeing_mark, 594 .freeing_mark = NULL,
630 .free_event_priv = NULL, 595 .free_event_priv = NULL,
631}; 596};
632 597