From 381581b373329b67187be494118df49e5ec2acca Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 6 Jun 2026 09:49:04 +0300 Subject: test(landlock): cover landlock_add_rule end-to-end (nj0) Extend the existing security-landlock scenario to also exercise landlock_add_rule in-process. After creating the ruleset fd, the scenario builds a struct landlock_path_beneath_attr (allowed_access = LANDLOCK_ACCESS_FS_READ_FILE, parent_fd = open("/", O_PATH)) and calls landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &attr, 0) (syscall nr 445), then closes both fds. landlock_add_rule is unprivileged and has no process-wide side effects (it only builds a ruleset that is never enforced), so it is safe to run in the shared workload process. The call is issued unconditionally even when ruleset creation fails: sys_enter_landlock_add_rule fires before the kernel validates the fd, so the enter tracepoint is captured regardless of whether Landlock is enabled, matching create_ruleset coverage. ret is UNCLASSIFIED (0/-1, not a byte count). TestSecurityLandlockCreateRuleset now adds landlock_add_rule to the trace-arg set and asserts enter_landlock_add_rule MinCount>=1 plus a positive event duration, capturing ruleset_fd at args[0] (KindFd). landlock_restrict_self (ci0) is intentionally NOT covered here: it would require a traced child subprocess, which the integration harness cannot support (it filters by the single workload PID at the BPF layer). Co-Authored-By: Claude Opus 4.8 --- integrationtests/security_test.go | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'integrationtests') diff --git a/integrationtests/security_test.go b/integrationtests/security_test.go index 596c8f6..8d41691 100644 --- a/integrationtests/security_test.go +++ b/integrationtests/security_test.go @@ -62,29 +62,39 @@ func TestSecurityKeysPtracePerf(t *testing.T) { } } -var landlockTraceArgs = []string{"-trace-syscalls", "landlock_create_ruleset,close"} +var landlockTraceArgs = []string{"-trace-syscalls", "landlock_create_ruleset,landlock_add_rule,close"} // TestSecurityLandlockCreateRuleset asserts end-to-end tracing of the -// Security-family landlock_create_ruleset syscall. The security-landlock -// scenario calls landlock_create_ruleset(&attr, sizeof(attr), 0) and closes -// the returned ruleset fd (it deliberately never calls landlock_restrict_self, -// which would irreversibly sandbox the shared test runner). +// Security-family landlock_create_ruleset and landlock_add_rule syscalls. The +// security-landlock scenario calls landlock_create_ruleset(&attr, sizeof(attr), +// 0), adds a PATH_BENEATH rule via landlock_add_rule(ruleset_fd, rule_type, +// &attr, 0), and closes the returned ruleset fd (it deliberately never calls +// landlock_restrict_self, which would irreversibly sandbox the shared test +// runner). // -// The sys_enter tracepoint fires before any ENOSYS/EOPNOTSUPP error, so the -// enter event is observed regardless of whether Landlock is enabled on the -// running kernel; we therefore assert the enter MinCount unconditionally. +// The sys_enter tracepoints fire before any ENOSYS/EOPNOTSUPP error, so both +// enter events are observed regardless of whether Landlock is enabled on the +// running kernel; we therefore assert the enter MinCounts unconditionally. // landlock_create_ruleset is KindEventfd (it captures flags at args[2]); when // the ruleset fd is successfully created and registered, it resolves to the // "landlockfd:" path label, which is also seen on the matching close. +// landlock_add_rule captures ruleset_fd (KindFd) at args[0]; its return value +// (0 or -1) is UNCLASSIFIED, not a byte count. func TestSecurityLandlockCreateRuleset(t *testing.T) { result, _ := runScenarioResultWithIorArgs(t, "security-landlock", []ExpectedEvent{ {Tracepoint: "enter_landlock_create_ruleset", Comm: "ioworkload", MinCount: 1}, + {Tracepoint: "enter_landlock_add_rule", Comm: "ioworkload", MinCount: 1}, }, landlockTraceArgs) - assertEventDurationPositive(t, result, ExpectedEvent{ - Tracepoint: "enter_landlock_create_ruleset", - Comm: "ioworkload", - }) + for _, tracepoint := range []string{ + "enter_landlock_create_ruleset", + "enter_landlock_add_rule", + } { + assertEventDurationPositive(t, result, ExpectedEvent{ + Tracepoint: tracepoint, + Comm: "ioworkload", + }) + } // landlock_create_ruleset may fail (ENOSYS on kernels < 5.13, or // EOPNOTSUPP when the Landlock LSM is disabled). If a tracked ruleset fd -- cgit v1.2.3