Skip to content

hostnet: refuse a bind on a port no one listed - #184

Merged
danbugs merged 1 commit into
mainfrom
bind-gate
Oct 22, 2026
Merged

danbugs merged 1 commit into
mainfrom
bind-gate

Conversation

@danbugs

@danbugs danbugs commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

A guest given a network policy and no listen ports could bind any port. Net::allow_bind let every bind through when there was no ListenPorts to ask, while --port's help ("Without this flag or a project's ports, bind() is rejected"), the ListenPorts rustdoc and docs/net.md all promise a guest that cannot serve on a port of its own without one. Found while integrating hyperlight-unikraft guests with urunc (urunc-dev/urunc#1135): hluk run --net with no --port served happily. Targets v0.19.0.

  • hostnet: allow_bind refuses every bind but an ephemeral one (port 0) unless the port is listed, whether the guest means to listen on it or to connect from it (source_address). A guest that serves on a port of its own needs --port, a manifest's ports, or listen_ports, as documented, and can still serve on a port the host picks.
  • Tests: a unit test for the no-ports case, which fails on the old code; the three python integration tests that serve on a fixed port under a bare AllowAll (tcp_bidir, http_server_client, threaded_select) list it, and the datagram rebind test lists the port it binds. tcp_echo and server_shutdown bind port 0 and are unchanged.
  • Conformance: the CPython conformance recipes (bash and pwsh) pass --port all: test_ftplib and test_smtplib bind a source port before connecting and failed under the gate with the bare --net they ran with, and the test host is the boundary there.
  • Docs: net.md states the rule next to the ephemeral exception and no longer calls the default "outbound-only", since a port-0 bind still serves; the --port help and the ListenPorts rustdoc say the same; the smolagents README and executor docstring no longer tie "cannot listen" to net_allow being empty (the executor never passes --port, so the guest cannot listen on a port of its own either way, and hluk_args=["--port", ...] opens one); CHANGELOG entry under Fixed.

Behaviour change for embedders: .network(policy) alone no longer lets the guest listen on a port of its own, or choose its source port; add listen_ports. The integrations (smolagents executor, MCP server, ClickHouse driver) never bind and are unaffected. urunc (urunc-dev/urunc#1135) passes --port=all unless a deployment lists ports.

Testing

Rebased onto main after #180, on Linux/KVM: cargo test --lib, the whole cargo test --test python suite and cargo test --test networking pass; cargo fmt --check and cargo clippy --all-targets --locked -- -D warnings are clean. just conformance python test_ftplib test_smtplib with the branch's release build: both PASS (96 and 82 tests), where they failed under the old recipe. By hand, hluk run --initrd python-rootfs.cpio --net examples/python/http_server_client.py fails to bind with Permission denied and --net --port 9997 serves.

Copilot AI balanced review requested due to automatic review settings October 22, 2026 16:03
@danbugs danbugs added the ci/arm64 Run the arm64 guest tests (self-hosted KVM and HVF runners) label Oct 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused bind-policy change, regression coverage, caller updates, and documentation are consistent, with no unresolved blocking findings.

No open issues 🎉

What changed in this PR

This PR makes host networking enforce the documented bind policy: nonzero ports require an explicit listen-port allowance, while port 0 remains permitted for host-assigned ports.

Changes:

  • Reject unlisted fixed-port binds, including outbound source-port selection, and add regression coverage.
  • Give affected Python tests explicit port permissions and enable all ports in CPython conformance recipes.
  • Align CLI help, API documentation, integration documentation, and release notes with the policy.
File Description
tests/​python.rs Allow the fixed ports used by three server tests.
src/​net_policy.rs Clarify listen-port requirements and the ephemeral-port exception.
src/​hostnet.rs Enforce the bind gate and update unit tests.
src/​cli/​mod.rs Clarify --port help text.
justfile Pass --port all in both conformance recipes.
integrations/​smolagents/​src/​smolagents_hyperlight/​executor.py Correct the executor’s networking docstring.
integrations/​smolagents/​README.md Clarify outbound policy versus fixed-port permissions.
docs/​net.md Document bind rejection and source-port restrictions.
CHANGELOG.md Record the fix and migration guidance for embedders.

Review effort: Balanced

A guest given a network policy and no listen ports could bind any
port: allow_bind let every bind through when there was no ListenPorts
to ask, while --port's help, SandboxBuilder::listen_ports and net.md
promise a guest that cannot. The gate refuses every bind but an
ephemeral one now unless the port is listed, whether the guest means
to listen on it or to connect from it, so a guest that serves on a
port of its own needs --port, as documented, and still serves on one
the host picks. The tests that bound a fixed port under a bare policy
list it, and the CPython conformance recipes pass --port all: those
tests bind as they please, and the test host is the boundary.

Signed-off-by: danbugs <danilochiarlone@gmail.com>
@danbugs
danbugs merged commit 342cd05 into main Oct 22, 2026
152 of 155 checks passed
@danbugs
danbugs deleted the bind-gate branch October 22, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/arm64 Run the arm64 guest tests (self-hosted KVM and HVF runners)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants