feat(sandbox): opt-in to AF_NETLINK socket creation via env var#1006
feat(sandbox): opt-in to AF_NETLINK socket creation via env var#1006alessandro-festa wants to merge 1 commit into
Conversation
Adds OPENSHELL_ALLOW_NETLINK_ENUMERATE (default off) so deployments that ship Node.js / Go / Python tooling inside the sandbox can let it call getifaddrs(3) — Node's `os.networkInterfaces()`, Go's `net.Interfaces()`, Python's `socket.if_nameindex()` all open AF_NETLINK sockets and currently fail with EPERM under the supervisor's seccomp filter, surfacing as opaque "Unknown system error 1" stack traces from libuv and friends. The default behavior is unchanged: AF_NETLINK socket creation stays in the seccomp denylist. Setting the env var to "1" / "true" / "yes" drops exactly that one rule. AF_PACKET, AF_BLUETOOTH and AF_VSOCK remain blocked unconditionally. Once the AF_NETLINK socket is created the process can issue any RTM_* netlink message; this is a coarse opt-in. A finer-grained policy that filters at the netlink message level would need an LSM/eBPF hook and is out of scope. Tests: - existing build_filter compile tests updated to the new (allow_inet, allow_netlink) signature - new tests cover the default-deny path, the opt-in path, and the rule-count delta between them
|
Thank you for your interest in contributing to OpenShell, @alessandro-festa. This project uses a vouch system for first-time contributors. Before submitting a pull request, you need to be vouched by a maintainer. To get vouched:
See CONTRIBUTING.md for details. |
|
Thank you for your submission! We ask that you sign our Developer Certificate of Origin before we can accept your contribution. You can sign the DCO by adding a comment below using this text: I have read the DCO document and I hereby sign the DCO. You can retrigger this bot by commenting recheck in this Pull Request. Posted by the DCO Assistant Lite bot. |
|
I have read the DCO document and I hereby sign the DCO. |
|
can we please re-open it? |
|
My opinion on this is that this seccomp rule is not providing value; historical kernel vulnerabilities in this space were more tied to user namespaces and netlink. But that said, I think unprivileged netlink is pretty heavily fuzzed nowadays too. So I'd say just allow by default. (Also I am of the opinion that more generally the additional seccomp/landlock stuff on top of the default container runtime security should all be opt-in, but that's a much bigger discussion) |
Summary
Adds
OPENSHELL_ALLOW_NETLINK_ENUMERATE(default off) so deployments that run Node.js / Go / Python tooling inside the sandbox can let it callgetifaddrs(3). Today this fails withEPERMunder the supervisor's seccomp filter and surfaces as opaque "Unknown system error 1" stack traces from libuv (Node'sos.networkInterfaces()), Go'snet.Interfaces(), Python'ssocket.if_nameindex(), etc.The default behavior is unchanged:
AF_NETLINKstays in the seccomp denylist. Setting the env var to1/true/yesdrops exactly that one rule.AF_PACKET,AF_BLUETOOTH, andAF_VSOCKremain blocked unconditionally.Related Issue
No upstream issue filed yet — happy to file one and link if preferred. Hit while building a sandboxed Node.js agent (the
openclawCLI fromOpenShell-Community/sandboxes/openclaw) inside an OpenShell sandbox:pickPrimaryLanIPv4callsos.networkInterfaces()→uv_interface_addresses→getifaddrs(3)→socket(AF_NETLINK, ...)→EPERM, which the agent doesn't tolerate.Changes
crates/openshell-sandbox/src/sandbox/linux/seccomp.rs:apply()readsOPENSHELL_ALLOW_NETLINK_ENUMERATEfrom env (case-insensitive1/true/yes)build_filter/build_filter_rulestake a newallow_netlink: boolparameterallow_netlinkistrue,AF_NETLINKis left out of the socket-domain denylist; otherwise behavior is identical to todaybuild_filter_*_compilestests updated to the new signaturebuild_filter_netlink_allowed_compilescovers the opt-in pathnetlink_blocked_by_defaultverifies the default-deny still installs aSYS_socketrulenetlink_allowed_drops_one_socket_ruleverifies the opt-in drops exactly one socket-domain ruleCaveats
This is a coarse opt-in: once the
AF_NETLINKsocket is created the process can issue anyRTM_*message (route table, neighbor table, etc.). A finer-grained policy that filters at the netlink message level would need an LSM/eBPF hook and is out of scope here. The use case it unblocks (interface enumeration for self-presence detection) is common enough in real-world Node/Go/Python codebases that an explicit opt-in seems worth the trade-off.If you'd prefer this as a per-policy field (
SandboxPolicy.network.allow_netlink) instead of an env var, happy to refactor — went with env var for the smallest diff and to avoid a proto bump.Testing
cargo build -p openshell-sandbox(host: macOS arm64) cleancargo build -p openshell-sandbox --releaseviaDockerfile.imagessupervisortarget — multi-arch (linux/amd64 + linux/arm64) succeedsos.networkInterfaces()succeeds withOPENSHELL_ALLOW_NETLINK_ENUMERATE=true, fails with EPERM otherwise (will validate in the smoke test today and update this checkbox)Checklist