aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRichard Guy Briggs <rgb@redhat.com>2017-08-23 07:03:39 -0400
committerPaul Moore <paul@paul-moore.com>2017-11-10 16:08:56 -0500
commit42d5e37654e4cdb9fb2e2f3ab30045fee35c42d8 (patch)
tree5fa06c6189f135561616208016519bb61c309b1b /kernel
parentf7b53637c090bd8ce2dc74ad0f3aa1898aff2524 (diff)
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>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/auditfilter.c39
-rw-r--r--kernel/auditsc.c23
2 files changed, 55 insertions, 7 deletions
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 0b0aa5854dac..4a1758adb222 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -56,7 +56,8 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
56 LIST_HEAD_INIT(audit_filter_list[3]), 56 LIST_HEAD_INIT(audit_filter_list[3]),
57 LIST_HEAD_INIT(audit_filter_list[4]), 57 LIST_HEAD_INIT(audit_filter_list[4]),
58 LIST_HEAD_INIT(audit_filter_list[5]), 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#error Fix audit_filter_list initialiser 61#error Fix audit_filter_list initialiser
61#endif 62#endif
62}; 63};
@@ -67,6 +68,7 @@ static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = {
67 LIST_HEAD_INIT(audit_rules_list[3]), 68 LIST_HEAD_INIT(audit_rules_list[3]),
68 LIST_HEAD_INIT(audit_rules_list[4]), 69 LIST_HEAD_INIT(audit_rules_list[4]),
69 LIST_HEAD_INIT(audit_rules_list[5]), 70 LIST_HEAD_INIT(audit_rules_list[5]),
71 LIST_HEAD_INIT(audit_rules_list[6]),
70}; 72};
71 73
72DEFINE_MUTEX(audit_filter_mutex); 74DEFINE_MUTEX(audit_filter_mutex);
@@ -263,6 +265,7 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *
263#endif 265#endif
264 case AUDIT_FILTER_USER: 266 case AUDIT_FILTER_USER:
265 case AUDIT_FILTER_TYPE: 267 case AUDIT_FILTER_TYPE:
268 case AUDIT_FILTER_FS:
266 ; 269 ;
267 } 270 }
268 if (unlikely(rule->action == AUDIT_POSSIBLE)) { 271 if (unlikely(rule->action == AUDIT_POSSIBLE)) {
@@ -338,6 +341,21 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
338 entry->rule.listnr != AUDIT_FILTER_USER) 341 entry->rule.listnr != AUDIT_FILTER_USER)
339 return -EINVAL; 342 return -EINVAL;
340 break; 343 break;
344 case AUDIT_FSTYPE:
345 if (entry->rule.listnr != AUDIT_FILTER_FS)
346 return -EINVAL;
347 break;
348 }
349
350 switch(entry->rule.listnr) {
351 case AUDIT_FILTER_FS:
352 switch(f->type) {
353 case AUDIT_FSTYPE:
354 case AUDIT_FILTERKEY:
355 break;
356 default:
357 return -EINVAL;
358 }
341 } 359 }
342 360
343 switch(f->type) { 361 switch(f->type) {
@@ -391,6 +409,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
391 return -EINVAL; 409 return -EINVAL;
392 /* FALL THROUGH */ 410 /* FALL THROUGH */
393 case AUDIT_ARCH: 411 case AUDIT_ARCH:
412 case AUDIT_FSTYPE:
394 if (f->op != Audit_not_equal && f->op != Audit_equal) 413 if (f->op != Audit_not_equal && f->op != Audit_equal)
395 return -EINVAL; 414 return -EINVAL;
396 break; 415 break;
@@ -910,10 +929,13 @@ static inline int audit_add_rule(struct audit_entry *entry)
910#ifdef CONFIG_AUDITSYSCALL 929#ifdef CONFIG_AUDITSYSCALL
911 int dont_count = 0; 930 int dont_count = 0;
912 931
913 /* If either of these, don't count towards total */ 932 /* If any of these, don't count towards total */
914 if (entry->rule.listnr == AUDIT_FILTER_USER || 933 switch(entry->rule.listnr) {
915 entry->rule.listnr == AUDIT_FILTER_TYPE) 934 case AUDIT_FILTER_USER:
935 case AUDIT_FILTER_TYPE:
936 case AUDIT_FILTER_FS:
916 dont_count = 1; 937 dont_count = 1;
938 }
917#endif 939#endif
918 940
919 mutex_lock(&audit_filter_mutex); 941 mutex_lock(&audit_filter_mutex);
@@ -989,10 +1011,13 @@ int audit_del_rule(struct audit_entry *entry)
989#ifdef CONFIG_AUDITSYSCALL 1011#ifdef CONFIG_AUDITSYSCALL
990 int dont_count = 0; 1012 int dont_count = 0;
991 1013
992 /* If either of these, don't count towards total */ 1014 /* If any of these, don't count towards total */
993 if (entry->rule.listnr == AUDIT_FILTER_USER || 1015 switch(entry->rule.listnr) {
994 entry->rule.listnr == AUDIT_FILTER_TYPE) 1016 case AUDIT_FILTER_USER:
1017 case AUDIT_FILTER_TYPE:
1018 case AUDIT_FILTER_FS:
995 dont_count = 1; 1019 dont_count = 1;
1020 }
996#endif 1021#endif
997 1022
998 mutex_lock(&audit_filter_mutex); 1023 mutex_lock(&audit_filter_mutex);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index aac1a41f82bd..c9bb29e17335 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1869,10 +1869,33 @@ void __audit_inode_child(struct inode *parent,
1869 struct inode *inode = d_backing_inode(dentry); 1869 struct inode *inode = d_backing_inode(dentry);
1870 const char *dname = dentry->d_name.name; 1870 const char *dname = dentry->d_name.name;
1871 struct audit_names *n, *found_parent = NULL, *found_child = NULL; 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 if (!context->in_syscall) 1876 if (!context->in_syscall)
1874 return; 1877 return;
1875 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();
1898
1876 if (inode) 1899 if (inode)
1877 handle_one(inode); 1900 handle_one(inode);
1878 1901