Repository navigation
fix(sandbox): fall back to drop when the kernel refuses the nft reject rule - #326
Merged
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Starting a Windows sandbox failed with
sandbox server exited during startup (code=1 ...)ending in a cryptic nftables error:Observed live 2026-08-25. The failure persists across retries until
wsl --shutdownor 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> rejectrule is the one piece of the ruleset the kernel loads from a module: Microsoft's WSL kernel hasCONFIG_NFT_REJECT=m(nft_reject_inet), while theacceptrules 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
wslFirewallScriptnow tries the ruleset withreject; if that transaction fails it logs an explanation (namingwsl --shutdownas the cure) and retries withdrop, 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 failednft -ftransaction is atomic, so the retry starts from a clean slate.Validation
/bin/sh(dash,set -u) with a PATH-shimmednftthrough all three paths: reject succeeds (no fallback), reject fails (warns, applies drop, boot continues), both fail (exit 1 with guidance).nftagainst the real WSL kernel./usr/lib/modulesdoes 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) andbun typecheckfrompackages/codev-sandbox.codev-sandboxis fork-only, so no DIVERGENCES.md row; CHANGELOG.md gets a Sandbox entry.🤖 Generated with Claude Code