refactor(net): restructure the network module into parse/decide/execute phases#128
refactor(net): restructure the network module into parse/decide/execute phases#128congwang-mk wants to merge 8 commits into
Conversation
Signed-off-by: Cong Wang <cwang@multikernel.io>
Signed-off-by: Cong Wang <cwang@multikernel.io>
…y connect and send Signed-off-by: Cong Wang <cwang@multikernel.io>
Signed-off-by: Cong Wang <cwang@multikernel.io>
…ecute phases Signed-off-by: Cong Wang <cwang@multikernel.io>
…rules Signed-off-by: Cong Wang <cwang@multikernel.io>
…odules Signed-off-by: Cong Wang <cwang@multikernel.io>
Signed-off-by: Cong Wang <cwang@multikernel.io>
32139da to
11ad724
Compare
|
@dzerik Please take a look. Thanks |
|
Reviewed with a focus on the send-engine, deferred-send, and TOCTOU-sensitive paths. The refactor itself is faithful; separately, the pass surfaced a few real defects in the underlying send/on-behalf logic (pre-existing in Refactor: behavior-preserving
Making "never decide on re-readable child state" structural rather than a comment is a real improvement. Findings in the underlying logic (worth a follow-up)1. [high] Uncapped child-controlled sockaddr length → multi-GiB supervisor allocation. The address length reaches 2. [high] Asymmetric named-AF_UNIX datagram gating. With a destination policy active and the unix fs-gate off (net-only sandbox, permissive fs), a named 3. [medium] Partial-stream send that can't finish reports total failure after committing bytes. On a blocking stream One behavior delta this PR does introduce
Lower-severity: a relative RecommendationThe refactor is good and can land on its own merits. Given finding #1 is a supervisor-availability issue reachable from inside the sandbox, it's worth a follow-up (or a fold-in here) that caps the sockaddr length and aligns the AF_UNIX datagram path. Happy to take the sockaddr-cap + AF_UNIX symmetry fix. |
|
Follow-up on the two findings from the review, both opened against
When applied, both are trivial rebases onto this refactor's |
Problem
The send-family and connect handlers in
network.rsre-implement kernel syscall semantics against attacker-controlled memory, and the file had grown to 3151 lines with the key invariants enforced only by convention:Continue-under-policy race was exactly a violation of it.msghdrlayout was hand-indexed in five places, the destination policy check was copy-pasted in three, and the 35-line blocking/EAGAIN/defer batch block existed in triplicate. During fix(net): pass through connected AF_UNIX sendmsg under a destination policy #125, every semantic fix had to land three times.Approach
Restructure
network.rsinto anetwork/module organized around three phases, each enforced by a module boundary rather than review discipline:materialize.rs: parse phase. Every byte-level reader of child-controlled memory. Produces owned values (ChildMsghdr,MaterializedMsg) so later phases structurally cannot re-read child state. One typedmsghdrparser replaces the five hand-rolled ones.verdict.rs: decide phase. Pure policy verdicts (destination_verdict) with no I/O and no locks, shared by connect, sendto, and sendmsg. Unit-tested directly.send_engine.rs: execute phase. The only code that performs sends, including the MSG_DONTWAIT-first blocking/defer state machine from fix(net): pass through connected AF_UNIX sendmsg under a destination policy #125. A sharedbatch_send_stepcollapses the triplicated sendmmsg block.connect.rs: the IP connect handler decomposed the same way; the decide phase computes aConnectPlanas data (HTTP-ACL proxy redirect, loopback port remap, or passthrough) via a pure, unit-testedplan_connect_target, and the duplicated v4/v6 bind/getsockname recording collapsed into one helper.unix.rs: the named AF_UNIX gate subsystem shared by connect and send.send.rs: the IP sendto/sendmsg/sendmmsg handlers as thin phase pipelines.rules.rs:--net-allow/--net-denyparsing, DNS resolution, and virtual/etc/hostscomposition, with their tests.mod.rs(138 lines): module docs, socket probes, re-exports, andhandle_netdispatch.Behavior-preserving throughout: moves are verbatim wherever possible, and the two rewrites (connect decomposition, batch step extraction) preserve syscall ordering and errnos. Best reviewed commit by commit; each of the seven commits is a self-contained step with tests passing.
Two deliberate micro-changes, called out for review:
mmsg_entry_named_unix_pathnow copies the full 56-byte msghdr instead of the first 12 bytes (matching what the kernel copies per entry; both versions fail closed), andconnect(2)now passes the materialized sockaddr length rather than the child-suppliedaddr_len, which only differs if the sockaddr read came back short.Test
13 new unit tests that were structurally impossible before the split:
ChildMsghdrparsing (short buffer, connected detection, field extraction),destination_verdict(unrestricted, allowlist match, fail-closed on unparseable port), andplan_connect_target(passthrough, remap, v4 redirect, v4-mapped v6 redirect, v6-proxy fail-closed, remap-never-applies-to-redirect).Full suite green: 457 lib + 284 integration (including the #125 deferred-send and SCM_RIGHTS regression tests) plus the CLI, OCI, and FFI suites, release mode, single-threaded.
🤖 Generated with Claude Code