Linux Security Modules development
 help / color / mirror / Atom feed
From: KP Singh <kpsingh@kernel.org>
To: linux-security-module@vger.kernel.org, bpf@vger.kernel.org
Cc: ast@kernel.org, daniel@iogearbox.net, memxor@gmail.com,
	James.Bottomley@HansenPartnership.com, paul@paul-moore.com,
	KP Singh <kpsingh@kernel.org>
Subject: [PATCH bpf-next 13/13] selftests/bpf: add IPE BPF policy integration tests
Date: Fri, 22 May 2026 04:32:33 +0200	[thread overview]
Message-ID: <20260522023234.3778588-14-kpsingh@kernel.org> (raw)
In-Reply-To: <20260522023234.3778588-1-kpsingh@kernel.org>

Smoke test for the IPE BPF signing properties and ops added in the
preceding patches. The test primes the kernel config with IPE
knobs, writes a boot policy, and boots vmtest.sh to verify that
signed lskels load, unsigned loads are denied, and the policy
audit lines match.

Manual only for now, not wired into the selftests Makefile.

Signed-off-by: KP Singh <kpsingh@kernel.org>
---
 .../selftests/bpf/test_signed_bpf_ipe.sh      | 156 ++++++++++++++++++
 tools/testing/selftests/bpf/vmtest.sh         |   4 +-
 2 files changed, 158 insertions(+), 2 deletions(-)
 create mode 100755 tools/testing/selftests/bpf/test_signed_bpf_ipe.sh

