From b48345aafb203803ccda4488cb5409b1ed435c0a Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Fri, 10 May 2019 12:21:49 -0400 Subject: [PATCH 1/5] audit: deliver signal_info regarless of syscall When a process signals the audit daemon (shutdown, rotate, resume, reconfig) but syscall auditing is not enabled, we still want to know the identity of the process sending the signal to the audit daemon. Move audit_signal_info() out of syscall auditing to general auditing but create a new function audit_signal_info_syscall() to take care of the syscall dependent parts for when syscall auditing is enabled. Please see the github kernel audit issue https://github.com/linux-audit/audit-kernel/issues/111 Signed-off-by: Richard Guy Briggs Signed-off-by: Paul Moore --- include/linux/audit.h | 9 +++++++++ kernel/audit.c | 27 +++++++++++++++++++++++++++ kernel/audit.h | 8 ++++++-- kernel/auditsc.c | 19 +++---------------- kernel/signal.c | 2 +- 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 43a23e28ba23..b4078560cb73 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -196,6 +196,9 @@ static inline unsigned int audit_get_sessionid(struct task_struct *tsk) } extern u32 audit_enabled; + +extern int audit_signal_info(int sig, struct task_struct *t); + #else /* CONFIG_AUDIT */ static inline __printf(4, 5) void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, @@ -249,6 +252,12 @@ static inline unsigned int audit_get_sessionid(struct task_struct *tsk) } #define audit_enabled AUDIT_OFF + +static inline int audit_signal_info(int sig, struct task_struct *t) +{ + return 0; +} + #endif /* CONFIG_AUDIT */ #ifdef CONFIG_AUDIT_COMPAT_GENERIC diff --git a/kernel/audit.c b/kernel/audit.c index b96bf69183f4..67399ff72d43 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -2273,6 +2273,33 @@ out: return rc; } +/** + * audit_signal_info - record signal info for shutting down audit subsystem + * @sig: signal value + * @t: task being signaled + * + * If the audit subsystem is being terminated, record the task (pid) + * and uid that is doing that. + */ +int audit_signal_info(int sig, struct task_struct *t) +{ + kuid_t uid = current_uid(), auid; + + if (auditd_test_task(t) && + (sig == SIGTERM || sig == SIGHUP || + sig == SIGUSR1 || sig == SIGUSR2)) { + audit_sig_pid = task_tgid_nr(current); + auid = audit_get_loginuid(current); + if (uid_valid(auid)) + audit_sig_uid = auid; + else + audit_sig_uid = uid; + security_task_getsecid(current, &audit_sig_sid); + } + + return audit_signal_info_syscall(t); +} + /** * audit_log_end - end one audit record * @ab: the audit_buffer diff --git a/kernel/audit.h b/kernel/audit.h index 2071725a999f..996d94faad43 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -299,7 +299,7 @@ extern const char *audit_tree_path(struct audit_tree *tree); extern void audit_put_tree(struct audit_tree *tree); extern void audit_kill_trees(struct audit_context *context); -extern int audit_signal_info(int sig, struct task_struct *t); +extern int audit_signal_info_syscall(struct task_struct *t); extern void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx); extern struct list_head *audit_killed_trees(void); @@ -330,7 +330,11 @@ extern struct list_head *audit_killed_trees(void); #define audit_tree_path(rule) "" /* never called */ #define audit_kill_trees(context) BUG() -#define audit_signal_info(s, t) AUDIT_DISABLED +static inline int audit_signal_info_syscall(struct task_struct *t) +{ + return 0; +} + #define audit_filter_inodes(t, c) AUDIT_DISABLED #endif /* CONFIG_AUDITSYSCALL */ diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 95ae27edd417..30aa07b0115f 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2360,30 +2360,17 @@ void __audit_ptrace(struct task_struct *t) } /** - * audit_signal_info - record signal info for shutting down audit subsystem - * @sig: signal value + * audit_signal_info_syscall - record signal info for syscalls * @t: task being signaled * * If the audit subsystem is being terminated, record the task (pid) * and uid that is doing that. */ -int audit_signal_info(int sig, struct task_struct *t) +int audit_signal_info_syscall(struct task_struct *t) { struct audit_aux_data_pids *axp; struct audit_context *ctx = audit_context(); - kuid_t uid = current_uid(), auid, t_uid = task_uid(t); - - if (auditd_test_task(t) && - (sig == SIGTERM || sig == SIGHUP || - sig == SIGUSR1 || sig == SIGUSR2)) { - audit_sig_pid = task_tgid_nr(current); - auid = audit_get_loginuid(current); - if (uid_valid(auid)) - audit_sig_uid = auid; - else - audit_sig_uid = uid; - security_task_getsecid(current, &audit_sig_sid); - } + kuid_t t_uid = task_uid(t); if (!audit_signals || audit_dummy_context()) return 0; diff --git a/kernel/signal.c b/kernel/signal.c index a1eb44dc9ff5..5cfc8611867b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -44,6 +44,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -53,7 +54,6 @@ #include #include #include -#include "audit.h" /* audit_signal_info() */ /* * SLAB caches for signal bits. From ecc68904a3e5efb07cb4f0b97d15c7e0e4623d13 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Wed, 22 May 2019 17:51:09 -0400 Subject: [PATCH 2/5] audit: re-structure audit field valid checks Multiple checks were being done in one switch case statement that started to cause some redundancies and awkward exceptions. Separate the valid field and op check from the select valid values checks. Enforce the elimination of meaningless bitwise and greater/lessthan checks on string fields and other fields with unrelated scalar values. Please see the github issue https://github.com/linux-audit/audit-kernel/issues/73 Signed-off-by: Richard Guy Briggs Signed-off-by: Paul Moore --- kernel/auditfilter.c | 56 +++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 303fb04770ce..d5e54e944f72 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -335,7 +335,7 @@ static u32 audit_to_op(u32 op) /* check if an audit field is valid */ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) { - switch(f->type) { + switch (f->type) { case AUDIT_MSGTYPE: if (entry->rule.listnr != AUDIT_FILTER_EXCLUDE && entry->rule.listnr != AUDIT_FILTER_USER) @@ -347,7 +347,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) break; } - switch(entry->rule.listnr) { + switch (entry->rule.listnr) { case AUDIT_FILTER_FS: switch(f->type) { case AUDIT_FSTYPE: @@ -358,9 +358,16 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) } } - switch(f->type) { - default: - return -EINVAL; + /* Check for valid field type and op */ + switch (f->type) { + case AUDIT_ARG0: + case AUDIT_ARG1: + case AUDIT_ARG2: + case AUDIT_ARG3: + case AUDIT_PERS: /* */ + case AUDIT_DEVMINOR: + /* all ops are valid */ + break; case AUDIT_UID: case AUDIT_EUID: case AUDIT_SUID: @@ -373,46 +380,52 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) case AUDIT_FSGID: case AUDIT_OBJ_GID: case AUDIT_PID: - case AUDIT_PERS: case AUDIT_MSGTYPE: case AUDIT_PPID: case AUDIT_DEVMAJOR: - case AUDIT_DEVMINOR: case AUDIT_EXIT: case AUDIT_SUCCESS: case AUDIT_INODE: case AUDIT_SESSIONID: + case AUDIT_SUBJ_SEN: + case AUDIT_SUBJ_CLR: + case AUDIT_OBJ_LEV_LOW: + case AUDIT_OBJ_LEV_HIGH: /* bit ops are only useful on syscall args */ if (f->op == Audit_bitmask || f->op == Audit_bittest) return -EINVAL; break; - case AUDIT_ARG0: - case AUDIT_ARG1: - case AUDIT_ARG2: - case AUDIT_ARG3: case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: - case AUDIT_SUBJ_SEN: - case AUDIT_SUBJ_CLR: case AUDIT_OBJ_USER: case AUDIT_OBJ_ROLE: case AUDIT_OBJ_TYPE: - case AUDIT_OBJ_LEV_LOW: - case AUDIT_OBJ_LEV_HIGH: case AUDIT_WATCH: case AUDIT_DIR: case AUDIT_FILTERKEY: - break; case AUDIT_LOGINUID_SET: - if ((f->val != 0) && (f->val != 1)) - return -EINVAL; - /* FALL THROUGH */ case AUDIT_ARCH: case AUDIT_FSTYPE: + case AUDIT_PERM: + case AUDIT_FILETYPE: + case AUDIT_FIELD_COMPARE: + case AUDIT_EXE: + /* only equal and not equal valid ops */ if (f->op != Audit_not_equal && f->op != Audit_equal) return -EINVAL; break; + default: + /* field not recognized */ + return -EINVAL; + } + + /* Check for select valid field values */ + switch (f->type) { + case AUDIT_LOGINUID_SET: + if ((f->val != 0) && (f->val != 1)) + return -EINVAL; + break; case AUDIT_PERM: if (f->val & ~15) return -EINVAL; @@ -425,11 +438,10 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) if (f->val > AUDIT_MAX_FIELD_COMPARE) return -EINVAL; break; - case AUDIT_EXE: - if (f->op != Audit_not_equal && f->op != Audit_equal) - return -EINVAL; + default: break; } + return 0; } From bf361231c295d92a28ca283ea713f56e93e55796 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Thu, 9 May 2019 20:01:36 -0400 Subject: [PATCH 3/5] audit: add saddr_fam filter field Provide a method to filter out sockaddr and bind calls by network address family. Existing SOCKADDR records are listed for any network activity. Implement the AUDIT_SADDR_FAM field selector to be able to classify or limit records to specific network address families, such as AF_INET or AF_INET6. An example of a network record that is unlikely to be useful and flood the logs: type=SOCKADDR msg=audit(07/27/2017 12:18:27.019:845) : saddr={ fam=local path=/var/run/nscd/socket } type=SYSCALL msg=audit(07/27/2017 12:18:27.019:845) : arch=x86_64 syscall=connect success=no exit=ENOENT(No such file or directory) a0=0x3 a1=0x7fff229c4980 a2=0x6e a3=0x6 items=1 ppid=3301 pid=6145 auid=sgrubb uid=sgrubb gid=sgrubb euid=sgrubb suid=sgrubb fsuid=sgrubb egid=sgrubb sgid=sgrubb fsgid=sgrubb tty=pts3 ses=4 comm=bash exe=/usr/bin/bash subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=network-test Please see the audit-testsuite PR at https://github.com/linux-audit/audit-testsuite/pull/87 Please see the github issue https://github.com/linux-audit/audit-kernel/issues/64 Please see the github issue for the accompanying userspace support https://github.com/linux-audit/audit-userspace/issues/93 Signed-off-by: Richard Guy Briggs [PM: merge fuzz in auditfilter.c] Signed-off-by: Paul Moore --- include/uapi/linux/audit.h | 1 + kernel/auditfilter.c | 5 +++++ kernel/auditsc.c | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index a1280af20336..c89c6495983d 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -281,6 +281,7 @@ #define AUDIT_OBJ_GID 110 #define AUDIT_FIELD_COMPARE 111 #define AUDIT_EXE 112 +#define AUDIT_SADDR_FAM 113 #define AUDIT_ARG0 200 #define AUDIT_ARG1 (AUDIT_ARG0+1) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index d5e54e944f72..e69d136eeaf6 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -391,6 +391,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) case AUDIT_SUBJ_CLR: case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: + case AUDIT_SADDR_FAM: /* bit ops are only useful on syscall args */ if (f->op == Audit_bitmask || f->op == Audit_bittest) return -EINVAL; @@ -438,6 +439,10 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) if (f->val > AUDIT_MAX_FIELD_COMPARE) return -EINVAL; break; + case AUDIT_SADDR_FAM: + if (f->val >= AF_MAX) + return -EINVAL; + break; default: break; } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 30aa07b0115f..9134fe11ff6c 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -615,6 +615,11 @@ static int audit_filter_rules(struct task_struct *tsk, case AUDIT_LOGINUID_SET: result = audit_comparator(audit_loginuid_set(tsk), f->op, f->val); break; + case AUDIT_SADDR_FAM: + if (ctx->sockaddr) + result = audit_comparator(ctx->sockaddr->ss_family, + f->op, f->val); + break; case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: From 0223fad3c98a9588c159a35dda2ef6e68ca27e3f Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Wed, 22 May 2019 17:52:02 -0400 Subject: [PATCH 4/5] audit: enforce op for string fields The field operator is ignored on several string fields. WATCH, DIR, PERM and FILETYPE field operators are completely ignored and meaningless since the op is not referenced in audit_filter_rules(). Range and bitwise operators are already addressed in ghak73. Honour the operator for WATCH, DIR, PERM, FILETYPE fields as is done in the EXE field. Please see github issue https://github.com/linux-audit/audit-kernel/issues/114 Signed-off-by: Richard Guy Briggs Signed-off-by: Paul Moore --- kernel/auditsc.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 9134fe11ff6c..4effe01ebbe2 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -601,12 +601,20 @@ static int audit_filter_rules(struct task_struct *tsk, } break; case AUDIT_WATCH: - if (name) - result = audit_watch_compare(rule->watch, name->ino, name->dev); + if (name) { + result = audit_watch_compare(rule->watch, + name->ino, + name->dev); + if (f->op == Audit_not_equal) + result = !result; + } break; case AUDIT_DIR: - if (ctx) + if (ctx) { result = match_tree_refs(ctx, rule->tree); + if (f->op == Audit_not_equal) + result = !result; + } break; case AUDIT_LOGINUID: result = audit_uid_comparator(audit_get_loginuid(tsk), @@ -689,9 +697,13 @@ static int audit_filter_rules(struct task_struct *tsk, break; case AUDIT_PERM: result = audit_match_perm(ctx, f->val); + if (f->op == Audit_not_equal) + result = !result; break; case AUDIT_FILETYPE: result = audit_match_filetype(ctx, f->val); + if (f->op == Audit_not_equal) + result = !result; break; case AUDIT_FIELD_COMPARE: result = audit_field_compare(tsk, cred, f, ctx, name); From 839d05e413856bd686a33b59294d4e8238169320 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Thu, 30 May 2019 12:53:42 -0400 Subject: [PATCH 5/5] audit: remove the BUG() calls in the audit rule comparison functions The audit_data_to_entry() function ensures that the operator is valid so we can get rid of these BUG() calls. We keep the "return 0" just so the system behaves in a sane-ish manner should something go horribly wrong. Signed-off-by: Paul Moore Acked-by: Richard Guy Briggs --- kernel/auditfilter.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index e69d136eeaf6..1a21b6aa50d1 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1220,7 +1220,6 @@ int audit_comparator(u32 left, u32 op, u32 right) case Audit_bittest: return ((left & right) == right); default: - BUG(); return 0; } } @@ -1243,7 +1242,6 @@ int audit_uid_comparator(kuid_t left, u32 op, kuid_t right) case Audit_bitmask: case Audit_bittest: default: - BUG(); return 0; } } @@ -1266,7 +1264,6 @@ int audit_gid_comparator(kgid_t left, u32 op, kgid_t right) case Audit_bitmask: case Audit_bittest: default: - BUG(); return 0; } }