diff options
| -rw-r--r-- | kernel/audit.c | 17 | ||||
| -rw-r--r-- | kernel/audit.h | 7 | ||||
| -rw-r--r-- | kernel/audit_tree.c | 56 | ||||
| -rw-r--r-- | kernel/auditsc.c | 15 |
4 files changed, 72 insertions, 23 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index 6194c50e2039..defc2e6f1e3b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
| @@ -133,7 +133,7 @@ static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); | |||
| 133 | static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); | 133 | static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); |
| 134 | 134 | ||
| 135 | /* Serialize requests from userspace. */ | 135 | /* Serialize requests from userspace. */ |
| 136 | static DEFINE_MUTEX(audit_cmd_mutex); | 136 | DEFINE_MUTEX(audit_cmd_mutex); |
| 137 | 137 | ||
| 138 | /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting | 138 | /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting |
| 139 | * audit records. Since printk uses a 1024 byte buffer, this buffer | 139 | * audit records. Since printk uses a 1024 byte buffer, this buffer |
| @@ -505,21 +505,6 @@ int audit_send_list(void *_dest) | |||
| 505 | return 0; | 505 | return 0; |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | #ifdef CONFIG_AUDIT_TREE | ||
| 509 | static int prune_tree_thread(void *unused) | ||
| 510 | { | ||
| 511 | mutex_lock(&audit_cmd_mutex); | ||
| 512 | audit_prune_trees(); | ||
| 513 | mutex_unlock(&audit_cmd_mutex); | ||
| 514 | return 0; | ||
| 515 | } | ||
| 516 | |||
| 517 | void audit_schedule_prune(void) | ||
| 518 | { | ||
| 519 | kthread_run(prune_tree_thread, NULL, "audit_prune_tree"); | ||
| 520 | } | ||
| 521 | #endif | ||
| 522 | |||
| 523 | struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, | 508 | struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, |
| 524 | int multi, void *payload, int size) | 509 | int multi, void *payload, int size) |
| 525 | { | 510 | { |
diff --git a/kernel/audit.h b/kernel/audit.h index bb1c0d69db08..208687be4f30 100644 --- a/kernel/audit.h +++ b/kernel/audit.h | |||
| @@ -128,10 +128,9 @@ extern int audit_add_tree_rule(struct audit_krule *); | |||
| 128 | extern int audit_remove_tree_rule(struct audit_krule *); | 128 | extern int audit_remove_tree_rule(struct audit_krule *); |
| 129 | extern void audit_trim_trees(void); | 129 | extern void audit_trim_trees(void); |
| 130 | extern int audit_tag_tree(char *old, char *new); | 130 | extern int audit_tag_tree(char *old, char *new); |
| 131 | extern void audit_schedule_prune(void); | ||
| 132 | extern void audit_prune_trees(void); | ||
| 133 | extern const char *audit_tree_path(struct audit_tree *); | 131 | extern const char *audit_tree_path(struct audit_tree *); |
| 134 | extern void audit_put_tree(struct audit_tree *); | 132 | extern void audit_put_tree(struct audit_tree *); |
| 133 | extern void audit_kill_trees(struct list_head *); | ||
| 135 | #else | 134 | #else |
| 136 | #define audit_remove_tree_rule(rule) BUG() | 135 | #define audit_remove_tree_rule(rule) BUG() |
| 137 | #define audit_add_tree_rule(rule) -EINVAL | 136 | #define audit_add_tree_rule(rule) -EINVAL |
| @@ -140,6 +139,7 @@ extern void audit_put_tree(struct audit_tree *); | |||
| 140 | #define audit_put_tree(tree) (void)0 | 139 | #define audit_put_tree(tree) (void)0 |
| 141 | #define audit_tag_tree(old, new) -EINVAL | 140 | #define audit_tag_tree(old, new) -EINVAL |
| 142 | #define audit_tree_path(rule) "" /* never called */ | 141 | #define audit_tree_path(rule) "" /* never called */ |
| 142 | #define audit_kill_trees(list) BUG() | ||
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | extern char *audit_unpack_string(void **, size_t *, size_t); | 145 | extern char *audit_unpack_string(void **, size_t *, size_t); |
| @@ -158,7 +158,10 @@ static inline int audit_signal_info(int sig, struct task_struct *t) | |||
| 158 | return 0; | 158 | return 0; |
| 159 | } | 159 | } |
| 160 | extern void audit_filter_inodes(struct task_struct *, struct audit_context *); | 160 | extern void audit_filter_inodes(struct task_struct *, struct audit_context *); |
| 161 | extern struct list_head *audit_killed_trees(void); | ||
| 161 | #else | 162 | #else |
| 162 | #define audit_signal_info(s,t) AUDIT_DISABLED | 163 | #define audit_signal_info(s,t) AUDIT_DISABLED |
| 163 | #define audit_filter_inodes(t,c) AUDIT_DISABLED | 164 | #define audit_filter_inodes(t,c) AUDIT_DISABLED |
| 164 | #endif | 165 | #endif |
| 166 | |||
| 167 | extern struct mutex audit_cmd_mutex; | ||
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 3ff0731284a1..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; |
| @@ -517,6 +518,8 @@ static void trim_marked(struct audit_tree *tree) | |||
| 517 | } | 518 | } |
| 518 | } | 519 | } |
| 519 | 520 | ||
| 521 | static void audit_schedule_prune(void); | ||
| 522 | |||
| 520 | /* called with audit_filter_mutex */ | 523 | /* called with audit_filter_mutex */ |
| 521 | int audit_remove_tree_rule(struct audit_krule *rule) | 524 | int audit_remove_tree_rule(struct audit_krule *rule) |
| 522 | { | 525 | { |
| @@ -822,10 +825,11 @@ int audit_tag_tree(char *old, char *new) | |||
| 822 | 825 | ||
| 823 | /* | 826 | /* |
| 824 | * 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. |
| 825 | * Runs from a separate thread, with audit_cmd_mutex held. | 828 | * Runs from a separate thread. |
| 826 | */ | 829 | */ |
| 827 | void audit_prune_trees(void) | 830 | static int prune_tree_thread(void *unused) |
| 828 | { | 831 | { |
| 832 | mutex_lock(&audit_cmd_mutex); | ||
| 829 | mutex_lock(&audit_filter_mutex); | 833 | mutex_lock(&audit_filter_mutex); |
| 830 | 834 | ||
| 831 | while (!list_empty(&prune_list)) { | 835 | while (!list_empty(&prune_list)) { |
| @@ -842,6 +846,40 @@ void audit_prune_trees(void) | |||
| 842 | } | 846 | } |
| 843 | 847 | ||
| 844 | 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); | ||
| 845 | } | 883 | } |
| 846 | 884 | ||
| 847 | /* | 885 | /* |
| @@ -852,6 +890,8 @@ void audit_prune_trees(void) | |||
| 852 | static void evict_chunk(struct audit_chunk *chunk) | 890 | static void evict_chunk(struct audit_chunk *chunk) |
| 853 | { | 891 | { |
| 854 | struct audit_tree *owner; | 892 | struct audit_tree *owner; |
| 893 | struct list_head *postponed = audit_killed_trees(); | ||
| 894 | int need_prune = 0; | ||
| 855 | int n; | 895 | int n; |
| 856 | 896 | ||
| 857 | if (chunk->dead) | 897 | if (chunk->dead) |
| @@ -867,15 +907,21 @@ static void evict_chunk(struct audit_chunk *chunk) | |||
| 867 | owner->root = NULL; | 907 | owner->root = NULL; |
| 868 | list_del_init(&owner->same_root); | 908 | list_del_init(&owner->same_root); |
| 869 | spin_unlock(&hash_lock); | 909 | spin_unlock(&hash_lock); |
| 870 | kill_rules(owner); | 910 | if (!postponed) { |
| 871 | list_move(&owner->list, &prune_list); | 911 | kill_rules(owner); |
| 872 | audit_schedule_prune(); | 912 | list_move(&owner->list, &prune_list); |
| 913 | need_prune = 1; | ||
| 914 | } else { | ||
| 915 | list_move(&owner->list, postponed); | ||
| 916 | } | ||
| 873 | spin_lock(&hash_lock); | 917 | spin_lock(&hash_lock); |
| 874 | } | 918 | } |
| 875 | list_del_rcu(&chunk->hash); | 919 | list_del_rcu(&chunk->hash); |
| 876 | for (n = 0; n < chunk->count; n++) | 920 | for (n = 0; n < chunk->count; n++) |
| 877 | list_del_init(&chunk->owners[n].list); | 921 | list_del_init(&chunk->owners[n].list); |
| 878 | spin_unlock(&hash_lock); | 922 | spin_unlock(&hash_lock); |
| 923 | if (need_prune) | ||
| 924 | audit_schedule_prune(); | ||
| 879 | mutex_unlock(&audit_filter_mutex); | 925 | mutex_unlock(&audit_filter_mutex); |
| 880 | } | 926 | } |
| 881 | 927 | ||
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 2de95d1582bc..68d3c6a0ecd6 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -199,6 +199,7 @@ struct audit_context { | |||
| 199 | 199 | ||
| 200 | struct audit_tree_refs *trees, *first_trees; | 200 | struct audit_tree_refs *trees, *first_trees; |
| 201 | int tree_count; | 201 | int tree_count; |
| 202 | struct list_head killed_trees; | ||
| 202 | 203 | ||
| 203 | int type; | 204 | int type; |
| 204 | union { | 205 | union { |
| @@ -853,6 +854,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state) | |||
| 853 | if (!(context = kmalloc(sizeof(*context), GFP_KERNEL))) | 854 | if (!(context = kmalloc(sizeof(*context), GFP_KERNEL))) |
| 854 | return NULL; | 855 | return NULL; |
| 855 | audit_zero_context(context, state); | 856 | audit_zero_context(context, state); |
| 857 | INIT_LIST_HEAD(&context->killed_trees); | ||
| 856 | return context; | 858 | return context; |
| 857 | } | 859 | } |
| 858 | 860 | ||
| @@ -1545,6 +1547,8 @@ void audit_free(struct task_struct *tsk) | |||
| 1545 | /* that can happen only if we are called from do_exit() */ | 1547 | /* that can happen only if we are called from do_exit() */ |
| 1546 | if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT) | 1548 | if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT) |
| 1547 | audit_log_exit(context, tsk); | 1549 | audit_log_exit(context, tsk); |
| 1550 | if (!list_empty(&context->killed_trees)) | ||
| 1551 | audit_kill_trees(&context->killed_trees); | ||
| 1548 | 1552 | ||
| 1549 | audit_free_context(context); | 1553 | audit_free_context(context); |
| 1550 | } | 1554 | } |
| @@ -1688,6 +1692,9 @@ void audit_syscall_exit(int valid, long return_code) | |||
| 1688 | context->in_syscall = 0; | 1692 | context->in_syscall = 0; |
| 1689 | context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0; | 1693 | context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0; |
| 1690 | 1694 | ||
| 1695 | if (!list_empty(&context->killed_trees)) | ||
| 1696 | audit_kill_trees(&context->killed_trees); | ||
| 1697 | |||
| 1691 | if (context->previous) { | 1698 | if (context->previous) { |
| 1692 | struct audit_context *new_context = context->previous; | 1699 | struct audit_context *new_context = context->previous; |
| 1693 | context->previous = NULL; | 1700 | context->previous = NULL; |
| @@ -2521,3 +2528,11 @@ void audit_core_dumps(long signr) | |||
| 2521 | audit_log_format(ab, " sig=%ld", signr); | 2528 | audit_log_format(ab, " sig=%ld", signr); |
| 2522 | audit_log_end(ab); | 2529 | audit_log_end(ab); |
| 2523 | } | 2530 | } |
| 2531 | |||
| 2532 | struct list_head *audit_killed_trees(void) | ||
| 2533 | { | ||
| 2534 | struct audit_context *ctx = current->audit_context; | ||
| 2535 | if (likely(!ctx || !ctx->in_syscall)) | ||
| 2536 | return NULL; | ||
| 2537 | return &ctx->killed_trees; | ||
| 2538 | } | ||
