diff options
Diffstat (limited to 'kernel/audit_tree.c')
-rw-r--r-- | kernel/audit_tree.c | 66 |
1 files changed, 55 insertions, 11 deletions
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 1f6396d76687..2451dc6f3282 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <linux/inotify.h> | 2 | #include <linux/inotify.h> |
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 | 6 | ||
6 | struct audit_tree; | 7 | struct audit_tree; |
7 | struct audit_chunk; | 8 | struct audit_chunk; |
@@ -441,13 +442,11 @@ static void kill_rules(struct audit_tree *tree) | |||
441 | if (rule->tree) { | 442 | if (rule->tree) { |
442 | /* not a half-baked one */ | 443 | /* not a half-baked one */ |
443 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | 444 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); |
444 | audit_log_format(ab, "op=remove rule dir="); | 445 | audit_log_format(ab, "op="); |
446 | audit_log_string(ab, "remove rule"); | ||
447 | audit_log_format(ab, " dir="); | ||
445 | audit_log_untrustedstring(ab, rule->tree->pathname); | 448 | audit_log_untrustedstring(ab, rule->tree->pathname); |
446 | if (rule->filterkey) { | 449 | audit_log_key(ab, rule->filterkey); |
447 | audit_log_format(ab, " key="); | ||
448 | audit_log_untrustedstring(ab, rule->filterkey); | ||
449 | } else | ||
450 | audit_log_format(ab, " key=(null)"); | ||
451 | audit_log_format(ab, " list=%d res=1", rule->listnr); | 450 | audit_log_format(ab, " list=%d res=1", rule->listnr); |
452 | audit_log_end(ab); | 451 | audit_log_end(ab); |
453 | rule->tree = NULL; | 452 | rule->tree = NULL; |
@@ -519,6 +518,8 @@ static void trim_marked(struct audit_tree *tree) | |||
519 | } | 518 | } |
520 | } | 519 | } |
521 | 520 | ||
521 | static void audit_schedule_prune(void); | ||
522 | |||
522 | /* called with audit_filter_mutex */ | 523 | /* called with audit_filter_mutex */ |
523 | int audit_remove_tree_rule(struct audit_krule *rule) | 524 | int audit_remove_tree_rule(struct audit_krule *rule) |
524 | { | 525 | { |
@@ -824,10 +825,11 @@ int audit_tag_tree(char *old, char *new) | |||
824 | 825 | ||
825 | /* | 826 | /* |
826 | * That gets run when evict_chunk() ends up needing to kill audit_tree. | 827 | * That gets run when evict_chunk() ends up needing to kill audit_tree. |
827 | * Runs from a separate thread, with audit_cmd_mutex held. | 828 | * Runs from a separate thread. |
828 | */ | 829 | */ |
829 | void audit_prune_trees(void) | 830 | static int prune_tree_thread(void *unused) |
830 | { | 831 | { |
832 | mutex_lock(&audit_cmd_mutex); | ||
831 | mutex_lock(&audit_filter_mutex); | 833 | mutex_lock(&audit_filter_mutex); |
832 | 834 | ||
833 | while (!list_empty(&prune_list)) { | 835 | while (!list_empty(&prune_list)) { |
@@ -844,6 +846,40 @@ void audit_prune_trees(void) | |||
844 | } | 846 | } |
845 | 847 | ||
846 | mutex_unlock(&audit_filter_mutex); | 848 | mutex_unlock(&audit_filter_mutex); |
849 | mutex_unlock(&audit_cmd_mutex); | ||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | static void audit_schedule_prune(void) | ||
854 | { | ||
855 | kthread_run(prune_tree_thread, NULL, "audit_prune_tree"); | ||
856 | } | ||
857 | |||
858 | /* | ||
859 | * ... and that one is done if evict_chunk() decides to delay until the end | ||
860 | * of syscall. Runs synchronously. | ||
861 | */ | ||
862 | void audit_kill_trees(struct list_head *list) | ||
863 | { | ||
864 | mutex_lock(&audit_cmd_mutex); | ||
865 | mutex_lock(&audit_filter_mutex); | ||
866 | |||
867 | while (!list_empty(list)) { | ||
868 | struct audit_tree *victim; | ||
869 | |||
870 | victim = list_entry(list->next, struct audit_tree, list); | ||
871 | kill_rules(victim); | ||
872 | list_del_init(&victim->list); | ||
873 | |||
874 | mutex_unlock(&audit_filter_mutex); | ||
875 | |||
876 | prune_one(victim); | ||
877 | |||
878 | mutex_lock(&audit_filter_mutex); | ||
879 | } | ||
880 | |||
881 | mutex_unlock(&audit_filter_mutex); | ||
882 | mutex_unlock(&audit_cmd_mutex); | ||
847 | } | 883 | } |
848 | 884 | ||
849 | /* | 885 | /* |
@@ -854,6 +890,8 @@ void audit_prune_trees(void) | |||
854 | static void evict_chunk(struct audit_chunk *chunk) | 890 | static void evict_chunk(struct audit_chunk *chunk) |
855 | { | 891 | { |
856 | struct audit_tree *owner; | 892 | struct audit_tree *owner; |
893 | struct list_head *postponed = audit_killed_trees(); | ||
894 | int need_prune = 0; | ||
857 | int n; | 895 | int n; |
858 | 896 | ||
859 | if (chunk->dead) | 897 | if (chunk->dead) |
@@ -869,15 +907,21 @@ static void evict_chunk(struct audit_chunk *chunk) | |||
869 | owner->root = NULL; | 907 | owner->root = NULL; |
870 | list_del_init(&owner->same_root); | 908 | list_del_init(&owner->same_root); |
871 | spin_unlock(&hash_lock); | 909 | spin_unlock(&hash_lock); |
872 | kill_rules(owner); | 910 | if (!postponed) { |
873 | list_move(&owner->list, &prune_list); | 911 | kill_rules(owner); |
874 | audit_schedule_prune(); | 912 | list_move(&owner->list, &prune_list); |
913 | need_prune = 1; | ||
914 | } else { | ||
915 | list_move(&owner->list, postponed); | ||
916 | } | ||
875 | spin_lock(&hash_lock); | 917 | spin_lock(&hash_lock); |
876 | } | 918 | } |
877 | list_del_rcu(&chunk->hash); | 919 | list_del_rcu(&chunk->hash); |
878 | for (n = 0; n < chunk->count; n++) | 920 | for (n = 0; n < chunk->count; n++) |
879 | list_del_init(&chunk->owners[n].list); | 921 | list_del_init(&chunk->owners[n].list); |
880 | spin_unlock(&hash_lock); | 922 | spin_unlock(&hash_lock); |
923 | if (need_prune) | ||
924 | audit_schedule_prune(); | ||
881 | mutex_unlock(&audit_filter_mutex); | 925 | mutex_unlock(&audit_filter_mutex); |
882 | } | 926 | } |
883 | 927 | ||