aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2009-06-24 00:02:38 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-06-24 00:02:38 -0400
commit916d75761c971b6e630a26bd4ba472e90ac9a4b9 (patch)
tree3a4b18d0d29c1d12f64fefbb2bc5559813a686f7
parent9d9609851003ebed15957f0f2ce18492739ee124 (diff)
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>
-rw-r--r--kernel/audit.c17
-rw-r--r--kernel/audit.h7
-rw-r--r--kernel/audit_tree.c56
-rw-r--r--kernel/auditsc.c15
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);
133static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); 133static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
134 134
135/* Serialize requests from userspace. */ 135/* Serialize requests from userspace. */
136static DEFINE_MUTEX(audit_cmd_mutex); 136DEFINE_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
509static 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
517void audit_schedule_prune(void)
518{
519 kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
520}
521#endif
522
523struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, 508struct 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 *);
128extern int audit_remove_tree_rule(struct audit_krule *); 128extern int audit_remove_tree_rule(struct audit_krule *);
129extern void audit_trim_trees(void); 129extern void audit_trim_trees(void);
130extern int audit_tag_tree(char *old, char *new); 130extern int audit_tag_tree(char *old, char *new);
131extern void audit_schedule_prune(void);
132extern void audit_prune_trees(void);
133extern const char *audit_tree_path(struct audit_tree *); 131extern const char *audit_tree_path(struct audit_tree *);
134extern void audit_put_tree(struct audit_tree *); 132extern void audit_put_tree(struct audit_tree *);
133extern 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
145extern char *audit_unpack_string(void **, size_t *, size_t); 145extern 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}
160extern void audit_filter_inodes(struct task_struct *, struct audit_context *); 160extern void audit_filter_inodes(struct task_struct *, struct audit_context *);
161extern 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
167extern 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
6struct audit_tree; 7struct audit_tree;
7struct audit_chunk; 8struct audit_chunk;
@@ -517,6 +518,8 @@ static void trim_marked(struct audit_tree *tree)
517 } 518 }
518} 519}
519 520
521static void audit_schedule_prune(void);
522
520/* called with audit_filter_mutex */ 523/* called with audit_filter_mutex */
521int audit_remove_tree_rule(struct audit_krule *rule) 524int 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 */
827void audit_prune_trees(void) 830static 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
853static 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 */
862void 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)
852static void evict_chunk(struct audit_chunk *chunk) 890static 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
2532struct 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}