Repository navigation
T124 — Refuse a host-address box with no grant the proxy's address inside the VM - #3052
Conversation
The VM guest's classifier table now carries a bep_lane_leaves set and a proxy_lane chain. A host-address box whose own leaf is not in the set is refused a new TCP connection to the proxy's address, at the listener port or at 443. The cohort lists the own leaf of each member that declares a credentialed upstream, and keeps that member in its own leaf while the cohort blocks UDP 443 (BEP-083).
A root kernel leg loads the table with --proxy-lane, places two host-address members in their own leaves with only one in the lane set, and checks that the other is refused with EHOSTUNREACH, with and without the UDP 443 block. BEP-083 gains the matching sub-requirement, and the interim note on the VM host's gate goes.
|
Important Review skippedBot user detected. To trigger a single review, invoke the
|
Spec lint
Advisory. None of this blocks the merge; the review decides. Advisory, and never a merge gate. Linter: |
|
Approved: every review thread resolved at @norrietaylor resolved the last thread, which releases the approval this review had withheld. Nothing to do. |
There was a problem hiding this comment.
arch-review: CONDITIONS · 2 conditions · the full ruling
The change puts the per-box refusal in the in-VM classifier, where networking §7.1 line 253 and §4.1 line 54 put it. It fails closed. Two proofs are missing. The guest daemon is root and adds a grant box's leaf through run_lane_nft, and no test reaches that path (C1). The kernel leg did not run, and the interim removal in egress_gate.rs depends on it (C2). Make the edit in C1, and record the minimald-root-integration result for C2.
Ruled at cdd82c2 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
/revise Arch CONDITIONS at cdd82c2 (arch_rulings 979), condition C1. The in-VM guest daemon runs as root, and it changes
Run the three T124 test lines and the new test. C2 needs no code. On cdd82c2 the |
run_lane_nft names the table through TABLE_NAME, and a unit test runs it over a recording nft stub for lane-add, lane-remove and a leaf outside the mount (BEP-083).
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The change conforms to networking §7.1. The in-VM classifier refuses the proxy's address to a host_ip box whose own leaf is not in bep_lane_leaves, and only a box with a credentialed upstream on a VM host enters that set. The change fails closed at each step. One gap stays open. On a VM guest, HostMoves::add_blocked_leaf runs sudo -n with a helper that the guest does not have, so a default GitHub grant box cannot launch on host_ip while it blocks UDP 443. The gap exists before this change, but your Mac proof depends on it and no issue tracks it. File the issue as C1 says, and list it in the PR body as a residual.
Ruled at 64ec306 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 1 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
On a Mac, while a GitHub grant box runs with --network host_ip, a second host-address box with no grant cannot connect to the proxy's address, and the grant box still reaches the proxy's listener. This round adds a unit test for the root guest daemon's path. That path puts the grant box's leaf in bep_lane_leaves, so the grant box is not refused at the proxy. Notes from the agent: C1 is done. run_lane_nft now names the table through crate::net::classifier::TABLE_NAME, which is now pub(crate). I also made the cfg(test) helpers recording_nft and nft_calls in classifier.rs pub(crate), so that the host.rs test can use them. The new test is quic443_cohort_tests::root_lane_change_runs_nft_on_the_lane_set. It checks the argv for lane-add and for lane-remove ('delete'). It also checks that a leaf outside the mount gives InvalidInput and that nft is not called. C2 needs no code. On this box the kernel leg skipped, because it runs as uid 1000 and MINIMALD_NETNS_TEST is not set. The minimald-root-integration job must prove it again on the new head. cargo clippy -p minimald --all-targets shows no warnings. |
|
/revise Review finding PRRT_kwDOPdfcxM60L_7z at 64ec306 (
Change nothing else. Keep each commit message line at 100 characters or fewer: commitlint's |
…ost-address-box-with-no-grant-the-prox
run_lane_nft now maps lane-add to add and lane-remove to delete. Any other verb returns InvalidInput and runs no nft, as the sudo helper refuses a verb it does not know (BEP-083).
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The in-VM classifier now refuses the proxy's address to a host-address box with no credentialed upstream, at the listener port and at 443. This is the per-box gate inside the VM that networking §7.1 line 253 assigns to the classifier, and the change conforms to it. The kernel leg that the spec names as the proof did not run on this branch. The guest digest test did not run either. C1 is open until the native lane and the VM lane run them green on this head.
Ruled at d51bbba against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 2 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
On a Mac, while a GitHub grant box runs with --network host_ip, a second host-address box with no grant cannot connect to the proxy's address, and the grant box still reaches the proxy's listener. This round adds that the root daemon's lane set change refuses a verb other than lane-add or lane-remove and runs no nft for it. Notes from the agent: Revise round 2 changed only run_lane_nft and its unit test in crates/minimald/src/box_actor/host.rs. The commitlint failure is on commit 64ec306, which is already on the branch. The rules forbid a rewrite of existing commits or a force-push, so that body line stays at 164 characters and commitlint stays red until a person squashes or rewords it on merge. The new commit d51bbba has every line at 100 characters or fewer. The kernel test only_the_declaring_cohort_member_reaches_the_proxy_address reported a pass, but it printed 'skipping netns proof: MINIMALD_NETNS_TEST not set'. This box is not root, so the kernel leg is not proved here. |
There was a problem hiding this comment.
minimal-review — approved
Verdict APPROVE — every review thread is resolved; @norrietaylor closed the last one. The review of d51bbbafe2a4 withheld this approval on the threads open then. Posted as a comment: the App cannot approve its own pull request; the check and the label carry it.
There was a problem hiding this comment.
Gate passed at d51bbba under the standing gate-4 rule.
T124 — Refuse a host-address box with no grant the proxy's address inside the VM
slice: S17
kind: task
covers: BEP-083
size: L
est: 300 code, 420 tests
executor: agent
difficulty: unknown ground
model: strongest
diagnostics: inside a
host_ipbox with no grant on a Mac, a TCP connect to the proxy's address on its listener port or on 443 fails at once with "No route to host", while ahost_ipgrant box in the same VM connects; the VM's kernel log carries the classifier's rate-limited "minimal-classifier: refused" line for the refused connectobservability: one info line per change of the classifier's proxy-lane set names the box id, its leaf and the lane members, as the UDP 443 set's change line does; the table's existing refusal counter counts each refused connect; the host gate's existing debug line for a cohort frame to the proxy's address still names the declaring members
layers:
- spec:
- docs/specs/24-spec-box-egress-proxy/24-spec-box-egress-proxy.md: BEP-083 gains a sub-requirement that refuses, inside the VM, a resident member that declares no credentialed upstream the proxy's listener and TCP 443, verified by the kernel test below
- table:
- scripts/install-host-classifier.sh: a VM-guest-only
--proxy-lane ADDR:PORTrenders a setbep_lane_leavesof box leaves and an output rule that refuses a new TCP connection from the boxes subtree to ADDR at PORT or 443 unless the socket's leaf is in the set, with the deny chain's counter, log prefix and reject; the helper takeslane-addandlane-removefor that set as it takesaddandremovefor the UDP 443 set- crates/minimald/src/net/classifier.rs:
GuestRendercarries the proxy's listener, andrender_guest_ruleset_overpasses--proxy-lane; the cohort records each member's lane bit, a member that declares a credentialed upstream has its own leaf inbep_lane_leaveswhile resident and stays in its own leaf when the cohort blocks UDP 443, a member that declares none is never listed, andinjection_leafanswers none for a lane member- crates/minimald/src/main.rs: the guest's render names
DEFAULT_SUBNET.box_egress_proxy_address()andPROXY_LISTENER_PORTas the proxy's listener- crates/minvmd/tests/guest_classifier_integration.rs:
native_ruleset_digestpasses the same--proxy-lane, so the guest's loaded table still digests equal to the native rendertest: cargo nextest run -p minimald guest_render_refuses_the_proxy_address_outside_the_lane_set
- cohort:
- crates/minimald/src/box_actor/host.rs:
HostMoveschanges the lane set through the helper's new verbs, andjoin_quic443_cohortpasses the record's lane bit to the cohorttest: cargo nextest run -p minimald lane_less_cohort_member_stays_out_of_the_proxy_lane_set
- kernel:
- crates/minimald/tests/netns_root_integration.rs: a leg that loads the table rendered with
--proxy-laneat a namespace address, places two members in their own leaves with only the first in the lane set, and shows the first's connects to the listener port and to 443 accepted and the second's refused with EHOSTUNREACH, both while the cohort blocks UDP 443 and while it does not- crates/minvmd/src/net/egress_gate.rs: the interim paragraph of
host_ip_verdict's doc comment goes; the gate logic stays as the lane's host halftest: cargo nextest run -p minimald --run-ignored ignored-only only_the_declaring_cohort_member_reaches_the_proxy_address
produces:
- the in-VM refusal of a host-address box with no grant at the proxy's address
consumes:
- the cohort's proxy lane at the host gate
proof: On a Mac, while a GitHub grant box runs with
--network host_ip, a second host-address box with no grant cannot connect to the proxy's address, and the grant box still reaches the proxy's listener.depends on:
- blocked by #2854
Proof
The VM guest's classifier table now refuses a new TCP connection from a host-address box to the proxy's address, at the listener port and at 443, unless that box's own cgroup leaf is in the bep_lane_leaves set. The daemon puts a box's leaf in that set only when the box declares a credentialed upstream on a VM host. So on a Mac, a second host_ip box with no grant gets 'No route to host' at the proxy's address, and the GitHub grant box still connects to the proxy's listener. This branch does not show that on a real Mac: the render and cohort tests pass here, but the kernel leg and the VM path were not run.
Notes from the agent: 1) The kernel leg was not exercised. This box has no root, no sudo, no nft and no cgroup2 mount, and MINIMALD_NETNS_TEST is unset. The test line passed because the leg returned at its gate. The native lane's minimald-root-integration job owes the evidence. The minvmd guest_classifier_integration digest was changed but not run (it needs a VM).
2) The VM guest's daemon runs as root and its image has no sudo and no quic443-leaf helper. So HostMoves runs the helper's lane-add/lane-remove through sudo -n only when the daemon is not root. A root daemon runs
nft add|delete element inet minimal_class bep_lane_leavesitself, with the leaf path below /sys/fs/cgroup. This is a deviation from 'through the helper's new verbs'. The existing UDP 443 blocked-leaves set has the same gap in the guest. It is filed as #3059, listed under Residuals.3) A refused lane-set add logs a warning and the launch continues. The grant box then stays refused at the proxy's address (fails closed). It does not fail the launch, so no new refusal text was added.
4) To keep box_runtime.rs and box_runtime/tests.rs out of the diff, CohortQuic443::admit keeps its signature and is now #[cfg(test)]. The new admit_with_lane carries the lane bit. join_quic443_cohort takes a paths::HostKind, and the lane bit is credentialed_u…[truncated]
Tests
cargo nextest run -p minimald guest_render_refuses_the_proxy_address_outside_the_lane_setcargo nextest run -p minimald lane_less_cohort_member_stays_out_of_the_proxy_lane_setcargo nextest run -p minimald --run-ignored ignored-only only_the_declaring_cohort_member_reaches_the_proxy_addressVerify
min task run agent-verifypassed ([tasks.verify]).Closes #3047
Residuals
sudo -nand a helper that the guest does not have. So ahost_ipbox whose stance blocks UDP 443 fails to launch on a Mac. This predates T124.