fix(net): cap child-controlled sockaddr length before reading it#129
Open
dzerik wants to merge 2 commits into
Open
fix(net): cap child-controlled sockaddr length before reading it#129dzerik wants to merge 2 commits into
dzerik wants to merge 2 commits into
Conversation
A sandboxed child can pass an arbitrary sockaddr length on connect/sendto/ sendmsg/sendmmsg (addr_len / msg_namelen are u32, up to 0xFFFFFFFF). The seccomp-notify trap fires at syscall entry, before the kernel's own `addrlen > sizeof(sockaddr_storage)` EINVAL check, so the length reached read_child_mem uncapped and read_child_mem_vm did `vec![0u8; len]` — letting the child force a multi-GiB allocation in the supervisor (OOM, or an alloc-abort of the whole monitor under RLIMIT_AS / overcommit=2 / low RAM) for a sockaddr that is at most 128 bytes. Every other child-controlled read is already bounded (MAX_SEND_BUF 64 MiB, MAX_CONTROL_BUF 16 KiB, iovlen 1024, vlen 256); the sockaddr length was the one gap. Clamp each of the six sockaddr reads to MAX_SOCKADDR_LEN (sizeof(sockaddr_storage) = 128) — the gate only needs the family and address bytes, and the actual send is either re-run by the kernel (Continue) or performed on-behalf with our own correctly-sized sockaddr, so no legitimate call is affected.
A child sends to the allowed and the blocked host with a bogus 4 GiB `addr_len` via raw `libc.sendto`. Without the clamp the supervisor allocated ~4 GiB and could OOM/abort; the test asserts the run completes (the supervisor survives) and that gating still holds on the real address bytes (allowed -> sent, blocked -> ECONNREFUSED) despite the huge claimed length. Verified passing against a system Python (the sandbox suite needs the interpreter stdlib under an fs-read grant).
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
A sandboxed child can force a multi-GiB allocation in the supervisor by passing an oversized sockaddr length.
connect/sendto/sendmsg/sendmmsgtake the address length straight from child-controlled args (addr_len=args[5],msg_namelen, bothu32up to0xFFFFFFFF). The seccomp-notify trap fires at syscall entry, before the kernel's ownaddrlen > sizeof(sockaddr_storage)→EINVALcheck, so the length reachedread_child_memuncapped andread_child_mem_vmdidvec![0u8; len].Repro (any active net interception):
The supervisor allocates ~4 GiB for a sockaddr that is at most 128 bytes. Under default overcommit this is a repeatable transient memory-amplification; under
RLIMIT_AS/overcommit_memory=2/ low RAM the Rust allocation fails andhandle_alloc_erroraborts the whole supervisor — a fail-open crash of the security monitor that takes down every sandbox it runs.Every other child-controlled read is already bounded (
MAX_SEND_BUF64 MiB,MAX_CONTROL_BUF16 KiB, iovlen 1024, vlen 256). The sockaddr length was the one uncapped read.Fix
Clamp each of the six sockaddr reads to
MAX_SOCKADDR_LEN=size_of::<sockaddr_storage>()(128). The gate only needs the family and address bytes, and the actual send is either re-run by the kernel (Continue) or performed on-behalf with our own correctly-sized sockaddr, so no legitimate call (a real sockaddr is ≤ 128 bytes) is affected.Test
cargo buildclean; fullsandlock-corelib suite green (444), including the network tests.Notes
maindirectly since the bug is live there. If refactor(net): restructure the network module into parse/decide/execute phases #128 lands first, the same clamp applies to the splitnetwork/modules (trivial rebase).SO_DOMAIN-gated change acrosssendmsg/sendmmsg/sendtoand is kept out of this focused security fix.