| From a3c54931199565930d6d84f4c3456f6440aefd41 Mon Sep 17 00:00:00 2001 |
| From: Andy Lutomirski <luto@amacapital.net> |
| Date: Wed, 28 May 2014 23:09:58 -0400 |
| Subject: auditsc: audit_krule mask accesses need bounds checking |
| |
| From: Andy Lutomirski <luto@amacapital.net> |
| |
| commit a3c54931199565930d6d84f4c3456f6440aefd41 upstream. |
| |
| Fixes an easy DoS and possible information disclosure. |
| |
| This does nothing about the broken state of x32 auditing. |
| |
| eparis: If the admin has enabled auditd and has specifically loaded |
| audit rules. This bug has been around since before git. Wow... |
| |
| Signed-off-by: Andy Lutomirski <luto@amacapital.net> |
| Signed-off-by: Eric Paris <eparis@redhat.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/auditsc.c | 27 ++++++++++++++++++--------- |
| 1 file changed, 18 insertions(+), 9 deletions(-) |
| |
| --- a/kernel/auditsc.c |
| +++ b/kernel/auditsc.c |
| @@ -720,6 +720,22 @@ static enum audit_state audit_filter_tas |
| return AUDIT_BUILD_CONTEXT; |
| } |
| |
| +static int audit_in_mask(const struct audit_krule *rule, unsigned long val) |
| +{ |
| + int word, bit; |
| + |
| + if (val > 0xffffffff) |
| + return false; |
| + |
| + word = AUDIT_WORD(val); |
| + if (word >= AUDIT_BITMASK_SIZE) |
| + return false; |
| + |
| + bit = AUDIT_BIT(val); |
| + |
| + return rule->mask[word] & bit; |
| +} |
| + |
| /* At syscall entry and exit time, this filter is called if the |
| * audit_state is not low enough that auditing cannot take place, but is |
| * also not high enough that we already know we have to write an audit |
| @@ -737,11 +753,8 @@ static enum audit_state audit_filter_sys |
| |
| rcu_read_lock(); |
| if (!list_empty(list)) { |
| - int word = AUDIT_WORD(ctx->major); |
| - int bit = AUDIT_BIT(ctx->major); |
| - |
| list_for_each_entry_rcu(e, list, list) { |
| - if ((e->rule.mask[word] & bit) == bit && |
| + if (audit_in_mask(&e->rule, ctx->major) && |
| audit_filter_rules(tsk, &e->rule, ctx, NULL, |
| &state, false)) { |
| rcu_read_unlock(); |
| @@ -761,20 +774,16 @@ static enum audit_state audit_filter_sys |
| static int audit_filter_inode_name(struct task_struct *tsk, |
| struct audit_names *n, |
| struct audit_context *ctx) { |
| - int word, bit; |
| int h = audit_hash_ino((u32)n->ino); |
| struct list_head *list = &audit_inode_hash[h]; |
| struct audit_entry *e; |
| enum audit_state state; |
| |
| - word = AUDIT_WORD(ctx->major); |
| - bit = AUDIT_BIT(ctx->major); |
| - |
| if (list_empty(list)) |
| return 0; |
| |
| list_for_each_entry_rcu(e, list, list) { |
| - if ((e->rule.mask[word] & bit) == bit && |
| + if (audit_in_mask(&e->rule, ctx->major) && |
| audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) { |
| ctx->current_state = state; |
| return 1; |