Skip to content

tests: enforce the runtime adapter's networks in VMs - #883

Open
Enrique Saurez (esaurez) wants to merge 2 commits into
esaurez/822-pr10-guest-network-settings-20261023from
esaurez/822-pr11-network-enforcement-vms-20261023
Open

Enrique Saurez (esaurez) wants to merge 2 commits into
esaurez/822-pr10-guest-network-settings-20261023from
esaurez/822-pr11-network-enforcement-vms-20261023

Conversation

@esaurez

@esaurez Enrique Saurez (esaurez) commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #882; this PR retargets when its parent merges.

Chain: #863 → #867 → #869 → #865 → #864 → #872 → #875 → #878 → #862 → #868 → #870 → #866 → #882 → #883 (this PR).

Part of #822: PR 11 of 11, enforcement in VMs (C4).

What changed

Tests only, in tests/vm_layered.rs, with the adapter's README. The layered scenarios check what each kind of network lets the guest's executions reach, on NVX's Ubuntu EROFS image over a scratch, as NVX's proxy-only scenario (scripts/nvx_tools/sandbox_proxy_tests.py) probes its network:

  • a_denied_network_lets_no_probe_through: a network that lets nothing through, which attaches no network device, and in which an execution reaches neither the test proxy nor any destination;
  • an_allow_rule_lets_only_its_destination_through: egress denied but for one rule, TCP to a port of host loopback at the gateway, which alone arrives;
  • a_proxy_only_network_lets_only_its_proxy_through: an execution reaches the test proxy through the URL in its environment, while the other destinations never arrive;
  • outbound_host_loopback_publishes_no_listener: outbound host-loopback access, through which an execution reaches host loopback, while the host does not reach the guest's listener, which OpenVMM does not publish;
  • allowed_host_loopback_publishes_the_listeners: host-loopback access allowed, with egress denied, through which the host reaches the guest's listener at the guest's port of host loopback, while an execution reaches nothing;
  • a_forward_reaches_its_guest_port: the host reaches the guest's listener through a forward of a port of host loopback.

How:

  • Before the launch, the test binds the host's side of the network, Host, whose ports the network names, each drawn at random from the dynamic range and free on every host address and on loopback: a test proxy on host IPv4 loopback, which the guest reaches at the same port of its gateway, and the sockets of the probes' destinations: another port of host loopback over TCP, the proxy's port over UDP, and the proxy's port over TCP at the host's own address and on host IPv6 loopback, where the host has them. Scenarios run at the same time, so each Host holds the ports that it drew until its scenario ends, or for good if the scenario fails, and draws none that another holds: OpenVMM binds the ports of a listener and of a forward only once it runs, and again for the scenario's VM after the positive control's.
  • A scenario whose network stops traffic first boots the positive control, Expect::Controlled: a VM of an open network over the same host's side, in which every probe arrives and the host reaches a listener of the guest. The host then discards what is left at its sockets, and the scenario's own VM runs the same checks, so that what does not arrive there shows the network's policy, not a broken probe. The control's VM is staged, launched, and checked as every scenario's: the table applied, its mappings counted, and the sandbox started.
  • Each VM with a network first has its network devices checked, and that OpenVMM asks /init on the kernel command line to publish the guest's listeners exactly where the root configuration says that they are published.
  • The scenarios' guest is at 192.0.2.2/24, in a range reserved for documentation, so that no host's own address is on its network; the proxy-only network's proxy is the test proxy, at a port of its own.

Validation

  • vm_layered (43 scenarios: runtime adapter: run cold sandboxes end to end on KVM, MSHV and WHP #822's and runtime adapter: settle executions through cgroups and run them in a VM #805's 35, tests: give the runtime adapter's executions their network's settings #882's 2, and these 6), vm_restart (3), and vm_steps (3) on WHP (local) and MSHV (Linux x86_64, as root).
  • Windows (local), in tests/runtime-adapter: cargo fmt --all --check; the protocol-only and host-only configurations' cargo clippy --locked --all-targets [--features host] -- -D warnings, cargo build --locked, cargo test --locked, and cargo +1.89 check --locked --all-targets.
  • Linux (x86_64), in tests/runtime-adapter: the same, plus the guest-only configuration (--features guest --target x86_64-unknown-linux-musl): clippy, build, tests, and the MSRV check; the guest-only library and guest_session tests as root; and a stress run of guest_session, 10 times as root and 10 times as a user, and of the library's tests, 3 times as root.
  • python scripts/check_markdown_links.py.
  • Left to CI: everything, once this PR targets dev, KVM's VM tests included; a stacked PR runs no NVX CI.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The test-only changes have no identified blocking issues and check network behavior using positive controls and host-side observations.

No open issues 🎉

What changed in this PR

Adds VM-level network enforcement tests for the runtime adapter, completing the network validation portion of #822 on top of #882’s execution settings.

Changes:

  • Adds six scenarios covering denied traffic, allow rules, proxy-only access, host-loopback access, and port forwarding.
  • Uses open-network positive controls and host-side traffic checks to distinguish policy enforcement from broken probes.
  • Documents the scenarios, dynamic port selection, and listener-publication checks.
File Description
tests/​runtime-adapter/​tests/​vm_layered.rs Adds network scenarios, host socket fixtures, traffic probes, and listener checks.
tests/​runtime-adapter/​README.md Documents network enforcement coverage and the test setup.

Review effort: Balanced

The layered scenarios check what each kind of network lets the guest's
executions reach, as NVX's proxy-only scenario probes its network: a
network that denies everything, which attaches no network device; an
allow rule; a proxy-only network, whose other destinations never
arrive; outbound host-loopback access, which publishes no listener of
the guest; and host-loopback access in both directions, through which
the host reaches a listener of the guest, at its port or through a
forward.

Before the launch, the test binds the host's side of the network, whose
ports the network names, each drawn at random from the dynamic range: a
test proxy on host loopback, and the sockets of the probes'
destinations. A scenario whose network stops traffic first boots a VM
of an open network over the same sockets, the positive control, in
which every probe arrives and the host reaches the guest's listener.
Each VM with a network has its network devices checked, and that
OpenVMM asks /init to publish the guest's listeners exactly where the
root configuration says that they are published.

The scenarios' guest moves to 192.0.2.2/24, in a range reserved for
documentation, so that no host's own address is on its network, and the
proxy-only network's proxy is the test proxy, at a port of its own.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a7c15634-094a-4a66-af59-25a58e732f4b

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Parallel network scenarios can select the same unreserved ports, causing intermittent launch or listener-publication failures.

1 open issue

Review effort: Balanced

Comment thread tests/runtime-adapter/tests/vm_layered.rs
The VM scenarios run at the same time. The host's side of a network
draws the ports of a listener of the guest and of a forward, then
releases them, since OpenVMM binds them only once it runs, and again for
the scenario's VM after the positive control's. Another scenario could
draw the same ports in between, and one of the two VMs would then fail
to bind them.

Each host's side now holds the ports that it drew, in a set that the
scenarios share, until its scenario ends, and draws none that another
holds. A scenario that ends confirmed that its VMs ended; one that fails
keeps its ports for good, since one of its VMs might still run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a7c15634-094a-4a66-af59-25a58e732f4b

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No unresolved blocking issues remain in the test and documentation changes; VM validation was not independently rerun.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

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.

2 participants