[PATCH 3/3] audit: unify audit_filter_{uring(),inode_name(),syscall()}
From: Ankur Arora
Date: Tue Sep 27 2022 - 19:00:34 EST
audit_filter_uring(), audit_filter_inode_name() are substantially similar
to audit_filter_syscall(). Move the core logic to __audit_filter() which
can be parametrized for all three.
On a Skylakex system, getpid() latency (all results aggregated
across 12 boot cycles):
Min Mean Median Max pstdev
(ns) (ns) (ns) (ns)
- 173.11 182.51 179.65 202.09 (+- 4.34%)
+ 162.11 175.26 173.71 190.56 (+- 4.33%)
Performance counter stats for 'bin/getpid' (3 runs) go from:
cycles 706.13 ( +- 4.13% )
instructions 1654.70 ( +- .06% )
IPC 2.35 ( +- 4.25% )
branches 430.99 ( +- .06% )
branch-misses 0.50 ( +- 2.00% )
L1-dcache-loads 440.02 ( +- .07% )
L1-dcache-load-misses 5.22 ( +- 82.75% )
to:
cycles 678.79 ( +- 4.22% )
instructions 1657.79 ( +- .05% )
IPC 2.45 ( +- 4.08% )
branches 432.00 ( +- .05% )
branch-misses 0.38 ( +- 23.68% )
L1-dcache-loads 444.96 ( +- .03% )
L1-dcache-load-misses 5.13 ( +- 73.09% )
(Both aggregated over 12 boot cycles.)
Unclear if the improvement is just run-to-run variation or because of
a slightly denser loop (the list parameter in the list_for_each_entry_rcu()
exit check now comes from a register rather than a constant as before.)
Signed-off-by: Ankur Arora <ankur.a.arora@xxxxxxxxxx>
---
kernel/auditsc.c | 86 +++++++++++++++++++++++++-----------------------
1 file changed, 44 insertions(+), 42 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index bf26f47b5226..dd89a52988b0 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -805,6 +805,41 @@ static bool audit_in_mask(const struct audit_krule *rule, unsigned long val)
return rule->mask[word] & bit;
}
+/**
+ * __audit_filter - common filter
+ *
+ * @tsk: associated task
+ * @ctx: audit context
+ * @list: audit filter list
+ * @op: current syscall/uring_op
+ * @name: name to be filtered (used by audit_filter_inode_name)
+ *
+ * return: 1 if we hit a filter, 0 if we don't
+ */
+static int __audit_filter(struct task_struct *tsk,
+ struct audit_context *ctx,
+ struct list_head *list,
+ unsigned long op,
+ struct audit_names *name)
+{
+ struct audit_entry *e;
+ enum audit_state state;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(e, list, list) {
+ if (unlikely(audit_in_mask(&e->rule, op))) {
+ if (audit_filter_rules(tsk, &e->rule, ctx, name,
+ &state, false)) {
+ rcu_read_unlock();
+ ctx->current_state = state;
+ return 1;
+ }
+ }
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
/**
* audit_filter_uring - apply filters to an io_uring operation
* @tsk: associated task
@@ -813,24 +848,11 @@ static bool audit_in_mask(const struct audit_krule *rule, unsigned long val)
static void audit_filter_uring(struct task_struct *tsk,
struct audit_context *ctx)
{
- struct audit_entry *e;
- enum audit_state state;
-
if (auditd_test_task(tsk))
return;
- rcu_read_lock();
- list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_URING_EXIT],
- list) {
- if (audit_in_mask(&e->rule, ctx->uring_op) &&
- audit_filter_rules(tsk, &e->rule, ctx, NULL, &state,
- false)) {
- rcu_read_unlock();
- ctx->current_state = state;
- return;
- }
- }
- rcu_read_unlock();
+ __audit_filter(tsk, ctx, &audit_filter_list[AUDIT_FILTER_URING_EXIT],
+ ctx->uring_op, NULL);
}
/* At syscall exit time, this filter is called if the audit_state is
@@ -841,26 +863,11 @@ static void audit_filter_uring(struct task_struct *tsk,
static void audit_filter_syscall(struct task_struct *tsk,
struct audit_context *ctx)
{
- struct audit_entry *e;
- enum audit_state state;
- unsigned long major = ctx->major;
-
if (auditd_test_task(tsk))
return;
- rcu_read_lock();
- list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_EXIT], list) {
- if (unlikely(audit_in_mask(&e->rule, major))) {
- if (audit_filter_rules(tsk, &e->rule, ctx, NULL,
- &state, false)) {
- rcu_read_unlock();
- ctx->current_state = state;
- return;
- }
- }
- }
- rcu_read_unlock();
- return;
+ __audit_filter(tsk, ctx, &audit_filter_list[AUDIT_FILTER_EXIT],
+ ctx->major, NULL);
}
/*
@@ -872,17 +879,12 @@ static int audit_filter_inode_name(struct task_struct *tsk,
struct audit_context *ctx) {
int h = audit_hash_ino((u32)n->ino);
struct list_head *list = &audit_inode_hash[h];
- struct audit_entry *e;
- enum audit_state state;
- list_for_each_entry_rcu(e, list, list) {
- if (audit_in_mask(&e->rule, ctx->major) &&
- audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) {
- ctx->current_state = state;
- return 1;
- }
- }
- return 0;
+ /*
+ * We are called holding an rcu read lock. __audit_filter() will take
+ * one as well.
+ */
+ return __audit_filter(tsk, ctx, list, ctx->major, n);
}
/* At syscall exit time, this filter is called if any audit_names have been
--
2.31.1