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

auditsc: audit_krule mask accesses need bounds checking

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...

Cc: stable@vger.kernel.org
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>

authored by

Andy Lutomirski and committed by
Linus Torvalds
a3c54931 64b2d1fb

+18 -9
+18 -9
kernel/auditsc.c
··· 728 728 return AUDIT_BUILD_CONTEXT; 729 729 } 730 730 731 + static int audit_in_mask(const struct audit_krule *rule, unsigned long val) 732 + { 733 + int word, bit; 734 + 735 + if (val > 0xffffffff) 736 + return false; 737 + 738 + word = AUDIT_WORD(val); 739 + if (word >= AUDIT_BITMASK_SIZE) 740 + return false; 741 + 742 + bit = AUDIT_BIT(val); 743 + 744 + return rule->mask[word] & bit; 745 + } 746 + 731 747 /* At syscall entry and exit time, this filter is called if the 732 748 * audit_state is not low enough that auditing cannot take place, but is 733 749 * also not high enough that we already know we have to write an audit ··· 761 745 762 746 rcu_read_lock(); 763 747 if (!list_empty(list)) { 764 - int word = AUDIT_WORD(ctx->major); 765 - int bit = AUDIT_BIT(ctx->major); 766 - 767 748 list_for_each_entry_rcu(e, list, list) { 768 - if ((e->rule.mask[word] & bit) == bit && 749 + if (audit_in_mask(&e->rule, ctx->major) && 769 750 audit_filter_rules(tsk, &e->rule, ctx, NULL, 770 751 &state, false)) { 771 752 rcu_read_unlock(); ··· 782 769 static int audit_filter_inode_name(struct task_struct *tsk, 783 770 struct audit_names *n, 784 771 struct audit_context *ctx) { 785 - int word, bit; 786 772 int h = audit_hash_ino((u32)n->ino); 787 773 struct list_head *list = &audit_inode_hash[h]; 788 774 struct audit_entry *e; 789 775 enum audit_state state; 790 776 791 - word = AUDIT_WORD(ctx->major); 792 - bit = AUDIT_BIT(ctx->major); 793 - 794 777 if (list_empty(list)) 795 778 return 0; 796 779 797 780 list_for_each_entry_rcu(e, list, list) { 798 - if ((e->rule.mask[word] & bit) == bit && 781 + if (audit_in_mask(&e->rule, ctx->major) && 799 782 audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) { 800 783 ctx->current_state = state; 801 784 return 1;