aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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