diff --git a/tools/testing/selftests/bpf/test_signed_bpf_ipe.sh b/tools/testing/selftests/bpf/test_signed_bpf_ipe.sh
new file mode 100755
index 000000000000..aaa259ddb917
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_signed_bpf_ipe.sh
@@ -0,0 +1,156 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# IPE BPF policy integration tests.
+
+if [ "${1:-}" = "--in-vm" ]; then
+	set -u
+	fail=0
+	record() {
+		id=$1; verdict=$2; shift 2
+		printf '%s %s %s\n' "$verdict" "$id" "$*"
+		[ "$verdict" = FAIL ] && fail=$((fail + 1))
+		return 0
+	}
+
+	mountpoint -q /sys/kernel/security 2>/dev/null \
+		|| mount -t securityfs none /sys/kernel/security 2>/dev/null || true
+	if [ -d /sys/kernel/security/ipe ]; then
+		record T0 PASS "securityfs/ipe present"
+	elif grep -qw ipe /sys/kernel/security/lsm 2>/dev/null; then
+		record T0 PASS "ipe in /sys/kernel/security/lsm"
+	elif [ -r /sys/module/ipe/parameters/enforce ]; then
+		record T0 PASS "ipe module parameters present"
+	else
+		record T0 FAIL "no sign that IPE LSM is loaded"
+	fi
+
+	if ./test_progs -t atomics 2>&1 | grep -qE '^#[0-9]+[[:space:]]+atomics:OK$'; then
+		record T1 PASS "atomics signed lskel loaded"
+	else
+		record T1 FAIL "atomics signed lskel did not load"
+	fi
+
+	if dmesg | grep -q 'ipe_op=BPF_PROG_LOAD ipe_hook=BPF_PROG_LOAD'; then
+		record T2 PASS "ipe_op=BPF_PROG_LOAD audit line found"
+	else
+		record T2 FAIL "no ipe_op=BPF_PROG_LOAD audit lines in dmesg"
+	fi
+
+	if dmesg | grep 'ipe_op=BPF_PROG_LOAD' \
+		| grep -q 'bpf_signature=UNSIGNED action=DENY'; then
+		record T3 PASS "deny-UNSIGNED rule matched"
+	else
+		record T3 FAIL "deny-UNSIGNED rule never matched"
+	fi
+
+	mountpoint -q /sys/kernel/security 2>/dev/null \
+		|| mount -t securityfs none /sys/kernel/security 2>/dev/null || true
+	content=
+	for d in /sys/kernel/security/ipe/policies/*/; do
+		[ -d "$d" ] || continue
+		if [ -r "$d/policy" ]; then
+			content=$(cat "$d/policy" 2>/dev/null || true)
+			break
+		fi
+	done
+	if [ -z "$content" ]; then
+		record T5 SKIP "could not read /sys/kernel/security/ipe/policies/*/policy"
+	elif echo "$content" | grep -q '^op=BPF_PROG_LOAD_POST_INTEGRITY'; then
+		record T5 PASS "post-integrity rule present in active policy"
+	else
+		record T5 FAIL "active policy does not contain a BPF_PROG_LOAD_POST_INTEGRITY rule"
+	fi
+
+	ENFORCE=/sys/kernel/security/ipe/enforce
+	mountpoint -q /sys/kernel/security 2>/dev/null \
+		|| mount -t securityfs none /sys/kernel/security 2>/dev/null || true
+
+	if [ ! -w "$ENFORCE" ]; then
+		record T4 SKIP "$ENFORCE not writable"
+	elif ! echo 1 > "$ENFORCE" 2>/dev/null; then
+		record T4 SKIP "could not toggle IPE to enforce=1"
+	else
+		out=$(./test_progs -t bind_perm 2>&1 || true)
+		if echo "$out" | grep -q -- '-EACCES\|errno 13'; then
+			record T4 PASS "unsigned load denied with -EACCES under enforce=1"
+		else
+			record T4 FAIL "no -EACCES seen from unsigned load under enforce=1"
+			echo "$out" | tail -10 | sed 's/^/  T4: /'
+		fi
+		echo 0 > "$ENFORCE" 2>/dev/null || true
+	fi
+
+	if [ "$fail" -eq 0 ]; then
+		echo ALL_TESTS_PASSED
+	else
+		echo FAIL_COUNT "$fail"
+	fi
+	exit 0
+fi
+
+set -euo pipefail
+
+SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+KERNEL_DIR=$(cd "$SCRIPT_DIR/../../../.." && pwd)
+VMTEST="$SCRIPT_DIR/vmtest.sh"
+
+POLICY_PATH=${IPE_TEST_POLICY:-/tmp/ipe_bpf_test_policy}
+
+red()   { printf '\033[31m%s\033[0m\n' "$*"; }
+green() { printf '\033[32m%s\033[0m\n' "$*"; }
+bold()  { printf '\033[1m%s\033[0m\n' "$*"; }
+
+bold "=== IPE BPF policy integration tests ==="
+
+tmpfile=$(mktemp -p "$(dirname "$POLICY_PATH")" \
+		  ".$(basename "$POLICY_PATH").XXXXXX")
+cat > "$tmpfile" <<EOF
+policy_name="ipe_bpf_test" policy_version=0.0.1
+op=BPF_PROG_LOAD bpf_signature=OK                action=ALLOW
+op=BPF_PROG_LOAD bpf_signature=UNSIGNED          action=DENY
+op=BPF_PROG_LOAD_POST_INTEGRITY                  action=ALLOW
+DEFAULT op=BPF_PROG_LOAD                         action=ALLOW
+DEFAULT op=BPF_PROG_LOAD_POST_INTEGRITY          action=ALLOW
+DEFAULT action=ALLOW
+EOF
+mv "$tmpfile" "$POLICY_PATH"
+echo "policy written to $POLICY_PATH"
+
+export OUTPUT_DIR=${OUTPUT_DIR:-$HOME/.bpf_selftests_ipe}
+CFG="$OUTPUT_DIR/latest.config"
+mkdir -p "$OUTPUT_DIR"
+if [ ! -f "$CFG" ]; then
+	PLATFORM=$(uname -m)
+	for src in "$KERNEL_DIR/tools/testing/selftests/bpf/config" \
+		   "$KERNEL_DIR/tools/testing/selftests/bpf/config.vm" \
+		   "$KERNEL_DIR/tools/testing/selftests/bpf/config.$PLATFORM"; do
+		[ -f "$src" ] && cat "$src" >> "$CFG"
+	done
+fi
+"$KERNEL_DIR/scripts/config" --file "$CFG" \
+	--enable SECURITY_IPE \
+	--enable IPE_PROP_BPF_SIGNATURE \
+	--set-str IPE_BOOT_POLICY "$POLICY_PATH"
+lsm=$("$KERNEL_DIR/scripts/config" --file "$CFG" --state LSM 2>/dev/null)
+if [ -z "$lsm" ] || [ "$lsm" = "undef" ]; then
+	"$KERNEL_DIR/scripts/config" --file "$CFG" --set-str LSM "bpf,ipe"
+elif ! echo ",${lsm}," | grep -q ',ipe,'; then
+	"$KERNEL_DIR/scripts/config" --file "$CFG" --set-str LSM "${lsm},ipe"
+fi
+touch "$CFG"
+
+RUN_OUT=$(mktemp -t ipe_test_run.XXXXXX)
+trap 'rm -f "$RUN_OUT"' EXIT
+export VMTEST_EXTRA_CMDLINE="ipe.enforce=0 ipe.success_audit=1"
+"$VMTEST" -- ./test_signed_bpf_ipe.sh --in-vm 2>&1 | tee "$RUN_OUT"
+
+if grep -q 'ALL_TESTS_PASSED' "$RUN_OUT"; then
+	green "=== all IPE policy integration tests PASSED ==="
+	grep -E '^(PASS|FAIL|SKIP) T[0-9]+' "$RUN_OUT" || true
+	exit 0
+else
+	red "=== IPE policy integration tests FAILED ==="
+	grep -E '^(PASS|FAIL|SKIP) T[0-9]+' "$RUN_OUT" || true
+	exit 1
+fi
diff --git a/tools/testing/selftests/bpf/vmtest.sh b/tools/testing/selftests/bpf/vmtest.sh
index 2f869daf8a06..b30e2b359413 100755
--- a/tools/testing/selftests/bpf/vmtest.sh
+++ b/tools/testing/selftests/bpf/vmtest.sh
@@ -61,7 +61,7 @@ DEFAULT_COMMAND="./test_progs"
 MOUNT_DIR="mnt"
 LOCAL_ROOTFS_IMAGE=""
 ROOTFS_IMAGE="root.img"
