Repository navigation
T135 — The VM host drops a gone host-address box's rules from its gate - #3014
norrietaylor merged 19 commits into
Conversation
The VM host daemon now reads the in-VM daemon's session list on each box event the guest report door sees and every 30 s. A host_ip box the VM no longer runs (reaped, stopped or exited with no client retire) leaves the union the egress gate decides box-marked frames by. A box the VM runs again rejoins with the rules the host client admitted. The guest's list can only narrow the union, never widen it.
|
Important Review skippedBot user detected. To trigger a single review, invoke the
|
|
Approved: no findings at Nothing to do. Clobber: none seen: the removed doc text is replaced by text that describes the new reconcile. |
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 3 conditions · the full ruling
The reconcile conforms to §4.3 rule 2 and §5.5. The gate now decides cohort frames by the live host_ip boxes only. The guest list can only narrow the union. The work that the PR leaves undone has no issue. File an issue for the end-to-end leg and the thread test (C1). Fix or file the stale HostIpResidency::keep comment (C2). Restore an issue link for the restart case (C3).
Ruled at d860695 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
/revise Arch conditions at d860695. The task's layers now carry
|
The thread takes its interval and its session-list read as arguments, so a test covers a nudge, the timer and a failed read that changes nothing. The keep doc in the min CLI now says the reconcile drops a stopped box's rules and a resume restores them. The admit doc links #3015 for the restart case.
New case host_ip_rules_follow_the_running_box. Root in the VM wears the node's address and the box mark at the gate. A host_ip box's rules admit the probe while the box runs. After min box stop, which retires nothing on the host, the gate drops the probe within the reconcile's 30 s timer. After a resume through min session attach, the gate admits it again. The spoofer takes --dscp and --src-port for the probes.
There was a problem hiding this comment.
arch-review: PASS · the full ruling
The change conforms to NET-085. The reconcile drops a box that the VM does not run from the cohort union, as §4.3 rule 2 and §5.5 require. A failed read holds the last state, as §4.3 rule 3 requires. This head adds the reconcile thread test and a hard e2e leg. It also links the restart gap to #3015, and that gap fails closed. No condition is open.
Ruled at 1239cb0 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 VM host, scripts/session-e2e.sh host_ip_rules_follow_the_running_box shows the reach that root in the VM gets through the box mark at the node address. A running host_ip box's rules admit that reach. After min box stop, which retires nothing on the host, the gate drops the same probe within the reconcile's 30 s timer, and the log shows the reconcile's drop line for the box. After a resume, the gate admits the probe again. The case is written but did not run on this box (no /dev/kvm), so the proof is not yet observed end to end. The unit and thread tests pass. Notes from the agent: Revise round 1. All four directive items are done. (1) New e2e case host_ip_rules_follow_the_running_box in scripts/session-e2e.sh. It is wired into the whole-lane order after escapes_and_builds_stay_inside_box_rules, into the direct-call VM case list, into the named-case dispatch and usage, and into the header. The spoofer that the case shares with the escape-union case now takes --dscp and --src-port. Defaults keep the old behaviour. Design: a spoofed SYN from the node address cannot complete, because the switch sends the SYN-ACK to the real guest's MAC. So the case reads the gate's per-SYN debug line 'decided a box-marked frame' (target minvmd::egress_gate::marked) for each probe's source port. It does not use a listener. The stop arm allows 35 s: the 30 s timer plus 5 s for the session-list read and the probe. NOT RUN: this box has no /dev/kvm. The e2e case needs the KVM or macOS VM lane (just e2e). bash -n and shellcheck -S warning are clean. Assumptions the lane will test: a host_ip box with no egress section admits a TCP SYN to 198.51.100.9:443 in the current egress-default phase (the case fails on the running arm and prints min session policy if not), and the in-VM daemon lists a box stopped by min box stop as stopped. (2) host_ip_reconcile_thread_runs_on_nudge_and_timer: spawn_host_ip_reconcile now calls spawn_host_ip_reconcile_with(boxes, interval, reader), so t…[truncated] |
…t-drops-a-gone-host-address-box-s-rule
A reconcile applied a session list that could predate a client admit, so a box created or resumed while the list was in flight lost its rules with nothing set aside. The reconcile now takes an admit mark read before the list and leaves alone every box a client admitted after it.
There was a problem hiding this comment.
arch-review: PASS · the full ruling
This head conforms to NET-085. The new admit mark stops a reconcile from dropping a box on a session list that is older than the box's client admit. The skip lasts one pass and adds no rules, so the guest list still only narrows the union (§4.3 line 88). The merge of main is clean. No conditions are open. Issue #3015 still owns the restart case.
Ruled at 5e114c1 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
There was a problem hiding this comment.
minimal-review — approval withheld
Verdict COMMENT — APPROVE withheld: 3 unresolved threads — minimal-arch[bot] crates/minvmd/src/control.rs:1049, minimal-arch[bot] crates/minvmd/src/box_registry.rs:6085, minimal-foundry[bot] crates/minvmd/src/box_registry.rs:6272. No findings.
Panel: 3 of 3 personas ran (correctness, security, supply-chain).
|
Round 2 of 10 on a failed check suite, pushed as
Verify Review threads the coder judged:
On a VM host, the VM host daemon drops a host_ip box's rules from the gate's union within 30 s after the VM reaps or stops the box with no client asking. Root inside the VM then cannot reach what only that box's rules allowed. A box that a client admits while a session list read is in progress keeps its rules for that pass. Notes from the agent: This round fixes the review thread. The reconcile takes a HostIpAdmitMark that the thread reads before the in-VM session list. A box that a client admitted after the mark survives that pass. host_ip_rules_retired_when_guest_no_longer_runs_box now covers this race. The failed test-kvm check: the job excerpt in the directive shows only the workflow's script text and no failing step, so I could not find the cause. This box has no /dev/kvm, so I did not run scripts/session-e2e.sh (host_ip_rules_follow_the_running_box). |
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 5e114c191c2b 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.
…t-drops-a-gone-host-address-box-s-rule Keep both sides of box_registry.rs: the reconcile types and main's host_ip registration ids. The reconcile now withdraws the registration name of a box the guest no longer lists, as a retire does. A box it set aside as stopped keeps its name, so a stale-name check counts it.
There was a problem hiding this comment.
arch-review: CONDITIONS · 1 condition · the full ruling
The merge of #2861 edits register_host_ip_box_as(). With that edit, a stopped host_ip box keeps its registration name against a new box. The design, architecture.md line 389, says that a name is unique only am
10BC8
ong running boxes, and that a new box may reuse a stopped box's name. A resume runs under the box's own box_id, so it does not need the name entry. Remove the dormant term from that check, and make the new test prove reuse after the bound. That is C1. The rest of the merge conforms, and NET-085 keeps its PASS from 5e114c19.
Ruled at 8fe9469 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
A merge of main before round 3, not counted against the cap (1 of 3), pushed as Resolved conflicts in:
Verify On a VM host, after the VM reaps or stops a host_ip box with no client asking, the reconcile drops that box's rules from the gate's union within 30 s, so root inside the VM can no longer reach what only that box's rules allowed. A resume restores them. This holds at the branch head after the merge with main. Notes from the agent: Conflict round. The one conflict in crates/minvmd/src/box_registry.rs was two independent additions next to each other: this branch's reconcile types and main's HostIpIds/HostIpName. Both sides are kept. Main's merge also added host_ip registration names, so two integration fixes are in the merge commit. First, reconcile_host_ip_boxes now withdraws the registration name of a box the guest no longer lists, the same as retire_host_ip_box does. Second, register_host_ip_box's stale-name check counts a set-aside (stopped) box as admitted, so a stopped box keeps its name for its resume. A new test pins both: host_ip_rules_retired_when_guest_no_longer_runs_box_withdraws_only_an_ended_name. The first test line's filter matches it. cargo clippy -p minvmd --all-targets is clean. I did not run just ci or the e2e script. |
|
/revise Arch at 8fe9469, C1, in |
…t-drops-a-gone-host-address-box-s-rule
|
Round 5 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
On a VM host, when the VM reaps or stops a host_ip box with no client asking, the next reconcile pass (a box event, or at most 30 s) drops that box's rules from the gate's union. A box the guest lists as stopped never keeps its rules for an extra pass. After a resume, the thread runs one more pass after 1 s, so the box gets its rules back as soon as the guest lists it running. Notes from the agent: Round 5. 6d2912a reverts 305615b: the mark is taken after the holds_host_ip_boxes() check and before read_guest(), and the box_registry docs and control.rs tests are back to their 1e445e0 text. 9837596 adds BoxRegistry::host_ip_admitted_after and a follow-up pass in spawn_host_ip_reconcile_with: when a pass drops a box admitted since the previous pass's mark, the thread runs one more pass after HOST_IP_RECONCILE_MIN_GAP. That pass logs trigger=timer. The first pass of the thread has no previous mark, so any drop on it runs a follow-up. That costs one extra read. New tests: host_ip_box_running_again_is_readmitted_after_a_drop_on_a_stopped_list (box_registry) and host_ip_reconcile_thread_runs_again_after_dropping_a_new_admit (control). scripts/session-e2e.sh was not run here: it needs a KVM VM. clippy -p minvmd --all-targets is clean. I did not run just clippy-strict. |
|
/revise One line, in |
A failed session-list read no longer moves the mark of the last pass that read the list, so an admit from before the failed read still gets its follow-up pass.
There was a problem hiding this comment.
arch-review: PASS · the full ruling
This push makes a failed session-list read leave the reconcile mark where the last good read put it. Before, a failed read moved the mark, and a resumed box that the next pass dropped had to wait for the 30 s timer. Section 5.5 line 184 says a resume re-enters by the same path as creation. A failed read still changes no rules, so section 4.3 line 85 (never fail open) holds. The new thread test fails on the old head and passes on this one. The rest of the PR keeps the PASS on 98375967.
Ruled at d0727e6 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 6 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
On a VM host, after the VM reaps or stops a host_ip box with no client asking, root inside the VM can no longer reach what only that box's rules allowed. With this round, a box that a client resumes just before a failed session-list read also rejoins on the follow-up pass, and does not wait for the 30 s timer. Notes from the agent: This round sets |
…t-drops-a-gone-host-address-box-s-rule # Conflicts: # scripts/session-e2e.sh
The reconcile admits a set-aside box again on the guest's word, as a real resume does. Retired rules are never set aside.
There was a problem hiding this comment.
arch-review: PASS · the full ruling
The compare has a merge of main (#3028) and one doc-comment commit. The merge conflict in scripts/session-e2e.sh resolves to keep both e2e legs. The new comment on reconcile_host_ip_boxes agrees with the code. It also agrees with the §4.3 line 88 bound: a guest list selects only within the rules that a host client admitted. NET-085 conforms, as in the PASS on d0727e60.
Ruled at 11ab51b against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
A merge of main before round 7, not counted against the cap (2 of 3), pushed as Resolved conflicts in:
Verify Review threads the coder judged:
On a VM host, when the VM reaps or stops a host_ip box and no client asks, the reconcile removes that box's rules from the gate within 30 s. After that, root inside the VM can no longer reach what only those rules allowed. A resume in the VM brings the rules back. Notes from the agent: The merge with main conflicted in scripts/session-e2e.sh, on one line of the standalone-case list. I kept both host_ip_rules_follow_the_running_box and host_exposures_follow_the_table, and both proofs still dispatch. I did not run the session-e2e case on this box. I changed only the reconcile doc in box_registry.rs. It now says exactly what a guest's session list can bring back. The e2e proof is not run here because it needs a KVM lane. |
|
/revise Comments only. The |
…t-drops-a-gone-host-address-box-s-rule
Root in the VM controls the in-VM daemon's session list. A false running can restore a set-aside box's rules, so the list does not only narrow the union. It moves the union only within the rules host clients admitted.
There was a problem hiding this comment.
arch-review: PASS · the full ruling
This push changes only two comments, and the merge of main is clean. The new comments say a guest's session list moves the host_ip union only within the rules host clients admitted. Section 4.3 line 88 gives that bound to a node-asserted input. The PASS on 11ab51ba stands, and nothing more is necessary.
Ruled at e190a7c against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
There was a problem hiding this comment.
minimal-review — approval withheld
Verdict COMMENT — APPROVE withheld: 8 unresolved threads — minimal-arch[bot] crates/minvmd/src/box_registry.rs, minimal-arch[bot] crates/minvmd/src/box_registry.rs, minimal-arch[bot] crates/minvmd/src/control.rs, minimal-arch[bot] crates/minvmd/src/control.rs, minimal-arch[bot] crates/minvmd/src/box_registry.rs, …. No findings.
Panel: 3 of 3 personas ran (correctness, security, supply-chain).
|
Round 7 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
On a VM host, after the VM reaps or stops a host_ip box with no client asking, root inside the VM can no longer reach what only that box's rules allowed. This round changes no behaviour. The comments in control.rs and on reconcile_host_ip_boxes now state that root in the VM can move the union only within the rules host clients admitted, never past them. Notes from the agent: Comments only, as the /revise note asked. No code changed. The comment at control.rs:865 no longer says the list only narrows the union. The doc on reconcile_host_ip_boxes no longer says a lying guest can never widen egress. Both say that a false running can restore a set-aside box's rules, within the resident set. |
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 e190a7ccaf55 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.
Read at e190a7c. The mark is taken before the read, previous moves only on a good read, a stopped box never keeps its rules, and the comments state the real trust limit. Arch passes.
…t-drops-a-gone-host-address-box-s-rule # Conflicts: # scripts/session-e2e.sh
There was a problem hiding this comment.
arch-review: PASS · the full ruling
The new head is one merge of main and has no branch commit. The one conflict is in scripts/session-e2e.sh, and the resolution keeps both proofs in the case list and in the run order. The reconcile, the dormant set and the reconcile thread do not change. NET-085 conforms to §4.3 line 84 and §5.5 line 183, as on e190a7cc. Residual #3015 stays filed.
Ruled at 0b9d428 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
A merge of main before round 8, not counted against the cap (3 of 3), pushed as Resolved conflicts in:
Verify On a VM host, after the VM reaps or stops a host_ip box with no client asking, the reconcile drops that box's rules from the gate, so root inside the VM can no longer reach what only those rules allowed. The merge with main keeps the host_ip_rules_follow_the_running_box e2e case beside main's new host_stop_stops_boxes_then_daemon_and_vm case. Notes from the agent: Conflict round only. The merge of origin/main conflicted in scripts/session-e2e.sh in two places: the VM-case list and the proof run order. I kept both sides in each place. host_ip_rules_follow_the_running_box runs before main's host_stop_stops_boxes_then_daemon_and_vm proof. bash -n passes on the script. I did not run the e2e script, because it needs a KVM host. The other merged files came from main and merged without conflict. |
There was a problem hiding this comment.
Re-approved at 0b9d428. This head only merges main. The conflict resolution keeps T135's and T28's e2e cases side by side. box_registry.rs is unchanged, and control.rs gains only T140's clear_down from main. CI, arch-review and minimal-review pass, and the host_ip proof printed OK on both VM lanes.
T135 — The VM host drops a gone host-address box's rules from its gate
slice: S16
kind: task
covers: NET-085
size: M
est: 160 code, 160 tests
executor: agent
difficulty: needs care
model: standard
diagnostics: the diagnostics bundle's VM host daemon log carries one line per host-address box the reconcile dropped from or admitted back to the gate's union, naming the box and why
observability: one info line per box the reconcile drops or admits again, with the box, the guest's state for it and the trigger (a box event or the timer)
layers:
- host:
- crates/minvmd/src/box_registry.rs:
reconcile_host_ip_boxesdrops fromhost_ip_boxesevery box the in-VM daemon does not report running, and admits again a box it reports running whose row still holds its rules- crates/minvmd/src/control.rs: runs the reconcile against the in-VM daemon's session list on each box event the guest door sees and every 30 s
test: cargo nextest run -p minvmd host_ip_rules_retired_when_guest_no_longer_runs_box
test: cargo nextest run -p minvmd host_ip_box_running_again_is_readmitted
produces: none
consumes: none
depends on:
- blocked by #2929
proof: On a VM host, after the VM reaps or stops a
host_ipbox with no client asking, root inside the VM can no longer reach what only that box's rules allowed.Proof
On a VM host, a host_ip box that the VM reaps, stops or exits with no client retire leaves the egress gate's union within 30 s, or sooner on the next box event at the guest door. After that, root inside the VM can no longer reach what only that box's rules allowed. A box the VM runs again gets back the rules the host client admitted. The VM host daemon log carries one info line per box dropped or admitted again, with the session, guest_state and trigger.
Notes from the agent: Design: BoxRegistry::reconcile_host_ip_boxes takes the guest's session-to-BoxState map. It treats active, pending and materializing as running. A resident box in any other state leaves the union. If the guest still lists it, its rules are set aside in a new
dormantmap, and they come back when the guest reports it running again. A box the guest does not list is forgotten. A client admit or retire clears the set-aside rules. The guest list can only narrow the union to rules a host client admitted. control.rs starts a reconcile thread beside the guest report door. It reads ListSessions over ssh.sock beside control.sock, the same path the stop flow uses. It runs on a nudge from guest-door box events (mint_box_id, listen_notice, admit_port, withdraw_port) and every 30 s, at most once a second. It does nothing while no host_ip box is held. A failed read changes nothing and logs one warn line until a read succeeds again. Not done: the end-to-end proof (root in the VM, a real reap) is not run here. Only the registry-level tests ran, plus the full minvmd suite once (695 passed). There is no control.rs test that drives the thread against 8000 a fake guest daemon. crates/minimal/src/cmd/boxes/vm_host.rs still has a doc comment (HostIpResidency::keep) that says the rules stay until destroy and cites issue 2747. That file is outside this task's layers, so I did not change it. A follow-up can update it.Tests
cargo nextest run -p minvmd host_ip_rules_retired_when_guest_no_longer_runs_boxcargo nextest run -p minvmd host_ip_box_running_again_is_readmittedVerify
min task run agent-verifypassed ([tasks.verify]).Residuals
host_ipbox gets no egress until a client admits it again.Closes #2944