diff options
Diffstat (limited to 'kernel/audit_tree.c')
| -rw-r--r-- | kernel/audit_tree.c | 101 |
1 files changed, 29 insertions, 72 deletions
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 4b05bd9479db..46a57b57a335 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #include <linux/namei.h> | 3 | #include <linux/namei.h> |
| 4 | #include <linux/mount.h> | 4 | #include <linux/mount.h> |
| 5 | #include <linux/kthread.h> | 5 | #include <linux/kthread.h> |
| 6 | #include <linux/slab.h> | ||
| 6 | 7 | ||
| 7 | struct audit_tree; | 8 | struct audit_tree; |
| 8 | struct audit_chunk; | 9 | struct audit_chunk; |
| @@ -548,6 +549,11 @@ int audit_remove_tree_rule(struct audit_krule *rule) | |||
| 548 | return 0; | 549 | return 0; |
| 549 | } | 550 | } |
| 550 | 551 | ||
| 552 | static int compare_root(struct vfsmount *mnt, void *arg) | ||
| 553 | { | ||
| 554 | return mnt->mnt_root->d_inode == arg; | ||
| 555 | } | ||
| 556 | |||
| 551 | void audit_trim_trees(void) | 557 | void audit_trim_trees(void) |
| 552 | { | 558 | { |
| 553 | struct list_head cursor; | 559 | struct list_head cursor; |
| @@ -559,7 +565,6 @@ void audit_trim_trees(void) | |||
| 559 | struct path path; | 565 | struct path path; |
| 560 | struct vfsmount *root_mnt; | 566 | struct vfsmount *root_mnt; |
| 561 | struct node *node; | 567 | struct node *node; |
| 562 | struct list_head list; | ||
| 563 | int err; | 568 | int err; |
| 564 | 569 | ||
| 565 | tree = container_of(cursor.next, struct audit_tree, list); | 570 | tree = container_of(cursor.next, struct audit_tree, list); |
| @@ -577,24 +582,16 @@ void audit_trim_trees(void) | |||
| 577 | if (!root_mnt) | 582 | if (!root_mnt) |
| 578 | goto skip_it; | 583 | goto skip_it; |
| 579 | 584 | ||
| 580 | list_add_tail(&list, &root_mnt->mnt_list); | ||
| 581 | spin_lock(&hash_lock); | 585 | spin_lock(&hash_lock); |
| 582 | list_for_each_entry(node, &tree->chunks, list) { | 586 | list_for_each_entry(node, &tree->chunks, list) { |
| 583 | struct audit_chunk *chunk = find_chunk(node); | 587 | struct inode *inode = find_chunk(node)->watch.inode; |
| 584 | struct inode *inode = chunk->watch.inode; | ||
| 585 | struct vfsmount *mnt; | ||
| 586 | node->index |= 1U<<31; | 588 | node->index |= 1U<<31; |
| 587 | list_for_each_entry(mnt, &list, mnt_list) { | 589 | if (iterate_mounts(compare_root, inode, root_mnt)) |
| 588 | if (mnt->mnt_root->d_inode == inode) { | 590 | node->index &= ~(1U<<31); |
| 589 | node->index &= ~(1U<<31); | ||
| 590 | break; | ||
| 591 | } | ||
| 592 | } | ||
| 593 | } | 591 | } |
| 594 | spin_unlock(&hash_lock); | 592 | spin_unlock(&hash_lock); |
| 595 | trim_marked(tree); | 593 | trim_marked(tree); |
| 596 | put_tree(tree); | 594 | put_tree(tree); |
| 597 | list_del_init(&list); | ||
| 598 | drop_collected_mounts(root_mnt); | 595 | drop_collected_mounts(root_mnt); |
| 599 | skip_it: | 596 | skip_it: |
| 600 | mutex_lock(&audit_filter_mutex); | 597 | mutex_lock(&audit_filter_mutex); |
| @@ -603,22 +600,6 @@ skip_it: | |||
| 603 | mutex_unlock(&audit_filter_mutex); | 600 | mutex_unlock(&audit_filter_mutex); |
| 604 | } | 601 | } |
| 605 | 602 | ||
| 606 | static int is_under(struct vfsmount *mnt, struct dentry *dentry, | ||
| 607 | struct path *path) | ||
| 608 | { | ||
| 609 | if (mnt != path->mnt) { | ||
| 610 | for (;;) { | ||
| 611 | if (mnt->mnt_parent == mnt) | ||
| 612 | return 0; | ||
| 613 | if (mnt->mnt_parent == path->mnt) | ||
| 614 | break; | ||
| 615 | mnt = mnt->mnt_parent; | ||
| 616 | } | ||
| 617 | dentry = mnt->mnt_mountpoint; | ||
| 618 | } | ||
| 619 | return is_subdir(dentry, path->dentry); | ||
| 620 | } | ||
| 621 | |||
| 622 | int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) | 603 | int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) |
| 623 | { | 604 | { |
| 624 | 605 | ||
| @@ -638,13 +619,17 @@ void audit_put_tree(struct audit_tree *tree) | |||
| 638 | put_tree(tree); | 619 | put_tree(tree); |
| 639 | } | 620 | } |
| 640 | 621 | ||
| 622 | static int tag_mount(struct vfsmount *mnt, void *arg) | ||
| 623 | { | ||
| 624 | return tag_chunk(mnt->mnt_root->d_inode, arg); | ||
| 625 | } | ||
| 626 | |||
| 641 | /* called with audit_filter_mutex */ | 627 | /* called with audit_filter_mutex */ |
| 642 | int audit_add_tree_rule(struct audit_krule *rule) | 628 | int audit_add_tree_rule(struct audit_krule *rule) |
| 643 | { | 629 | { |
| 644 | struct audit_tree *seed = rule->tree, *tree; | 630 | struct audit_tree *seed = rule->tree, *tree; |
| 645 | struct path path; | 631 | struct path path; |
| 646 | struct vfsmount *mnt, *p; | 632 | struct vfsmount *mnt; |
| 647 | struct list_head list; | ||
| 648 | int err; | 633 | int err; |
| 649 | 634 | ||
| 650 | list_for_each_entry(tree, &tree_list, list) { | 635 | list_for_each_entry(tree, &tree_list, list) { |
| @@ -670,16 +655,9 @@ int audit_add_tree_rule(struct audit_krule *rule) | |||
| 670 | err = -ENOMEM; | 655 | err = -ENOMEM; |
| 671 | goto Err; | 656 | goto Err; |
| 672 | } | 657 | } |
| 673 | list_add_tail(&list, &mnt->mnt_list); | ||
| 674 | 658 | ||
| 675 | get_tree(tree); | 659 | get_tree(tree); |
| 676 | list_for_each_entry(p, &list, mnt_list) { | 660 | err = iterate_mounts(tag_mount, tree, mnt); |
| 677 | err = tag_chunk(p->mnt_root->d_inode, tree); | ||
| 678 | if (err) | ||
| 679 | break; | ||
| 680 | } | ||
| 681 | |||
| 682 | list_del(&list); | ||
| 683 | drop_collected_mounts(mnt); | 661 | drop_collected_mounts(mnt); |
| 684 | 662 | ||
| 685 | if (!err) { | 663 | if (!err) { |
| @@ -714,31 +692,23 @@ int audit_tag_tree(char *old, char *new) | |||
| 714 | { | 692 | { |
| 715 | struct list_head cursor, barrier; | 693 | struct list_head cursor, barrier; |
| 716 | int failed = 0; | 694 | int failed = 0; |
| 717 | struct path path; | 695 | struct path path1, path2; |
| 718 | struct vfsmount *tagged; | 696 | struct vfsmount *tagged; |
| 719 | struct list_head list; | ||
| 720 | struct vfsmount *mnt; | ||
| 721 | struct dentry *dentry; | ||
| 722 | int err; | 697 | int err; |
| 723 | 698 | ||
| 724 | err = kern_path(new, 0, &path); | 699 | err = kern_path(new, 0, &path2); |
| 725 | if (err) | 700 | if (err) |
| 726 | return err; | 701 | return err; |
| 727 | tagged = collect_mounts(&path); | 702 | tagged = collect_mounts(&path2); |
| 728 | path_put(&path); | 703 | path_put(&path2); |
| 729 | if (!tagged) | 704 | if (!tagged) |
| 730 | return -ENOMEM; | 705 | return -ENOMEM; |
| 731 | 706 | ||
| 732 | err = kern_path(old, 0, &path); | 707 | err = kern_path(old, 0, &path1); |
| 733 | if (err) { | 708 | if (err) { |
| 734 | drop_collected_mounts(tagged); | 709 | drop_collected_mounts(tagged); |
| 735 | return err; | 710 | return err; |
| 736 | } | 711 | } |
| 737 | mnt = mntget(path.mnt); | ||
| 738 | dentry = dget(path.dentry); | ||
| 739 | path_put(&path); | ||
| 740 | |||
| 741 | list_add_tail(&list, &tagged->mnt_list); | ||
| 742 | 712 | ||
| 743 | mutex_lock(&audit_filter_mutex); | 713 | mutex_lock(&audit_filter_mutex); |
| 744 | list_add(&barrier, &tree_list); | 714 | list_add(&barrier, &tree_list); |
| @@ -746,7 +716,7 @@ int audit_tag_tree(char *old, char *new) | |||
| 746 | 716 | ||
| 747 | while (cursor.next != &tree_list) { | 717 | while (cursor.next != &tree_list) { |
| 748 | struct audit_tree *tree; | 718 | struct audit_tree *tree; |
| 749 | struct vfsmount *p; | 719 | int good_one = 0; |
| 750 | 720 | ||
| 751 | tree = container_of(cursor.next, struct audit_tree, list); | 721 | tree = container_of(cursor.next, struct audit_tree, list); |
| 752 | get_tree(tree); | 722 | get_tree(tree); |
| @@ -754,30 +724,19 @@ int audit_tag_tree(char *old, char *new) | |||
| 754 | list_add(&cursor, &tree->list); | 724 | list_add(&cursor, &tree->list); |
| 755 | mutex_unlock(&audit_filter_mutex); | 725 | mutex_unlock(&audit_filter_mutex); |
| 756 | 726 | ||
| 757 | err = kern_path(tree->pathname, 0, &path); | 727 | err = kern_path(tree->pathname, 0, &path2); |
| 758 | if (err) { | 728 | if (!err) { |
| 759 | put_tree(tree); | 729 | good_one = path_is_under(&path1, &path2); |
| 760 | mutex_lock(&audit_filter_mutex); | 730 | path_put(&path2); |
| 761 | continue; | ||
| 762 | } | 731 | } |
| 763 | 732 | ||
| 764 | spin_lock(&vfsmount_lock); | 733 | if (!good_one) { |
| 765 | if (!is_under(mnt, dentry, &path)) { | ||
| 766 | spin_unlock(&vfsmount_lock); | ||
| 767 | path_put(&path); | ||
| 768 | put_tree(tree); | 734 | put_tree(tree); |
| 769 | mutex_lock(&audit_filter_mutex); | 735 | mutex_lock(&audit_filter_mutex); |
| 770 | continue; | 736 | continue; |
| 771 | } | 737 | } |
| 772 | spin_unlock(&vfsmount_lock); | ||
| 773 | path_put(&path); | ||
| 774 | |||
| 775 | list_for_each_entry(p, &list, mnt_list) { | ||
| 776 | failed = tag_chunk(p->mnt_root->d_inode, tree); | ||
| 777 | if (failed) | ||
| 778 | break; | ||
| 779 | } | ||
| 780 | 738 | ||
| 739 | failed = iterate_mounts(tag_mount, tree, tagged); | ||
| 781 | if (failed) { | 740 | if (failed) { |
| 782 | put_tree(tree); | 741 | put_tree(tree); |
| 783 | mutex_lock(&audit_filter_mutex); | 742 | mutex_lock(&audit_filter_mutex); |
| @@ -818,10 +777,8 @@ int audit_tag_tree(char *old, char *new) | |||
| 818 | } | 777 | } |
| 819 | list_del(&barrier); | 778 | list_del(&barrier); |
| 820 | list_del(&cursor); | 779 | list_del(&cursor); |
| 821 | list_del(&list); | ||
| 822 | mutex_unlock(&audit_filter_mutex); | 780 | mutex_unlock(&audit_filter_mutex); |
| 823 | dput(dentry); | 781 | path_put(&path1); |
| 824 | mntput(mnt); | ||
| 825 | drop_collected_mounts(tagged); | 782 | drop_collected_mounts(tagged); |
| 826 | return failed; | 783 | return failed; |
| 827 | } | 784 | } |
