Skip to content

feat(net): support the '*' wildcard in --net-allow-bind#137

Merged
congwang-mk merged 1 commit into
mainfrom
feat/net-allow-bind-wildcard
Jul 11, 2026
Merged

feat(net): support the '*' wildcard in --net-allow-bind#137
congwang-mk merged 1 commit into
mainfrom
feat/net-allow-bind-wildcard

Conversation

@congwang-mk

@congwang-mk congwang-mk commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Closes #133.

--net-allow-bind '*' allows the sandbox to bind any TCP port, including an ephemeral bind(0), while the rest of the network policy stays active. Previously the only way to approximate this was --net-allow-bind 0-65535, which installs 65536 individual Landlock rules.

  • Sandbox.net_allow_bind becomes a BindPorts enum (Ports(Vec<u16>) or All); pre-1.0 hard break.
  • Mixing * with port lists is rejected at build time, as is * in --net-deny-bind; repeating the bare wildcard is idempotent. Mutual exclusion with --net-deny-bind is unchanged.
  • Enforcement: All drops LANDLOCK_ACCESS_NET_BIND_TCP from the handled access set (the same mechanism --net-deny-bind already uses), so no per-port rules are installed. Connect-side handling is untouched.
  • C ABI cleanup (pre-1.0 hard break): the per-port entry points sandlock_sandbox_builder_net_allow_bind_port / net_deny_bind_port are removed in favor of spec-string entries sandlock_sandbox_builder_net_allow_bind(spec) / net_deny_bind(spec), matching how net_allow/net_deny already work. Port-spec grammar and the wildcard rule are parsed and validated in one place (the core builder); the Python and Go SDKs forward specs verbatim, and their local port/wildcard parsing (bind_all()/bind_ports()/deny_bind_ports(), Go ParsePorts/HasPortWildcard) is deleted.
  • Wired through every surface: CLI, TOML profiles (allow_bind = ["*"]), the C ABI, the Python SDK (net_allow_bind=["*"]), and the Go SDK (NetAllowBind: []string{"*"}).
  • Tests: parser/exclusivity/Landlock-mask unit tests; kernel-level integration tests (default denies bind with EACCES; wildcard allows fixed-port and port-0 binds; wildcard bind alongside connect enforcement under both the Landlock deny-all and the on-behalf bounded-net_allow enforcers); Python config/profile/end-to-end tests; a Go end-to-end wildcard test.

🤖 Generated with Claude Code

@dzerik

dzerik commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Traced the Landlock path end-to-end — the bind-access semantics are exactly right: All drops only BIND_TCP from the handled mask, CONNECT_TCP and the net_wildcard derivation are untouched, no per-port rules are installed, and the on-behalf bind_deny_ports path stays uninvolved, so --net-allow-bind '*' alone still default-denies outbound TCP. The two mask-contract tests pin this. FFI/Python/Go wiring is faithful and the new spec-string C entry mirrors net_allow/net_deny for error-path ownership. LGTM overall.

A few non-blocking notes:

  1. Doc drift — the old parse_bind_ports docstring ("expand into a sorted, deduplicated port list … Mirrors the Python SDK's parse_ports") is now stacked above parse_allow_bind_ports (sandbox.rs:2350), which returns BindPorts, while parse_bind_ports at :2373 is left undocumented. Worth moving the 3 lines down.
  2. Wildcard predicate is implemented three timesparse_allow_bind_ports, Python bind_all(), Go HasPortWildcard. They agree today, but there's no shared test vector guarding drift; a divergence would let one binding forward a spec another rejects. A single cross-language vector would lock it.
  3. The headline "rest of the network policy stays active" isn't exercised at runtimetest_net_allow_bind_wildcard_permits_any_bind only bind()s on base_policy() (no net_allow), so connect-enforcement-under-* rests entirely on the mask unit test. One case combining .net_allow_bind("*") with a bounded net_allow, asserting a disallowed connect() still fails EACCES beside a succeeding bind, would guard the actual claim.
  4. Parity nit — Go has no end-to-end test for the * path (only HasPortWildcard); Python got a real bind test plus both exclusivity errors.

Nit: --net-allow-bind '*' '*' errors with "cannot be combined with port lists" — a repeated bare wildcard could just be idempotent.

@congwang-mk

congwang-mk commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for your review. I have addressed them and refactored the FFI API together too.

Signed-off-by: Cong Wang <cwang@multikernel.io>
@congwang-mk congwang-mk force-pushed the feat/net-allow-bind-wildcard branch from b405fcd to 68a50a3 Compare July 11, 2026 05:28
@dzerik

dzerik commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Re-read the update — all cleanly addressed, and asserting EACCES rather than tolerating an ECONNREFUSED in the connect test is exactly the right instinct. LGTM, thanks for the fast turnaround.

@congwang-mk congwang-mk merged commit 0098225 into main Jul 11, 2026
13 checks passed
@congwang-mk congwang-mk deleted the feat/net-allow-bind-wildcard branch July 11, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support wildcard in --net-allow-bind

2 participants