diff options
Diffstat (limited to 'kernel/audit_watch.c')
-rw-r--r-- | kernel/audit_watch.c | 45 |
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. */ |
65 | struct fsnotify_group *audit_watch_group; | 64 | struct 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 | ||
616 | static 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 | |||
625 | static const struct fsnotify_ops audit_watch_fsnotify_ops = { | 590 | static 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 | ||