diff options
| -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 | ||
