Repository navigation
policy_fn: support event category subscriptions - #306
Merged
Merged
Conversation
Any policy_fn trapped every file syscall and turned on ptrace fork tracking plus the execve freeze, even when the callback only cared about connect. PolicyFn::events() now limits delivery to the chosen categories and drops the traps and argv safety machinery that only unsubscribed categories need, so a network-only embedder pays for network supervision alone. ctx.deny_path() returns an error without file events: the path syscalls it relies on are no longer intercepted, and a silent no-op would leave the path reachable. Refs: #290 Signed-off-by: Cong Wang <cwang@multikernel.io>
The C builders take a SANDLOCK_EVENT_* mask and Python's PolicyFn takes
events={"network", ...}, so embedders outside Rust can opt out of the
file traps and execve freezing a network-only callback does not need.
Go passes every category until it grows its own option.
sandlock_ctx_deny_path now returns -1 when file events are not
subscribed, and Python raises instead of silently not denying.
Refs: #290
Signed-off-by: Cong Wang <cwang@multikernel.io>
PolicyFn.Events lets a Go embedder take only network events and skip the file traps and execve freezing the callback would otherwise pay for. DenyPath reports ErrFileEventsRequired instead of claiming success when file events are not delivered. Refs: #290 Signed-off-by: Cong Wang <cwang@multikernel.io>
Explain what a narrower subscription saves, how each binding spells it, and why deny_path() still needs file events. Refs: #290 Signed-off-by: Cong Wang <cwang@multikernel.io>
congwang-mk
force-pushed
the
issue-290-policy-fn-net-events
branch
from
October 21, 2026 01:20
1bd3efd to
ebb7a44
Compare
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.
Closes #290.
Any
policy_fnused to trap every file syscall and turn on ptrace fork tracking plus theexecvefreeze, even when the callback only cared aboutconnect. A callback can now subscribe to event categories, and the sandbox installs only the interception those categories need.API
PolicyFn::new(cb).events(&[SyscallCategory::Network])PolicyFn(cb, events={"network"}); an empty set or unknown name raisesValueErrorPolicyFn.Events: []sandlock.SyscallCategory{sandlock.CategoryNetwork}sandlock_sandbox_builder_policy_fn*builders take aneventsmask ofSANDLOCK_EVENT_*bits (SANDLOCK_EVENT_ALLkeeps every category). This changes the C signature.The default is still all categories, so existing callers and
sandlock learnbehave as before.The categories are now
filesystem,networkandprocess.Fileis renamed toFilesystemeverywhere (SyscallCategory::Filesystem,"filesystem",CategoryFilesystem,SANDLOCK_EVENT_FILESYSTEM, event category0) so it matches the other two names.Memoryis removed: policy_fn never trapped memory syscalls, so subscribing to it did nothing unlessmax_memorywas set, and then every mmap went to a callback that had no action to take on it.What each category costs
filesystemctx.deny_path()gatesnetworkconnect,sendto,sendmsg,sendmmsg,bindprocessexecvetraps, ptrace fork tracking, and theexecvefreezeargv_safety_required, which gates both ptrace mechanisms, is now set only whenprocessis subscribed or anexecvehandler is registered. Events in unsubscribed categories are dropped even when another feature (procfs, COW, chroot) traps the syscall. Syscalls with no category, such as the memory-limit mmap/brk traps orsetpgid, never reach the callback; they used to fall through to a default and get reported as file events.Behaviour notes
ctx.restrict_network()keeps working from any event category.ctx.deny_path()needs filesystem events, because only they keep path syscalls trapped. Without them it fails instead of silently not denying: Rust returnsPolicyFnError::NotSubscribed, Csandlock_ctx_deny_pathreturns-1, Python raisesRuntimeError, Go returnsErrFilesystemEventsRequired.Testing
Ran locally only the tests the change touches, leaving the full suite to CI: Rust
policy_fnunit (21) and integration (32) tests, FFIpolicy_fnand C smoke tests, Pythontest_policy_fn.py(39), and the Go policy tests. New tests check that a network-only callback seesconnectbut no filesystem or process events while the workload opens a file and runs a subprocess, thatdeny_pathfails without filesystem events, that memory-limit syscalls undermax_memorynever reach the callback, that the trap plan dropsmkdirat,unlinkatandexecve, and that the Pythoneventsargument is validated.🤖 Generated with Claude Code