From 43c3d4408e14b9b315783fe77f082393eb3d8c50 Mon Sep 17 00:00:00 2001 From: didericis Date: Thu, 16 Jul 2026 16:09:45 -0400 Subject: [PATCH] fix(firecracker-netpool): per-TAP anti-spoof so source-IP attribution is sound (PR #354 review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /31 point-to-point TAP does NOT make a guest source address unspoofable: root in an agent VM can source another bottle's guest IP on its own bbfc TAP. The isolation table only matched iifname class + port (DNAT) and never bound iifname to its assigned ip saddr — so a spoofed source was DNAT'd to the gateway and attributed to the *victim* bottle, getting the victim's policy/tokens. Source-IP attribution was therefore not actually sound. Add one anti-spoof rule per slot in the isolation forward chain, before the established/DNAT accepts: `iifname bbfcN ip saddr != drop`. Generated in the existing setup loop — no new dependency, ~pool_size lines. Legit traffic (correct saddr) is unchanged; a spoofed saddr on any bbfc TAP is dropped before it can be attributed. Apply with a nixos-rebuild (the systemd unit re-runs this script). Codex review blocker; the app-layer identity token (defense-in-depth) is wired separately. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck --- scripts/firecracker-netpool.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/scripts/firecracker-netpool.sh b/scripts/firecracker-netpool.sh index 2d2ce7c..356947d 100755 --- a/scripts/firecracker-netpool.sh +++ b/scripts/firecracker-netpool.sh @@ -166,6 +166,19 @@ _install_nft() { # Delete-first (create empty, delete, recreate) so a re-applied `up` # lands identical state instead of appending rules / erroring on the # existing base chains — the setup is idempotent regardless of history. + + # Anti-spoof: bind each TAP to its assigned guest IP. The /31 alone + # does NOT make the source address unspoofable — root in an agent VM + # can source another bottle's guest IP on its own bbfc TAP, and the + # gateway attributes egress/policy/tokens by source IP. So drop any + # packet whose source isn't the guest address assigned to the exact + # TAP it arrived on, before it can be attributed. One rule per slot. + local antispoof="" i + for i in $(seq 0 $((POOL_SIZE-1))); do + antispoof="${antispoof} iifname \"$(iface "$i")\" ip saddr != $(guest_ip "$i") drop +" + done + nft -f - <