fix(enforce): wire ardur run to actually invoke the seccomp shim (#104)#129
Draft
gnanirahulnutakki wants to merge 1 commit into
Draft
fix(enforce): wire ardur run to actually invoke the seccomp shim (#104)#129gnanirahulnutakki wants to merge 1 commit into
gnanirahulnutakki wants to merge 1 commit into
Conversation
Closes the false-success bug: on a seccomp-only host (the majority — no "bpf" in the boot lsm= list), apply_policy could report "applied_seccomp_tier" while run_bridge never invoked ardur-exec-shim or checked the daemon's advertised tier, so nothing actually wrapped the agent. ardur run now detects the active tier before spawning the agent and, when it's seccomp, launches through ardur-exec-shim; under --enforce, if the tier can't actually be wired (shim missing, or its listener never attaches — confirmed via a new session_status field), the run aborts loudly instead of reporting success. Two more bugs surfaced only by running the real shim through the real CLI, not by any unit test: a startup race where the shim's one-shot daemon handoff could lose to register_session (fixed with a file-based readiness handshake — a daemon round-trip doesn't work here since session_status enforces exact-PID peer ownership, and a signal-based handshake risks killing the shim if it arrives before the handler is installed); and every mission's default cwd-based file resource_scope making a mission un-enforceable on the seccomp tier regardless of its network scope, since that tier only ever covers OP_NET_CONNECT (fixed with an opt-in --no-resource-scope flag for network-only missions). Adds a real ardur run --enforce full-flow e2e for both tiers: a new CI job builds the enforce-e2e demo image and runs it against a seccomp-only host (--disable-bpf-lsm), and the existing BPF-LSM virtme-ng smoke test now also runs the full CLI flow, not just the piecewise guard-smoke tool. Both assert the denied syscall actually fails and the hash-chained receipt + attestation verify offline — the exact test class that would have caught this.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #104 — Epic A #63. Fixes the false-success bug the holistic integration review found: on a seccomp-only host (no
bpfin the bootlsm=list — the majority case, per E4/#103's own rationale),ardur run --enforcecould report kernel policy as applied while nothing actually wrapped the agent.The false-success path (before this fix)
run_bridge.pynever inspected the daemon's advertisedenforcement_tier, and never invokedardur-exec-shim(feat(enforce): seccomp user-notify enforcement tier (E4) #103's seccomp on-ramp) under any circumstance.apply_policycould genuinely returnstatus="applied_seccomp_tier"(the daemon's in-memory seccomp policy store synced correctly) for a mission whose policy happened to be fully seccomp-coverable._apply_kernel_policytreated any non-exceptionapply_policyresponse asapplied=True— with no process ever wrapped in a seccomp filter, no syscall was ever actually trapped or enforced.--enforcewould report success for a run that enforced nothing.The fix
run_governednow calls the daemon'shealthmethod before launching the agent. When the active tier isseccomp, it resolvesardur-exec-shim(kernel_correlation.exec_shim_path()—PATH, then the systemd-packaged install location) and wraps the launch command with it, so the filter actually installs on the agent before it execs.SeccompListenerAttachedfield onsession_status(Go:daemon.seccompListenerAttached, populated from the existingseccompListenersmap) lets the launcher confirm a listener is genuinely supervising the session — not just that the tier is theoretically active or thatapply_policysynced its store._apply_kernel_policynow polls this after a seccomp-tier apply succeeds; if the shim was never resolved or its listener never attaches, the result downgrades toapplied=False, and under--enforcethe run aborts loudly (KernelPolicyEnforcementError) instead of reporting success.Two more bugs, found only by running the real shim through the real CLI (not by any unit test)
register_sessioncall, which runs concurrently. Fixed with a file-based readiness handshake: the launcher creates a marker file right afterregister_sessionsucceeds; the shim waits for it before attempting the handoff. Two alternatives were tried and rejected first — a daemon round-trip (session_statusenforces exact-PID peer ownership, so the shim, a different process than the launcher, can never pass it) and a signal-based handshake (a signal arriving before the handler is installed would kill the shim outright, since most signals default to terminate — a race with a fatal failure mode, not just a slow one).run_governedalways attaches a cwd-based fileresource_scope(OP_FILE_READ/OP_FILE_WRITE) regardless of mission content, but the seccomp tier's "fully covered" gate (seccompFullyCoversPolicy, from feat(enforce): seccomp user-notify enforcement tier (E4) #103) requires every op to beOP_NET_CONNECT— so no real mission could ever reachapplied_seccomp_tierthrough the CLI, only through hand-constructed test policies. Added an opt-in--no-resource-scopeflag (andrun_governed(no_resource_scope=...)) for missions that are genuinely network-only.Real end-to-end verification (not just unit tests)
Directly exercised the real Go daemon + real
ardur-exec-shim+ realardur runCLI in a privileged Linux container (--disable-bpf-lsmto force the seccomp tier regardless of the host kernel's own LSM list):ardur run --forbidden-tools fetch --no-resource-scope --enforceon a seccomp-only host: the agent'sconnect()gets a genuine kernelEPERM, the hash-chainedenforce_events.jsonlreceipt reflects the denial, and the attestation'skernel_enforcement.chain_digestverifies offline (enforce-verify, no kernel/daemon/root needed).ECONNREFUSED, not blocked), logged but not denied.KernelPolicyEnforcementErrorunder--enforceagainst the real daemon.run.shdemo still passes unmodified — no regression on that tier.CI
New job
ardur-run-e2e-seccomp(required, no VM needed — confirmed empirically that the seccomp install syscall needs no special kernel boot): builds thedocs/demo/enforce-e2eDocker image and runs the newrun-seccomp.shin bothenforceandpermissivemode, asserting the EPERM/receipt/attestation chain described above. This is the exact test class that would have caught #104 — piecewiseardur-seccomp-smokedrives the shim directly and would never have caughtrun_bridge.pyfailing to invoke it at all.The existing
kernel-smokejob (virtme-ng, BPF-LSM tier) now also runs the fullardur run --enforceCLI viarun.sh, not just the piecewiseardur-guard-smoketool — this specific step is unverified against live GitHub-hosted virtme-ng as of this PR (I have no way to test virtme-ng locally); it inheritskernel-smoke's existingcontinue-on-error: truesoft-gate for exactly this reason, the same positionkernel-smokeitself started from before its own multi-round-trip burn-in.Testing
SeccompListenerAttachedtests (daemon-level, session_status/health scoping);go build/go vet/go test -race ./...green on darwin + Linux.exec_shim_path/seccomp_handoff_socket_pathresolution,_plan_seccomp_shimtier detection,_wrap_command_with_seccomp_shimargv shape,_verify_seccomp_listener_attached(true/timeout/unreachable), and fullrun_governedintegration tests for the success path, both abort paths, and the permissive degrade — all against a real daemon protocol (mocked socket, not the CLI). Full suite (1206 tests, including a realbiscuit-pythoninstall) green.Ref: #104, #63