Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix rule eviction order for AUDIT_DIR

If syscall removes the root of subtree being watched, we
definitely do not want the rules refering that subtree
to be destroyed without the syscall in question having
a chance to match them.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 916d7576 9d960985

+72 -23
+1 -16
kernel/audit.c
··· 133 133 static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); 134 134 135 135 /* Serialize requests from userspace. */ 136 - static DEFINE_MUTEX(audit_cmd_mutex); 136 + DEFINE_MUTEX(audit_cmd_mutex); 137 137 138 138 /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting 139 139 * audit records. Since printk uses a 1024 byte buffer, this buffer ··· 504 504 505 505 return 0; 506 506 } 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 507 523 508 struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, 524 509 int multi, void *payload, int size)
+5 -2
kernel/audit.h
··· 128 128 extern int audit_remove_tree_rule(struct audit_krule *); 129 129 extern void audit_trim_trees(void); 130 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 131 extern const char *audit_tree_path(struct audit_tree *); 134 132 extern void audit_put_tree(struct audit_tree *); 133 + extern void audit_kill_trees(struct list_head *); 135 134 #else 136 135 #define audit_remove_tree_rule(rule) BUG() 137 136 #define audit_add_tree_rule(rule) -EINVAL ··· 139 140 #define audit_put_tree(tree) (void)0 140 141 #define audit_tag_tree(old, new) -EINVAL 141 142 #define audit_tree_path(rule) "" /* never called */ 143 + #define audit_kill_trees(list) BUG() 142 144 #endif 143 145 144 146 extern char *audit_unpack_string(void **, size_t *, size_t); ··· 158 158 return 0; 159 159 } 160 160 extern void audit_filter_inodes(struct task_struct *, struct audit_context *); 161 + extern struct list_head *audit_killed_trees(void); 161 162 #else 162 163 #define audit_signal_info(s,t) AUDIT_DISABLED 163 164 #define audit_filter_inodes(t,c) AUDIT_DISABLED 164 165 #endif 166 + 167 + extern struct mutex audit_cmd_mutex;
+51 -5
kernel/audit_tree.c
··· 2 2 #include <linux/inotify.h> 3 3 #include <linux/namei.h> 4 4 #include <linux/mount.h> 5 + #include <linux/kthread.h> 5 6 6 7 struct audit_tree; 7 8 struct audit_chunk; ··· 518 517 } 519 518 } 520 519 520 + static void audit_schedule_prune(void); 521 + 521 522 /* called with audit_filter_mutex */ 522 523 int audit_remove_tree_rule(struct audit_krule *rule) 523 524 { ··· 825 822 826 823 /* 827 824 * That gets run when evict_chunk() ends up needing to kill audit_tree. 828 - * Runs from a separate thread, with audit_cmd_mutex held. 825 + * Runs from a separate thread. 829 826 */ 830 - void audit_prune_trees(void) 827 + static int prune_tree_thread(void *unused) 831 828 { 829 + mutex_lock(&audit_cmd_mutex); 832 830 mutex_lock(&audit_filter_mutex); 833 831 834 832 while (!list_empty(&prune_list)) { ··· 846 842 } 847 843 848 844 mutex_unlock(&audit_filter_mutex); 845 + mutex_unlock(&audit_cmd_mutex); 846 + return 0; 847 + } 848 + 849 + static void audit_schedule_prune(void) 850 + { 851 + kthread_run(prune_tree_thread, NULL, "audit_prune_tree"); 852 + } 853 + 854 + /* 855 + * ... and that one is done if evict_chunk() decides to delay until the end 856 + * of syscall. Runs synchronously. 857 + */ 858 + void audit_kill_trees(struct list_head *list) 859 + { 860 + mutex_lock(&audit_cmd_mutex); 861 + mutex_lock(&audit_filter_mutex); 862 + 863 + while (!list_empty(list)) { 864 + struct audit_tree *victim; 865 + 866 + victim = list_entry(list->next, struct audit_tree, list); 867 + kill_rules(victim); 868 + list_del_init(&victim->list); 869 + 870 + mutex_unlock(&audit_filter_mutex); 871 + 872 + prune_one(victim); 873 + 874 + mutex_lock(&audit_filter_mutex); 875 + } 876 + 877 + mutex_unlock(&audit_filter_mutex); 878 + mutex_unlock(&audit_cmd_mutex); 849 879 } 850 880 851 881 /* ··· 890 852 static void evict_chunk(struct audit_chunk *chunk) 891 853 { 892 854 struct audit_tree *owner; 855 + struct list_head *postponed = audit_killed_trees(); 856 + int need_prune = 0; 893 857 int n; 894 858 895 859 if (chunk->dead) ··· 907 867 owner->root = NULL; 908 868 list_del_init(&owner->same_root); 909 869 spin_unlock(&hash_lock); 910 - kill_rules(owner); 911 - list_move(&owner->list, &prune_list); 912 - audit_schedule_prune(); 870 + if (!postponed) { 871 + kill_rules(owner); 872 + list_move(&owner->list, &prune_list); 873 + need_prune = 1; 874 + } else { 875 + list_move(&owner->list, postponed); 876 + } 913 877 spin_lock(&hash_lock); 914 878 } 915 879 list_del_rcu(&chunk->hash); 916 880 for (n = 0; n < chunk->count; n++) 917 881 list_del_init(&chunk->owners[n].list); 918 882 spin_unlock(&hash_lock); 883 + if (need_prune) 884 + audit_schedule_prune(); 919 885 mutex_unlock(&audit_filter_mutex); 920 886 } 921 887
+15
kernel/auditsc.c
··· 199 199 200 200 struct audit_tree_refs *trees, *first_trees; 201 201 int tree_count; 202 + struct list_head killed_trees; 202 203 203 204 int type; 204 205 union { ··· 854 853 if (!(context = kmalloc(sizeof(*context), GFP_KERNEL))) 855 854 return NULL; 856 855 audit_zero_context(context, state); 856 + INIT_LIST_HEAD(&context->killed_trees); 857 857 return context; 858 858 } 859 859 ··· 1547 1545 /* that can happen only if we are called from do_exit() */ 1548 1546 if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT) 1549 1547 audit_log_exit(context, tsk); 1548 + if (!list_empty(&context->killed_trees)) 1549 + audit_kill_trees(&context->killed_trees); 1550 1550 1551 1551 audit_free_context(context); 1552 1552 } ··· 1691 1687 1692 1688 context->in_syscall = 0; 1693 1689 context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0; 1690 + 1691 + if (!list_empty(&context->killed_trees)) 1692 + audit_kill_trees(&context->killed_trees); 1694 1693 1695 1694 if (context->previous) { 1696 1695 struct audit_context *new_context = context->previous; ··· 2527 2520 audit_log_untrustedstring(ab, current->comm); 2528 2521 audit_log_format(ab, " sig=%ld", signr); 2529 2522 audit_log_end(ab); 2523 + } 2524 + 2525 + struct list_head *audit_killed_trees(void) 2526 + { 2527 + struct audit_context *ctx = current->audit_context; 2528 + if (likely(!ctx || !ctx->in_syscall)) 2529 + return NULL; 2530 + return &ctx->killed_trees; 2530 2531 }