Repository navigation
Install the Unix-socket filter through prctl so it works under the service's own unit (v0.55.1) - #199
Merged
Merged
Conversation
…rvice's own unit (v0.55.1) v0.55.0 passed every test and failed on its first real run: the service unit's SystemCallFilter does not allow the seccomp(2) syscall (systemd keeps it in @sandbox), so installing the filter answered operation not permitted, nmap failed closed and the nightly audit died. The filter is now installed with prctl(PR_SET_SECCOMP), which the unit allows, on a thread the runner pins and execs from. A test that refuses seccomp(2) before installing reproduced the exact error and now passes. The failure message names sandboxing.unix_sockets as the way to run without the filter. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…dening A confinement change has to be tried where the service really runs: a container or CI runner has no copy of the unit's SystemCallFilter, which is how the Unix-socket filter passed every test and still failed on vertex. The script builds its systemd-run properties from the installed unit (or the repo template when none is installed), runs a small python probe as the service user, and prints whether the filter installs by seccomp(2) and by prctl and what it refuses. The probe's own logic was checked in the Docker VM, plain and with seccomp(2) refused first. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
📊 Test coverage and CRAP scoresBackend (Go)Go coverageTotal: 81.0% Packages below 50% (statement coverage)Frontend (Vitest)Total: 86.83% statements, 83.56% branches, 86.05% functions, 87.66% lines CRAP scoresReport only. Scores above 30 are flagged; lower is better. Go4764 functions scored; 55 above 30; highest score 870.00. Highest 10 flagged functions:
Missing coverage is scored as 0%. Full reports are in the TypeScript1833 functions scored; 8 above 30; highest score 146.29. Highest 8 flagged functions:
Missing coverage is scored as 0%. Full reports are in the Full coverage and CRAP reports in the artifacts of this workflow run |
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.
What broke
v0.55.0 (#198) shipped broken. On vertex the nightly audit failed with
nmap failed: exit status 1: sandbox-runner: unix socket denial failed: seccomp: install the unix socket filter: operation not permitted.The runner failing closed did its job (nmap never ran unconfined), but every jailed child goes through the same runner, so agent terminal commands and automations that use the shell were failing too, not only the audit.
Cause
The filter was installed with the
seccomp(2)syscall. The service's unit allowsSystemCallFilter=@system-service landlock_create_ruleset landlock_add_rule landlock_restrict_self, and systemd keepsseccomp(2)in@sandbox, which the unit does not list, so under the real unit it answers EPERM. No test environment had that filter (CI runners, and a Docker VM on the production kernel), so everything was green. I called the Ubuntu CI jobs "the amd64 evidence"; that was the wrong gate for this kind of change.Fix
prctl(PR_SET_SECCOMP), which the unit allows, on a thread the runner pins and execs from (Landlock is per-thread too, so the pin helps it as well). The failure message now namessandboxing.unix_sockets: trueas the way to run without the filter.TestUnixSocketDeny_InstallsUnderTheServiceUnitsOwnSyscallFilterrefusesseccomp(2)before installing, as the unit does. It reproduced the exact vertex error before the fix and passes after it. It stands in for the one syscall known to differ; it is not the whole unit.scripts/check-sandbox-under-unit.sh(+scripts/sandbox-probe.py) is the deploy gate: it builds itssystemd-runproperties from the installed unit, runs a probe as the service user, and prints whether the filter installs byseccomp(2)and byprctl, and what it refuses. Pitfall 68 and the setup notes say to run it before deploying any sandbox change. The probe's own logic was checked in the Docker VM, plain and withseccomp(2)refused first (old routeEPERM, new route ok).Not verified
Nothing here has run under vertex's real unit. Do not deploy before running the probe on vertex (
sudo scripts/check-sandbox-under-unit.sh): ifprctlis also refused there, this explanation is wrong and the narrowest alternative is addingseccompto the unit'sSystemCallFilternext to the three Landlock calls, which is a unit change for the owner to decide.Restoring vertex right now (before this is deployed)
Turn on Settings → Security → "Let programs use Unix sockets", or set
sandboxing.unix_sockets: truein/var/lib/llm-proxy/settings.yml, thensudo systemctl restart llm-proxy. Turn it back off once the fix is confirmed, or the protection stays off unnoticed.Checked
Backend build, vet, full tests,
-raceon the sandbox and progexec packages, complexity gate and harness pass; the sandbox tests, including the conformance test, pass on a real kernel (6.8, arm64) in a Docker VM.🤖 Generated with Claude Code