freenode
Kernel & Low-Level

BPF stack limit rises to 2 KiB on x86-64 and arm64

A verifier and JIT series lifts the long-standing 512-byte frame budget for JITed programs while leaving the interpreter and other architectures unchanged.

BPF programs have long been capped at 512 bytes of stack. Kumar Kartikeya Dwivedi has posted a series for bpf-next that raises that budget to 2 KiB for programs JITed on x86-64 and arm64, giving a single function or an entire call chain room to use the full amount, and giving each frame on a private stack the same allowance.

The interpreter, offloaded programs, and JITs that do not opt in stay at 512 bytes. Both the x86-64 and arm64 JITs already encode frame sizes in wide immediates and handle tail calls by popping the caller frame before the target sets up its own, so they do not depend on fixed 512-byte frames. Dwivedi adds a per-program budget that those JITs can claim, with the verifier enforcing it for fixed and variable stack accesses, unprivileged pointer arithmetic, and combined or private stack depth.

The harder work is in the verifier. Its bookkeeping had assumed at most 64 stack slots per frame. Growing every structure fourfold would make all programs pay for deep stacks most never use. The series instead makes liveness masks and related maps grow with the stack a frame actually touches, so only programs that exercise the larger budget incur the cost. Peak verifier memory across thousands of selftests rises only slightly overall, with a few loop-heavy cases growing more.

Tail-call chains need no separate new limit. Callers may still leave at most 256 bytes behind; only the final frame grows to 2 KiB, so worst-case kernel stack use for a long chain moves from roughly 8.5 KiB to about 10 KiB on a typical 16 KiB kernel stack. Unprivileged programs cannot call other BPF functions, so their worst case remains a single frame. Nesting through helpers or attach points is still not charged across levels, though each level may now consume more.

Documentation and selftests are updated so kernels with and without the larger budget run the matching limit checks. The change matters for authors of complex tracing, networking, and struct_ops programs that previously had to split logic or spill to maps to stay under 512 bytes.