Skip to content

fix(sandbox): fall back to drop when the kernel refuses the nft reject rule - #326

Merged
quickbeard merged 1 commit into
mainfrom
firewall-reject-fallback
Aug 25, 2026
Merged

quickbeard merged 1 commit into
mainfrom
firewall-reject-fallback

Conversation

@quickbeard

Copy link
Copy Markdown
Owner

Problem

Starting a Windows sandbox failed with sandbox server exited during startup (code=1 ...) ending in a cryptic nftables error:

/dev/stdin:8:5-33: Error: Could not process rule: No such file or directory
    meta cgroup 1129315998 reject

Observed live 2026-08-25. The failure persists across retries until wsl --shutdown or a reboot, so the sandbox is effectively bricked for the session. (The socat timeout/refused lines that precede it in the UI are the broker-reachability probe legitimately falling back to the reverse bridge — a handled path, not the fatal error.)

Root cause

The egress firewall's final meta cgroup <classid> reject rule is the one piece of the ruleset the kernel loads from a module: Microsoft's WSL kernel has CONFIG_NFT_REJECT=m (nft_reject_inet), while the accept rules use only nf_tables built-ins. When WSL services itself while its utility VM keeps running (Docker Desktop or another distro keeps it alive — here 2.7.11 → 2.7.12 on 2026-08-19), the old package's modules disappear from under the live kernel, module autoload returns ENOENT, and exactly the reject rule fails while both accept rules load. The firewall correctly fails closed, so the boot dies.

Fix

wslFirewallScript now tries the ruleset with reject; if that transaction fails it logs an explanation (naming wsl --shutdown as the cure) and retries with drop, which is nf_tables core and always available. Confinement is identical — blocked connects hang until timeout instead of failing fast — and the sandbox boots. If even the drop ruleset fails, the boot still ends closed, now with an actionable message instead of the raw nft error. A failed nft -f transaction is atomic, so the retry starts from a clean slate.

Validation

  • Ran the generated script under the real guest's /bin/sh (dash, set -u) with a PATH-shimmed nft through all three paths: reject succeeds (no fallback), reject fails (warns, applies drop, boot continues), both fail (exit 1 with guidance).
  • Loaded both the reject and drop rulesets with the real nft against the real WSL kernel.
  • The genuinely stale-modules window is not reproducible without breaking the running VM's system modules mount (autoload runs in WSL init's namespace, so hiding the calling distro's /usr/lib/modules does not trigger it), so the fallback has not been exercised in anger.
  • bun test (33 pass, incl. a new test that the drop fallback keeps the same holes and still fails closed) and bun typecheck from packages/codev-sandbox.

codev-sandbox is fork-only, so no DIVERGENCES.md row; CHANGELOG.md gets a Sandbox entry.

🤖 Generated with Claude Code

…t rule

The egress firewall's final `meta cgroup <classid> reject` rule is the one
piece of the ruleset backed by a loadable kernel module (CONFIG_NFT_REJECT=m;
accept/drop are nf_tables core). When WSL services itself while its utility VM
keeps running, the old package's modules disappear from under the live kernel
and loading nft_reject_inet fails with ENOENT - observed live 2026-08-25 as
"Could not process rule: No such file or directory" on exactly the reject rule
while both accept rules loaded. The firewall failed closed, so every sandbox
start died with that cryptic error until `wsl --shutdown`.

Retry the ruleset with drop when the reject variant fails: confinement is
identical, blocked connects merely hang until timeout instead of failing fast,
and the boot log explains the state and names `wsl --shutdown` as the cure.
If even the drop ruleset fails the boot still ends, now with an actionable
message. A failed `nft -f` transaction is atomic, so the retry starts clean.

Validated in the real guest dash with a PATH-shimmed nft across all three
paths (reject ok / reject fails / both fail), and both rulesets against the
real kernel's nft.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@quickbeard
quickbeard merged commit 8eb8c32 into main Aug 25, 2026
0 of 5 checks passed
@quickbeard
quickbeard deleted the firewall-reject-fallback branch August 25, 2026 06:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant