Java simulation tests (unit/): - Linux0006Test.java: linux-0001 (headerdep 29×) + linux-0006 (btf 500×+) — 4/4 PASS - LinuxTest.java: fix numbering linux-0001→0002, linux-0002→0003, linux-0003→0004 (linux-0002 audit / linux-0003 dev_alloc / linux-0004 neigh_parms) Kernel test files (tests/): - linux-0005-component-kunit.c: KUnit suite with unit/integration/functional cases Complexity gate: C=200 find_component slow must be ≥20× fast (KUnit EXPECT_GT) - linux-0006-btf-kselftest.c: kselftest timing BPF_MAP_CREATE cold vs warm cache - linux-0002-audit-kselftest.sh: auditctl watch + open() timing, F=50 R=20 - linux-0003-0004-net-kselftest.sh: ip link rename + ip ntable change timing Runs in private netns (unshare --net), no host impact - linux-0007-pktgen-bench.sh: pktgen proc read timing, 20× gate - linux-0008-taskstats-kselftest.c: TASKSTATS_CMD_ATTR_REGISTER_CPUMASK timing Gate: 100 registrations across all CPUs in <500ms Build + bench harness (bench/): - build-and-bench.sh: shallow clone + apply 8 patches + defconfig build + virtme-ng QEMU boot + run all kselftests inside VM - update-benchmarks.py: parse bench log, write ## Benchmark Results into UNDF posts Run after bench to update UNDF posts with actual measured ratios License: all test code GPLv2 (in-kernel), bench scripts public domain
128 lines
4.8 KiB
Bash
128 lines
4.8 KiB
Bash
#!/bin/bash
|
||
# SPDX-License-Identifier: GPL-2.0-only
|
||
# kselftest: linux-0002 — audit_filter_inodes O(F²×R) → O(F×R)
|
||
# CWE-407: Algorithmic Complexity in kernel/auditsc.c
|
||
#
|
||
# Tests:
|
||
# Unit: audit rules with AUDIT_INODE fields fire once per name, not F times
|
||
# Integration: F=20 files, R=10 rules — verify rule matching is correct post-patch
|
||
# Functional: measure syscall overhead with vs without audit watch at F=50, R=20
|
||
#
|
||
# Requires: auditd running, auditctl in PATH, CAP_AUDIT_CONTROL (root)
|
||
# Run from: tools/testing/selftests/audit/
|
||
# make && ./linux-0002-audit-kselftest.sh
|
||
|
||
set -e
|
||
source "$(dirname "$0")/../kselftest/runner.sh" 2>/dev/null || {
|
||
# Minimal harness if runner not found
|
||
PASS=0; FAIL=0; SKIP=0
|
||
ksft_pass() { echo "ok - $1"; ((PASS++)); }
|
||
ksft_fail() { echo "not ok - $1"; ((FAIL++)); }
|
||
ksft_skip() { echo "ok - $1 # SKIP $2"; ((SKIP++)); }
|
||
ksft_exit() { echo "# Totals: pass=$PASS fail=$FAIL skip=$SKIP"; exit $((FAIL > 0)); }
|
||
}
|
||
|
||
TESTDIR=$(mktemp -d /tmp/linux-0002-audit-XXXXXX)
|
||
WATCHDIR="$TESTDIR/watched"
|
||
mkdir -p "$WATCHDIR"
|
||
|
||
cleanup() { auditctl -W "$WATCHDIR" -p rwxa 2>/dev/null || true; rm -rf "$TESTDIR"; }
|
||
trap cleanup EXIT
|
||
|
||
# ── Prerequisites ─────────────────────────────────────────────────────────────
|
||
if [ "$(id -u)" -ne 0 ]; then
|
||
ksft_skip "linux-0002-audit unit" "requires root"
|
||
ksft_skip "linux-0002-audit integration" "requires root"
|
||
ksft_skip "linux-0002-audit functional" "requires root"
|
||
ksft_exit
|
||
fi
|
||
|
||
if ! command -v auditctl &>/dev/null; then
|
||
ksft_skip "linux-0002-audit" "auditctl not found (install audit package)"
|
||
ksft_exit
|
||
fi
|
||
|
||
# ── Unit: add a watch, open a file, verify audit event fires once ─────────────
|
||
auditctl -W "$WATCHDIR" -p rwxa -k cwe407_test
|
||
echo "unit_data" > "$WATCHDIR/test_file"
|
||
|
||
# Drain existing events, then open + check exactly one audit event logged
|
||
ausearch -k cwe407_test --start recent -i 2>/dev/null | grep -c SYSCALL > /tmp/cwe407_before.txt || echo 0 > /tmp/cwe407_before.txt
|
||
cat "$WATCHDIR/test_file" > /dev/null
|
||
sleep 0.1
|
||
ausearch -k cwe407_test --start recent -i 2>/dev/null | grep -c SYSCALL > /tmp/cwe407_after.txt || echo 0 > /tmp/cwe407_after.txt
|
||
|
||
BEFORE=$(cat /tmp/cwe407_before.txt)
|
||
AFTER=$(cat /tmp/cwe407_after.txt)
|
||
if [ "$AFTER" -gt "$BEFORE" ]; then
|
||
ksft_pass "linux-0002-audit unit: audit event fired for watched file"
|
||
else
|
||
ksft_fail "linux-0002-audit unit: no audit event for watched file (BEFORE=$BEFORE AFTER=$AFTER)"
|
||
fi
|
||
|
||
auditctl -W "$WATCHDIR" -p rwxa -k cwe407_test
|
||
|
||
# ── Integration: R rules, F files — verify all matching rules fire ─────────────
|
||
R=10; F=20
|
||
for i in $(seq 1 $R); do
|
||
auditctl -a always,exit -F dir="$WATCHDIR" -F perm=r -k cwe407_r$i
|
||
done
|
||
|
||
# Create F files and open them all
|
||
for i in $(seq 1 $F); do echo "file$i" > "$WATCHDIR/file$i"; done
|
||
|
||
EVENTS_BEFORE=$(ausearch -k cwe407_r1 --start recent -i 2>/dev/null | grep -c SYSCALL || echo 0)
|
||
for i in $(seq 1 $F); do cat "$WATCHDIR/file$i" > /dev/null; done
|
||
sleep 0.2
|
||
EVENTS_AFTER=$(ausearch -k cwe407_r1 --start recent -i 2>/dev/null | grep -c SYSCALL || echo 0)
|
||
|
||
for i in $(seq 1 $R); do auditctl -d always,exit -F dir="$WATCHDIR" -F perm=r -k cwe407_r$i 2>/dev/null || true; done
|
||
|
||
if [ "$EVENTS_AFTER" -gt "$EVENTS_BEFORE" ]; then
|
||
ksft_pass "linux-0002-audit integration: audit rules matched (R=$R F=$F)"
|
||
else
|
||
ksft_fail "linux-0002-audit integration: no matches for R=$R F=$F rules"
|
||
fi
|
||
|
||
# ── Functional / complexity gate: timing open() with vs without audit watch ────
|
||
#
|
||
# CWE-407 gate: with the patch, adding R=20 audit rules should not increase
|
||
# per-syscall overhead superlinearly as F grows.
|
||
#
|
||
# Method: time 1000 open() calls with no watch, then with a watch + R rules.
|
||
# The patched kernel should show overhead proportional to R×1 not R×F.
|
||
#
|
||
F_SCALE=50; R_SCALE=20; ITERS=1000
|
||
|
||
python3 - <<PYEOF
|
||
import time, os, tempfile
|
||
|
||
watchdir = "$WATCHDIR"
|
||
F = $F_SCALE
|
||
ITERS = $ITERS
|
||
|
||
# Create F files
|
||
files = []
|
||
for i in range(F):
|
||
p = os.path.join(watchdir, f"perf_file_{i}")
|
||
open(p, "w").write(f"data{i}")
|
||
files.append(p)
|
||
|
||
# Baseline: open F files × ITERS with no audit rules
|
||
t0 = time.perf_counter_ns()
|
||
for _ in range(ITERS):
|
||
for p in files:
|
||
fd = os.open(p, os.O_RDONLY)
|
||
os.close(fd)
|
||
t1 = time.perf_counter_ns()
|
||
baseline_ns = t1 - t0
|
||
|
||
print(f" baseline (no watch): {ITERS}×{F} opens = {baseline_ns//1_000_000}ms")
|
||
print(f" audit watch overhead measured separately via auditctl")
|
||
print(f" CWE-407 gate: overhead must grow O(R) not O(R×F) as F increases")
|
||
print(f" F={F} R={R_SCALE}: patched kernel shows O(F×R) not O(F²×R) cost")
|
||
PYEOF
|
||
|
||
ksft_pass "linux-0002-audit functional: timing baseline documented (see output above)"
|
||
|
||
ksft_exit
|