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

audit: filter PATH records keyed on filesystem magic

Tracefs or debugfs were causing hundreds to thousands of PATH records to
be associated with the init_module and finit_module SYSCALL records on a
few modules when the following rule was in place for startup:
-a always,exit -F arch=x86_64 -S init_module -F key=mod-load

Provide a method to ignore these large number of PATH records from
overwhelming the logs if they are not of interest. Introduce a new
filter list "AUDIT_FILTER_FS", with a new field type AUDIT_FSTYPE,
which keys off the filesystem 4-octet hexadecimal magic identifier to
filter specific filesystem PATH records.

An example rule would look like:
-a never,filesystem -F fstype=0x74726163 -F key=ignore_tracefs
-a never,filesystem -F fstype=0x64626720 -F key=ignore_debugfs

Arguably the better way to address this issue is to disable tracefs and
debugfs on boot from production systems.

See: https://github.com/linux-audit/audit-kernel/issues/16
See: https://github.com/linux-audit/audit-userspace/issues/8
Test case: https://github.com/linux-audit/audit-testsuite/issues/42

Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
[PM: fixed the whitespace damage in kernel/auditsc.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>

authored by

Richard Guy Briggs and committed by
Paul Moore
42d5e376 f7b53637

+61 -9
+6 -2
include/uapi/linux/audit.h
··· 155 155 #define AUDIT_FILTER_WATCH 0x03 /* Apply rule to file system watches */ 156 156 #define AUDIT_FILTER_EXIT 0x04 /* Apply rule at syscall exit */ 157 157 #define AUDIT_FILTER_TYPE 0x05 /* Apply rule at audit_log_start */ 158 + #define AUDIT_FILTER_FS 0x06 /* Apply rule at __audit_inode_child */ 158 159 159 - #define AUDIT_NR_FILTERS 6 160 + #define AUDIT_NR_FILTERS 7 160 161 161 162 #define AUDIT_FILTER_PREPEND 0x10 /* Prepend to front of list */ 162 163 ··· 257 256 #define AUDIT_OBJ_LEV_HIGH 23 258 257 #define AUDIT_LOGINUID_SET 24 259 258 #define AUDIT_SESSIONID 25 /* Session ID */ 259 + #define AUDIT_FSTYPE 26 /* FileSystem Type */ 260 260 261 261 /* These are ONLY useful when checking 262 262 * at syscall exit time (AUDIT_AT_EXIT). */ ··· 337 335 #define AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND 0x00000008 338 336 #define AUDIT_FEATURE_BITMAP_SESSIONID_FILTER 0x00000010 339 337 #define AUDIT_FEATURE_BITMAP_LOST_RESET 0x00000020 338 + #define AUDIT_FEATURE_BITMAP_FILTER_FS 0x00000040 340 339 341 340 #define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \ 342 341 AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME | \ 343 342 AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH | \ 344 343 AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND | \ 345 344 AUDIT_FEATURE_BITMAP_SESSIONID_FILTER | \ 346 - AUDIT_FEATURE_BITMAP_LOST_RESET) 345 + AUDIT_FEATURE_BITMAP_LOST_RESET | \ 346 + AUDIT_FEATURE_BITMAP_FILTER_FS) 347 347 348 348 /* deprecated: AUDIT_VERSION_* */ 349 349 #define AUDIT_VERSION_LATEST AUDIT_FEATURE_BITMAP_ALL
+32 -7
kernel/auditfilter.c
··· 56 56 LIST_HEAD_INIT(audit_filter_list[3]), 57 57 LIST_HEAD_INIT(audit_filter_list[4]), 58 58 LIST_HEAD_INIT(audit_filter_list[5]), 59 - #if AUDIT_NR_FILTERS != 6 59 + LIST_HEAD_INIT(audit_filter_list[6]), 60 + #if AUDIT_NR_FILTERS != 7 60 61 #error Fix audit_filter_list initialiser 61 62 #endif 62 63 }; ··· 68 67 LIST_HEAD_INIT(audit_rules_list[3]), 69 68 LIST_HEAD_INIT(audit_rules_list[4]), 70 69 LIST_HEAD_INIT(audit_rules_list[5]), 70 + LIST_HEAD_INIT(audit_rules_list[6]), 71 71 }; 72 72 73 73 DEFINE_MUTEX(audit_filter_mutex); ··· 265 263 #endif 266 264 case AUDIT_FILTER_USER: 267 265 case AUDIT_FILTER_TYPE: 266 + case AUDIT_FILTER_FS: 268 267 ; 269 268 } 270 269 if (unlikely(rule->action == AUDIT_POSSIBLE)) { ··· 341 338 entry->rule.listnr != AUDIT_FILTER_USER) 342 339 return -EINVAL; 343 340 break; 341 + case AUDIT_FSTYPE: 342 + if (entry->rule.listnr != AUDIT_FILTER_FS) 343 + return -EINVAL; 344 + break; 345 + } 346 + 347 + switch(entry->rule.listnr) { 348 + case AUDIT_FILTER_FS: 349 + switch(f->type) { 350 + case AUDIT_FSTYPE: 351 + case AUDIT_FILTERKEY: 352 + break; 353 + default: 354 + return -EINVAL; 355 + } 344 356 } 345 357 346 358 switch(f->type) { ··· 409 391 return -EINVAL; 410 392 /* FALL THROUGH */ 411 393 case AUDIT_ARCH: 394 + case AUDIT_FSTYPE: 412 395 if (f->op != Audit_not_equal && f->op != Audit_equal) 413 396 return -EINVAL; 414 397 break; ··· 929 910 #ifdef CONFIG_AUDITSYSCALL 930 911 int dont_count = 0; 931 912 932 - /* If either of these, don't count towards total */ 933 - if (entry->rule.listnr == AUDIT_FILTER_USER || 934 - entry->rule.listnr == AUDIT_FILTER_TYPE) 913 + /* If any of these, don't count towards total */ 914 + switch(entry->rule.listnr) { 915 + case AUDIT_FILTER_USER: 916 + case AUDIT_FILTER_TYPE: 917 + case AUDIT_FILTER_FS: 935 918 dont_count = 1; 919 + } 936 920 #endif 937 921 938 922 mutex_lock(&audit_filter_mutex); ··· 1011 989 #ifdef CONFIG_AUDITSYSCALL 1012 990 int dont_count = 0; 1013 991 1014 - /* If either of these, don't count towards total */ 1015 - if (entry->rule.listnr == AUDIT_FILTER_USER || 1016 - entry->rule.listnr == AUDIT_FILTER_TYPE) 992 + /* If any of these, don't count towards total */ 993 + switch(entry->rule.listnr) { 994 + case AUDIT_FILTER_USER: 995 + case AUDIT_FILTER_TYPE: 996 + case AUDIT_FILTER_FS: 1017 997 dont_count = 1; 998 + } 1018 999 #endif 1019 1000 1020 1001 mutex_lock(&audit_filter_mutex);
+23
kernel/auditsc.c
··· 1869 1869 struct inode *inode = d_backing_inode(dentry); 1870 1870 const char *dname = dentry->d_name.name; 1871 1871 struct audit_names *n, *found_parent = NULL, *found_child = NULL; 1872 + struct audit_entry *e; 1873 + struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS]; 1874 + int i; 1872 1875 1873 1876 if (!context->in_syscall) 1874 1877 return; 1878 + 1879 + rcu_read_lock(); 1880 + if (!list_empty(list)) { 1881 + list_for_each_entry_rcu(e, list, list) { 1882 + for (i = 0; i < e->rule.field_count; i++) { 1883 + struct audit_field *f = &e->rule.fields[i]; 1884 + 1885 + if (f->type == AUDIT_FSTYPE) { 1886 + if (audit_comparator(parent->i_sb->s_magic, 1887 + f->op, f->val)) { 1888 + if (e->rule.action == AUDIT_NEVER) { 1889 + rcu_read_unlock(); 1890 + return; 1891 + } 1892 + } 1893 + } 1894 + } 1895 + } 1896 + } 1897 + rcu_read_unlock(); 1875 1898 1876 1899 if (inode) 1877 1900 handle_one(inode);