aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2008-12-14 23:45:27 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2009-01-04 15:14:41 -0500
commit0590b9335a1c72a3f0defcc6231287f7817e07c8 (patch)
tree289fa4668ae304f79f7484ac31b2cab0ab8894c1
parent1a9d0797b8977d413435277bf9661efbbd584693 (diff)
fixing audit rule ordering mess, part 1
Problem: ordering between the rules on exit chain is currently lost; all watch and inode rules are listed after everything else _and_ exit,never on one kind doesn't stop exit,always on another from being matched. Solution: assign priorities to rules, keep track of the current highest-priority matching rule and its result (always/never). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--include/linux/audit.h1
-rw-r--r--kernel/audit.h5
-rw-r--r--kernel/auditfilter.c17
-rw-r--r--kernel/auditsc.c79
4 files changed, 59 insertions, 43 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 7ddcb6a29eb1..5b47eeb00d53 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -373,6 +373,7 @@ struct audit_krule {
373 struct audit_watch *watch; /* associated watch */ 373 struct audit_watch *watch; /* associated watch */
374 struct audit_tree *tree; /* associated watched tree */ 374 struct audit_tree *tree; /* associated watched tree */
375 struct list_head rlist; /* entry in audit_{watch,tree}.rules list */ 375 struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
376 u64 prio;
376}; 377};
377 378
378struct audit_field { 379struct audit_field {
diff --git a/kernel/audit.h b/kernel/audit.h
index 9d6717412fec..16f18cac661b 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -159,11 +159,8 @@ static inline int audit_signal_info(int sig, struct task_struct *t)
159 return __audit_signal_info(sig, t); 159 return __audit_signal_info(sig, t);
160 return 0; 160 return 0;
161} 161}
162extern enum audit_state audit_filter_inodes(struct task_struct *, 162extern void audit_filter_inodes(struct task_struct *, struct audit_context *);
163 struct audit_context *);
164extern void audit_set_auditable(struct audit_context *);
165#else 163#else
166#define audit_signal_info(s,t) AUDIT_DISABLED 164#define audit_signal_info(s,t) AUDIT_DISABLED
167#define audit_filter_inodes(t,c) AUDIT_DISABLED 165#define audit_filter_inodes(t,c) AUDIT_DISABLED
168#define audit_set_auditable(c)
169#endif 166#endif
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 0febaa0f784c..995a2e86808d 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -919,6 +919,7 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
919 new->action = old->action; 919 new->action = old->action;
920 for (i = 0; i < AUDIT_BITMASK_SIZE; i++) 920 for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
921 new->mask[i] = old->mask[i]; 921 new->mask[i] = old->mask[i];
922 new->prio = old->prio;
922 new->buflen = old->buflen; 923 new->buflen = old->buflen;
923 new->inode_f = old->inode_f; 924 new->inode_f = old->inode_f;
924 new->watch = NULL; 925 new->watch = NULL;
@@ -987,9 +988,8 @@ static void audit_update_watch(struct audit_parent *parent,
987 988
988 /* If the update involves invalidating rules, do the inode-based 989 /* If the update involves invalidating rules, do the inode-based
989 * filtering now, so we don't omit records. */ 990 * filtering now, so we don't omit records. */
990 if (invalidating && current->audit_context && 991 if (invalidating && current->audit_context)
991 audit_filter_inodes(current, current->audit_context) == AUDIT_RECORD_CONTEXT) 992 audit_filter_inodes(current, current->audit_context);
992 audit_set_auditable(current->audit_context);
993 993
994 nwatch = audit_dupe_watch(owatch); 994 nwatch = audit_dupe_watch(owatch);
995 if (IS_ERR(nwatch)) { 995 if (IS_ERR(nwatch)) {
@@ -1258,6 +1258,9 @@ static int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp,
1258 return ret; 1258 return ret;
1259} 1259}
1260 1260
1261static u64 prio_low = ~0ULL/2;
1262static u64 prio_high = ~0ULL/2 - 1;
1263
1261/* Add rule to given filterlist if not a duplicate. */ 1264/* Add rule to given filterlist if not a duplicate. */
1262static inline int audit_add_rule(struct audit_entry *entry, 1265static inline int audit_add_rule(struct audit_entry *entry,
1263 struct list_head *list) 1266 struct list_head *list)
@@ -1319,6 +1322,14 @@ static inline int audit_add_rule(struct audit_entry *entry,
1319 } 1322 }
1320 } 1323 }
1321 1324
1325 entry->rule.prio = ~0ULL;
1326 if (entry->rule.listnr == AUDIT_FILTER_EXIT) {
1327 if (entry->rule.flags & AUDIT_FILTER_PREPEND)
1328 entry->rule.prio = ++prio_high;
1329 else
1330 entry->rule.prio = --prio_low;
1331 }
1332
1322 if (entry->rule.flags & AUDIT_FILTER_PREPEND) { 1333 if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
1323 list_add_rcu(&entry->list, list); 1334 list_add_rcu(&entry->list, list);
1324 entry->rule.flags &= ~AUDIT_FILTER_PREPEND; 1335 entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index c76a58215f54..19d2c2747c8d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -165,14 +165,14 @@ struct audit_tree_refs {
165struct audit_context { 165struct audit_context {
166 int dummy; /* must be the first element */ 166 int dummy; /* must be the first element */
167 int in_syscall; /* 1 if task is in a syscall */ 167 int in_syscall; /* 1 if task is in a syscall */
168 enum audit_state state; 168 enum audit_state state, current_state;
169 unsigned int serial; /* serial number for record */ 169 unsigned int serial; /* serial number for record */
170 struct timespec ctime; /* time of syscall entry */ 170 struct timespec ctime; /* time of syscall entry */
171 int major; /* syscall number */ 171 int major; /* syscall number */
172 unsigned long argv[4]; /* syscall arguments */ 172 unsigned long argv[4]; /* syscall arguments */
173 int return_valid; /* return code is valid */ 173 int return_valid; /* return code is valid */
174 long return_code;/* syscall return code */ 174 long return_code;/* syscall return code */
175 int auditable; /* 1 if record should be written */ 175 u64 prio;
176 int name_count; 176 int name_count;
177 struct audit_names names[AUDIT_NAMES]; 177 struct audit_names names[AUDIT_NAMES];
178 char * filterkey; /* key for rule that triggered record */ 178 char * filterkey; /* key for rule that triggered record */
@@ -630,8 +630,16 @@ static int audit_filter_rules(struct task_struct *tsk,
630 return 0; 630 return 0;
631 } 631 }
632 } 632 }
633 if (rule->filterkey && ctx) 633
634 ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC); 634 if (ctx) {
635 if (rule->prio <= ctx->prio)
636 return 0;
637 if (rule->filterkey) {
638 kfree(ctx->filterkey);
639 ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
640 }
641 ctx->prio = rule->prio;
642 }
635 switch (rule->action) { 643 switch (rule->action) {
636 case AUDIT_NEVER: *state = AUDIT_DISABLED; break; 644 case AUDIT_NEVER: *state = AUDIT_DISABLED; break;
637 case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; 645 case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break;
@@ -685,6 +693,7 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
685 audit_filter_rules(tsk, &e->rule, ctx, NULL, 693 audit_filter_rules(tsk, &e->rule, ctx, NULL,
686 &state)) { 694 &state)) {
687 rcu_read_unlock(); 695 rcu_read_unlock();
696 ctx->current_state = state;
688 return state; 697 return state;
689 } 698 }
690 } 699 }
@@ -698,15 +707,14 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
698 * buckets applicable to the inode numbers in audit_names[]. 707 * buckets applicable to the inode numbers in audit_names[].
699 * Regarding audit_state, same rules apply as for audit_filter_syscall(). 708 * Regarding audit_state, same rules apply as for audit_filter_syscall().
700 */ 709 */
701enum audit_state audit_filter_inodes(struct task_struct *tsk, 710void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx)
702 struct audit_context *ctx)
703{ 711{
704 int i; 712 int i;
705 struct audit_entry *e; 713 struct audit_entry *e;
706 enum audit_state state; 714 enum audit_state state;
707 715
708 if (audit_pid && tsk->tgid == audit_pid) 716 if (audit_pid && tsk->tgid == audit_pid)
709 return AUDIT_DISABLED; 717 return;
710 718
711 rcu_read_lock(); 719 rcu_read_lock();
712 for (i = 0; i < ctx->name_count; i++) { 720 for (i = 0; i < ctx->name_count; i++) {
@@ -723,17 +731,20 @@ enum audit_state audit_filter_inodes(struct task_struct *tsk,
723 if ((e->rule.mask[word] & bit) == bit && 731 if ((e->rule.mask[word] & bit) == bit &&
724 audit_filter_rules(tsk, &e->rule, ctx, n, &state)) { 732 audit_filter_rules(tsk, &e->rule, ctx, n, &state)) {
725 rcu_read_unlock(); 733 rcu_read_unlock();
726 return state; 734 ctx->current_state = state;
735 return;
727 } 736 }
728 } 737 }
729 } 738 }
730 rcu_read_unlock(); 739 rcu_read_unlock();
731 return AUDIT_BUILD_CONTEXT;
732} 740}
733 741
734void audit_set_auditable(struct audit_context *ctx) 742static void audit_set_auditable(struct audit_context *ctx)
735{ 743{
736 ctx->auditable = 1; 744 if (!ctx->prio) {
745 ctx->prio = 1;
746 ctx->current_state = AUDIT_RECORD_CONTEXT;
747 }
737} 748}
738 749
739static inline struct audit_context *audit_get_context(struct task_struct *tsk, 750static inline struct audit_context *audit_get_context(struct task_struct *tsk,
@@ -764,23 +775,11 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
764 else 775 else
765 context->return_code = return_code; 776 context->return_code = return_code;
766 777
767 if (context->in_syscall && !context->dummy && !context->auditable) { 778 if (context->in_syscall && !context->dummy) {
768 enum audit_state state; 779 audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]);
769 780 audit_filter_inodes(tsk, context);
770 state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]);
771 if (state == AUDIT_RECORD_CONTEXT) {
772 context->auditable = 1;
773 goto get_context;
774 }
775
776 state = audit_filter_inodes(tsk, context);
777 if (state == AUDIT_RECORD_CONTEXT)
778 context->auditable = 1;
779
780 } 781 }
781 782
782get_context:
783
784 tsk->audit_context = NULL; 783 tsk->audit_context = NULL;
785 return context; 784 return context;
786} 785}
@@ -790,8 +789,7 @@ static inline void audit_free_names(struct audit_context *context)
790 int i; 789 int i;
791 790
792#if AUDIT_DEBUG == 2 791#if AUDIT_DEBUG == 2
793 if (context->auditable 792 if (context->put_count + context->ino_count != context->name_count) {
794 ||context->put_count + context->ino_count != context->name_count) {
795 printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d" 793 printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"
796 " name_count=%d put_count=%d" 794 " name_count=%d put_count=%d"
797 " ino_count=%d [NOT freeing]\n", 795 " ino_count=%d [NOT freeing]\n",
@@ -842,6 +840,7 @@ static inline void audit_zero_context(struct audit_context *context,
842{ 840{
843 memset(context, 0, sizeof(*context)); 841 memset(context, 0, sizeof(*context));
844 context->state = state; 842 context->state = state;
843 context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
845} 844}
846 845
847static inline struct audit_context *audit_alloc_context(enum audit_state state) 846static inline struct audit_context *audit_alloc_context(enum audit_state state)
@@ -1543,7 +1542,7 @@ void audit_free(struct task_struct *tsk)
1543 * We use GFP_ATOMIC here because we might be doing this 1542 * We use GFP_ATOMIC here because we might be doing this
1544 * in the context of the idle thread */ 1543 * in the context of the idle thread */
1545 /* that can happen only if we are called from do_exit() */ 1544 /* that can happen only if we are called from do_exit() */
1546 if (context->in_syscall && context->auditable) 1545 if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
1547 audit_log_exit(context, tsk); 1546 audit_log_exit(context, tsk);
1548 1547
1549 audit_free_context(context); 1548 audit_free_context(context);
@@ -1627,15 +1626,17 @@ void audit_syscall_entry(int arch, int major,
1627 1626
1628 state = context->state; 1627 state = context->state;
1629 context->dummy = !audit_n_rules; 1628 context->dummy = !audit_n_rules;
1630 if (!context->dummy && (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT)) 1629 if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
1630 context->prio = 0;
1631 state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]); 1631 state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]);
1632 }
1632 if (likely(state == AUDIT_DISABLED)) 1633 if (likely(state == AUDIT_DISABLED))
1633 return; 1634 return;
1634 1635
1635 context->serial = 0; 1636 context->serial = 0;
1636 context->ctime = CURRENT_TIME; 1637 context->ctime = CURRENT_TIME;
1637 context->in_syscall = 1; 1638 context->in_syscall = 1;
1638 context->auditable = !!(state == AUDIT_RECORD_CONTEXT); 1639 context->current_state = state;
1639 context->ppid = 0; 1640 context->ppid = 0;
1640} 1641}
1641 1642
@@ -1643,17 +1644,20 @@ void audit_finish_fork(struct task_struct *child)
1643{ 1644{
1644 struct audit_context *ctx = current->audit_context; 1645 struct audit_context *ctx = current->audit_context;
1645 struct audit_context *p = child->audit_context; 1646 struct audit_context *p = child->audit_context;
1646 if (!p || !ctx || !ctx->auditable) 1647 if (!p || !ctx)
1648 return;
1649 if (!ctx->in_syscall || ctx->current_state != AUDIT_RECORD_CONTEXT)
1647 return; 1650 return;
1648 p->arch = ctx->arch; 1651 p->arch = ctx->arch;
1649 p->major = ctx->major; 1652 p->major = ctx->major;
1650 memcpy(p->argv, ctx->argv, sizeof(ctx->argv)); 1653 memcpy(p->argv, ctx->argv, sizeof(ctx->argv));
1651 p->ctime = ctx->ctime; 1654 p->ctime = ctx->ctime;
1652 p->dummy = ctx->dummy; 1655 p->dummy = ctx->dummy;
1653 p->auditable = ctx->auditable;
1654 p->in_syscall = ctx->in_syscall; 1656 p->in_syscall = ctx->in_syscall;
1655 p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL); 1657 p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL);
1656 p->ppid = current->pid; 1658 p->ppid = current->pid;
1659 p->prio = ctx->prio;
1660 p->current_state = ctx->current_state;
1657} 1661}
1658 1662
1659/** 1663/**
@@ -1677,11 +1681,11 @@ void audit_syscall_exit(int valid, long return_code)
1677 if (likely(!context)) 1681 if (likely(!context))
1678 return; 1682 return;
1679 1683
1680 if (context->in_syscall && context->auditable) 1684 if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
1681 audit_log_exit(context, tsk); 1685 audit_log_exit(context, tsk);
1682 1686
1683 context->in_syscall = 0; 1687 context->in_syscall = 0;
1684 context->auditable = 0; 1688 context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
1685 1689
1686 if (context->previous) { 1690 if (context->previous) {
1687 struct audit_context *new_context = context->previous; 1691 struct audit_context *new_context = context->previous;
@@ -2091,7 +2095,10 @@ int auditsc_get_stamp(struct audit_context *ctx,
2091 t->tv_sec = ctx->ctime.tv_sec; 2095 t->tv_sec = ctx->ctime.tv_sec;
2092 t->tv_nsec = ctx->ctime.tv_nsec; 2096 t->tv_nsec = ctx->ctime.tv_nsec;
2093 *serial = ctx->serial; 2097 *serial = ctx->serial;
2094 ctx->auditable = 1; 2098 if (!ctx->prio) {
2099 ctx->prio = 1;
2100 ctx->current_state = AUDIT_RECORD_CONTEXT;
2101 }
2095 return 1; 2102 return 1;
2096} 2103}
2097 2104