feat(py): the worker's Linux seccomp filter and network block - #362
Draft
jat255 wants to merge 1 commit into
Draft
feat(py): the worker's Linux seccomp filter and network block#362jat255 wants to merge 1 commit into
jat255 wants to merge 1 commit into
Conversation
The part of the worker's boundary a filesystem sandbox cannot express: the syscalls that would let it step out of the sandbox rather than read around it, and, under network="none", the syscalls that open a socket. Both are BPF programs built as ctypes structures and installed with prctl. A seccomp filter matches raw syscall numbers, so the module carries a table per architecture, for the same four the R implementation supports. The numbers were read from each architecture's kernel headers rather than written from memory: they diverge below 425, and two of them disagree where it would be easy to assume otherwise. Two entry points the R filter does not screen are screened here, and kata mv69 tracks closing them there: socketcall on i386, which multiplexes the socket calls behind one number, and pidfd_getfd, which hands over a descriptor belonging to another process of the same user and so returns a capability the filesystem sandbox never granted. Filters carry the calling architecture's tag, so each program confirms that tag before comparing any number, and refuses the call otherwise. An architecture with no table is refused outright rather than filtered against someone else's numbers. seccomp_available() now answers sandbox_capabilities()'s seccomp field, so the construction-time gate makes a real decision on Linux. It finds out whether a filter installs by installing an allow-all one in a child, because a kernel that answers PR_GET_SECCOMP can still refuse PR_SET_SECCOMP, and a gate that missed that would approve a host whose worker then fails to start. The other three mechanisms still report unavailable and belong to their own tasks. Nothing calls engage() yet; the worker that will is task 6. The filter programs are tested by running them through a BPF interpreter, which is how one machine checks all four tables. The Linux tests engage for real in a child, since a filter cannot be lifted. Three of them guard against proving nothing: the unshare and pidfd_getfd tests skip where the host already refuses the call with no filter on, which a container commonly does, and the install probe is checked under a filter that permits PR_GET_SECCOMP while denying PR_SET_SECCOMP. CI gains one arm64 leg, so the aarch64 numbers are exercised and not merely built; kata 9jmj covers the 32-bit tables.
jat255
force-pushed
the
jat255/s87h-seccomp-network-block
branch
from
September 11, 2026 19:48
7ea79c4 to
83c0775
Compare
jat255
changed the base branch from
jat255/t7d4-sandbox-gate-rlimits
to
jat255/tpw5-macos-seatbelt-sandbox
September 11, 2026 19:48
jat255
added this pull request to stack #364
September 11, 2026 19:48
This was referenced Sep 11, 2026
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.
This PR adds the worker's seccomp filter and its
network="none"socket block, built as ctypes BPF programs and installed withprctl. It also fills in theseccompfield of the construction-time gate, so that gate makes a real decision on Linux.Stacked on #355. Nothing calls
engage()yet; the worker that will is task 6.Agent-written detail
The filter matches raw syscall numbers, so
_seccomp.pycarries a table for each of the four architectures the R implementation supports. The numbers came from each architecture's kernel headers rather than from memory: they diverge below 425, andpivot_rootis 217 on i386 but 218 on arm.Two entry points the R filter does not screen are screened here, and kata
mv69tracks closing them there.socketcallreaches every socket operation on i386 behind one number.pidfd_getfdhands over a descriptor belonging to another process of the same user, which is a capability no filesystem sandbox granted; it postdates that C and looks like an omission rather than a decision.x32 is the one ABI reporting a 64-bit machine with 32-bit pointers, and it belongs to neither table, so it gets no entry and such a host is refused rather than handed a filter that would reject its every call. A 32-bit i386 process is not that case: the kernel reports
i686to it.seccomp_available()finds out whether a filter installs by installing an allow-all one in an isolated child, because a kernel that answersPR_GET_SECCOMPcan still refusePR_SET_SECCOMP, and a gate that missed that would approve a host whose worker then fails to start.The tests run the filter programs through a small BPF interpreter, which is how one machine checks all four tables. The Linux ones engage for real in a child, since a filter cannot be lifted, and three of them first check the host does not already refuse the call, so they skip rather than passing hollowly inside a container. Verified under three container profiles: default, unconfined, and one that permits
PR_GET_SECCOMPwhile denyingPR_SET_SECCOMP, where the suite skips cleanly instead of failing.CI gains one arm64 leg, so the aarch64 numbers are exercised rather than merely built. kata
9jmjcovers the 32-bit tables, which need a container job rather than the current uv matrix. katahm25records a separate gap this surfaced: abstract-namespace AF_UNIX sockets are reachable throughsocketpairand no filesystem sandbox governs them, which belongs with the Landlock and userns tasks.