[PATCH 3/3] audit: unify audit_filter_{uring(), inode_name(), syscall()}

Ankur Arora ankur.a.arora at oracle.com
Tue Sep 27 22:59:44 UTC 2022


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 at oracle.com>
---
 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



More information about the Linux-audit mailing list