From c0205cb309d8267f3d52a366c3d694f4b84fb52b Mon Sep 17 00:00:00 2001 From: meganz009 Date: Sat, 17 Jun 2023 22:21:00 +0800 Subject: [PATCH] audit: speed up syscall rule filtering audit_filter_list to find out whether current syscall match one rule. This takes o(n), which is not necessary, specially for user who add a very few syscall rules. On the other hand, user may not much care about rule add/delete speed. So do o(n) calculates when rule changes, and ease the burden of audit_filter_syscall(). Define audit_rule_syscall_mask[NR_syscalls], every element stands for one syscall.audit_rule_syscall_mask[n] == 0 indicates no rule cares about syscall n, so we can avoid unnecessary calling audit_filter_syscall(). audit_rule_syscall_mask[n] > 0 indicates at least one rule cares about syscall n, then calls audit_filter_syscall(). Update audit_rule_syscall_mask[n] when syscall rule changes. Signed-off-by: Yang Yang Signed-off-by: Wenya Zhang Reviewed-by: Huang Jian --- include/linux/audit.h | 3 +++ kernel/auditfilter.c | 4 ++++ kernel/auditsc.c | 29 ++++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 9334fbef7bae..543200fc37ac 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 425c67e4f568..43d17b436806 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 1513873e23bd..7b3d43d257a6 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); } -- Gitee