fix(sandbox): close io_uring and sendmmsg holes in the child network filter

Port of upstream grok-build 9684fa3 (1.0.11 window) `child_net.rs`.

The per-child seccomp filter matched seven socket syscalls by number and
allowed everything else, so a restricted child could still reach the
network through `sendmmsg` or an io_uring submission queue, and a
syscall issued through another arch table (x32 on x86_64) never matched
the deny list at all.

- Gate on the audit arch before matching `nr` and reject x32 numbers on
  x86_64 (foreign-table syscalls now get EPERM instead of passing).
- Add `sendmmsg`, `io_uring_setup`, `io_uring_enter`, `io_uring_register`.
- Build the program once (`prebuilt_child_network_filter`) and hand the
  slice to the `pre_exec` installer; the old code allocated the Vec after
  `fork`, which is not async-signal-safe. All three callers updated.
- Tests evaluate the BPF program over synthetic `seccomp_data`.

Claude-Session: https://claude.ai/code/session_01RUqV8HVGXcAETyYbZ2tPQ4
This commit is contained in:
雷电芽衣 committed 2026-09-13 01:19:36 -04:00
1 parent b957e12370
commit cadc46f5dc
3 files changed
+218 -77

No files matched your search

@@ -912,7 +912,10 @@ fn spawn_with_argv(
if kigi_sandbox::should_restrict_child_network() {
// SAFETY: single prctl syscall (async-signal-safe).
unsafe {
cmd.pre_exec(|| kigi_sandbox::child_net::install_child_network_filter());
let filter = kigi_sandbox::child_net::prebuilt_child_network_filter();
cmd.pre_exec(move || {
kigi_sandbox::child_net::install_child_network_filter(filter)
});
}
}
});