diff --git a/include/linux/audit.h b/include/linux/audit.h index 9334fbef7bae63fab7993ead40177297ca1c9ca3..543200fc37ac7d391388ec634543116221be3487 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -239,6 +239,7 @@ extern void audit_seccomp(unsigned long syscall, long signr, int code); extern void audit_seccomp_actions_logged(const char *names, const char *old_names, int res); extern void __audit_ptrace(struct task_struct *t); +extern void audit_rule_syscall_mask_update(struct audit_krule rule, bool add); static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx) { @@ -513,6 +514,8 @@ static inline void audit_inode_child(struct inode *parent, { } static inline void audit_core_dumps(long signr) { } +static inline void audit_rule_syscall_mask_update(struct audit_krule rule, bool add) +{} static inline void audit_seccomp(unsigned long syscall, long signr, int code) { } static inline void audit_seccomp_actions_logged(const char *names, diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 425c67e4f5681a7fc0947ff916138a905a19939c..43d17b4368066f35900a8d37ff95e7c8abf29ae1 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -946,6 +946,8 @@ static inline int audit_add_rule(struct audit_entry *entry) return err; } + audit_rule_syscall_mask_update(entry->rule, true); + if (watch) { /* audit_filter_mutex is dropped and re-taken during this call */ err = audit_add_watch(&entry->rule, &list); @@ -1024,6 +1026,8 @@ int audit_del_rule(struct audit_entry *entry) goto out; } + audit_rule_syscall_mask_update(entry->rule, false); + if (e->rule.watch) audit_remove_watch_rule(&e->rule); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 1513873e23bd12d956c4fbcaf05c979f14cd1303..7b3d43d257a6013eebf41aeef031f0414ccbecc4 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -96,6 +96,9 @@ int audit_n_rules; /* determines whether we collect data for signals sent */ int audit_signals; +/* whether one syscall needs to be audited */ +u32 audit_rule_syscall_mask[NR_syscalls] = {0}; + struct audit_aux_data { struct audit_aux_data *next; int type; @@ -758,6 +761,29 @@ static int audit_in_mask(const struct audit_krule *rule, unsigned long val) return rule->mask[word] & bit; } +/** + * audit_rule_syscall_mask_update - update syscall mask when audit rule changes + * @rule: audit rule + * @add: add rule or delete + * + * Caller must hold audit_filter_mutex to prevent stale data. + */ +void audit_rule_syscall_mask_update(struct audit_krule rule, bool add) +{ + int i; + + if (rule.listnr == AUDIT_FILTER_EXIT && !rule.watch && !rule.tree) { + for (i = 0; i < NR_syscalls; i++) { + if (unlikely(audit_in_mask(&rule, i))) { + if (add == true) + audit_rule_syscall_mask[i]++; + else + audit_rule_syscall_mask[i]--; + } + } + } +} + /* 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 @@ -866,7 +892,8 @@ static inline struct audit_context *audit_take_context(struct task_struct *tsk, context->return_code = return_code; if (context->in_syscall && !context->dummy) { - audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); + if (unlikely(audit_rule_syscall_mask[context->major])) + audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); audit_filter_inodes(tsk, context); }