diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-12-14 23:45:27 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2009-01-04 15:14:41 -0500 |
commit | 0590b9335a1c72a3f0defcc6231287f7817e07c8 (patch) | |
tree | 289fa4668ae304f79f7484ac31b2cab0ab8894c1 /kernel/auditfilter.c | |
parent | 1a9d0797b8977d413435277bf9661efbbd584693 (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>
Diffstat (limited to 'kernel/auditfilter.c')
-rw-r--r-- | kernel/auditfilter.c | 17 |
1 files changed, 14 insertions, 3 deletions
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 | ||
1261 | static u64 prio_low = ~0ULL/2; | ||
1262 | static 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. */ |
1262 | static inline int audit_add_rule(struct audit_entry *entry, | 1265 | static 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; |