-OUTPUT_DIR="$HOME/.bpf_selftests"
+OUTPUT_DIR="${OUTPUT_DIR:-$HOME/.bpf_selftests}"
 KCONFIG_REL_PATHS=("tools/testing/selftests/bpf/config"
 	"tools/testing/selftests/bpf/config.vm"
 	"tools/testing/selftests/bpf/config.${PLATFORM}")
@@ -294,7 +294,7 @@ EOF
 		-m 4G \
 		-drive file="${rootfs_img}",format=raw,index=1,media=disk,if=virtio,cache=none \
 		-kernel "${kernel_bzimage}" \
-		-append "root=/dev/vda rw console=${QEMU_CONSOLE}"
+		-append "root=/dev/vda rw console=${QEMU_CONSOLE} ${VMTEST_EXTRA_CMDLINE:-}"
 }
 
 copy_logs()
-- 
2.53.0


      parent reply	other threads:[~2026-05-22  2:33 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-22  2:32 [PATCH bpf-next 00/13] Signed BPF + IPE Policies KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 01/13] bpf: expose signature verdict to LSMs via bpf_prog_aux KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 02/13] bpf: include prog BTF in the signed loader signature scope KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 03/13] bpf, libbpf: load prog BTF in the skel_internal loader KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 04/13] bpf: add bpf_loader_verify_metadata kfunc KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 05/13] bpf: compute prog->digest at BPF_PROG_LOAD entry KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 06/13] bpf: resolve loader-style kfunc CALLs against prog BTF KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 07/13] libbpf: generate prog BTF for loader programs KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 08/13] bpftool gen: embed loader prog BTF in the lskel header KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 09/13] lsm: add bpf_prog_load_post_integrity hook KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 10/13] bpf: invoke security_bpf_prog_load_post_integrity from the metadata kfunc KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 11/13] ipe: add BPF program signature properties KP Singh
2026-05-22  2:32 ` [PATCH bpf-next 12/13] ipe: gate post-integrity BPF program loads KP Singh
2026-05-22  2:32 ` KP Singh [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260522023234.3778588-14-kpsingh@kernel.org \
    --to=kpsingh@kernel.org \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=linux-security-module@vger.kernel.org \
    --cc=memxor@gmail.com \
    --cc=paul@paul-moore.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox