1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Network policy enforcement via seccomp notification: connect/sendto/
// sendmsg/sendmmsg are intercepted and either passed through, denied, or
// performed on-behalf against a copy of the child's arguments.
//
// The module is organized around three phases, each enforced by a boundary:
//
// materialize parse phase: every byte-level reader of child-controlled
// memory; produces owned values (ChildMsghdr, MaterializedMsg)
// so later phases never re-read child state (TOCTOU-safe).
// verdict decide phase: pure policy verdicts over materialized values;
// no I/O, no locks, unit-testable.
// send_engine execute phase: the only code that performs sends, including
// the blocking/defer state machine for the notification loop.
//
// The per-syscall handlers chain those phases:
//
// connect IP connect (verdict + HTTP-ACL redirect / port-remap plan).
// send IP sendto/sendmsg/sendmmsg.
// unix the named AF_UNIX gate shared by connect and send.
// rules --net-allow/--net-deny parsing, DNS resolution, /etc/hosts.
//
// This file keeps the socket probes and the handle_net dispatch.
use RawFd;
use Arc;
use crateSupervisorCtx;
use crate;
use crateSeccompNotif;
pub
// `network` is pub(crate), so this re-export is the crate-internal path for
// the rule types. The two resolved-set types are named only in re-exported
// signatures (callers bind them by inference), which trips unused_imports.
pub use ;
use connect_on_behalf;
use ;
/// Largest sockaddr length we copy from the child when gating a `connect`/
/// `sendto`/`sendmsg` destination. The seccomp-notify trap fires at syscall
/// entry, *before* the kernel's own `addrlen > sizeof(sockaddr_storage)`
/// (`EINVAL`) check, so a child can pass `addr_len`/`msg_namelen` up to
/// `u32::MAX`. Reading that verbatim into `vec![0u8; len]` would let the child
/// force a multi-GiB supervisor allocation (OOM / alloc-abort of the monitor)
/// for an address that is at most this many bytes. Every legitimate sockaddr
/// fits in `sizeof(sockaddr_storage)`, so a larger length is rejected before the
/// read (see [`read_sockaddr`]).
const MAX_SOCKADDR_LEN: usize = ;
/// Copy a sockaddr from child memory, rejecting an oversized length *before* the
/// allocation. `len` is child-controlled (`addr_len` / `msg_namelen`, a `u32`),
/// and the trap fires before the kernel's `addrlen > sizeof(sockaddr_storage)`
/// check, so an uncapped read would let the child force a multi-GiB supervisor
/// allocation. A length larger than a `sockaddr_storage` cannot address a valid
/// sockaddr, so it fails closed with `EINVAL` (matching what the kernel would
/// return) rather than being silently truncated; a read fault maps to `EIO`.
pub
// ============================================================
// query_socket_protocol — derive the rule Protocol from a fd via getsockopt
// ============================================================
/// Query `SO_PROTOCOL` on a dup'd socket fd to learn whether to route
/// the on-behalf check through the TCP, UDP, or ICMP policy.
///
/// Returns `None` for protocols sandlock does not gate via `net_allow`
/// (raw, SCTP, etc.) — the handler treats those as "no rule applies"
/// which collapses to the default-deny path.
pub
/// True iff `fd` is an `AF_UNIX` socket, probed via `SO_DOMAIN`. `SCM_RIGHTS`
/// and `SCM_CREDENTIALS` are unix-only, so control rewriting/gating is applied
/// only to unix sockets — an IP socket's control (e.g. `IP_PKTINFO`) carries no
/// fds or credentials and passes through untouched.
// ============================================================
// handle_net — main handler for connect/sendto/sendmsg
// ============================================================
/// Handle network-related notifications (connect, sendto, sendmsg).
///
/// All three are handled on-behalf (TOCTOU-safe): the supervisor copies data
/// from child memory, validates the destination, duplicates the socket via
/// pidfd_getfd, and performs the syscall itself. The child's memory is never
/// re-read by the kernel after validation.
///
/// Continue safety (issue #27): the on-behalf paths don't return Continue
/// at all (they return ReturnValue/Errno after performing the syscall in
/// the supervisor). The Continue cases in this module are:
/// 1. Non-IP families (AF_UNIX etc.) — the IP allowlist doesn't apply;
/// Landlock IPC scoping is the enforcement boundary.
/// 2. Connected sockets with addr_ptr == 0 — the address was already
/// validated at connect time, so the kernel re-read of (nothing) is
/// moot.
/// 3. The fall-through case below — only reachable if the BPF filter
/// mis-routes a syscall; the kernel handles it normally.
/// In sendmsg_on_behalf, the msghdr read failure path returns
/// Errno(EFAULT) rather than Continue: a racing thread that briefly
/// unmaps the msghdr could otherwise force a fall-through that lets the
/// kernel execute sendmsg without the allowlist check. Sub-buffer read
/// failures (sockaddr/iovec/control) already return Errno(EIO) and so
/// don't bypass the check either.
pub async