This fixes a verifier argument-size overflow in global BPF subprogram
calls.
For global subprogram generic pointer arguments, the verifier derives the
pointee size from program BTF and stores it as u32. That value is later
passed to check_mem_reg(), which feeds a signed int access-size path. For
stack pointers, the value is negated to mark the call-site validation path
where STACK_POISON is allowed.
That conversion is unsafe for BTF-resolved sizes above INT_MAX. A type
such as int[0x3fffffff] resolves to 0xfffffffc bytes. On the vulnerable
stack path, (int)0xfffffffc becomes -4, and the negation validates only a
four-byte stack object. The callee is still verified with the original
large memory size, so the caller/callee memory contract is inconsistent.
I confirmed the issue with a non-executing raw-BTF verifier reproducer. On
a vulnerable kernel, the verifier accepted a program with:
- caller object: a four-byte stack slot
- BTF callee argument: int[0x3fffffff]
- resolved BTF size: 0xfffffffc
- accepted callee access: *(u32 *)(r1 + 4)
The relevant vulnerable verifier log contained:
R1=mem_or_null(id=1,sz=0xfffffffc)
r0 = *(u32 *)(r1 +4)
The program was only loaded to prove verifier acceptance. It was not
attached or executed.
The fix rejects sizes that cannot be represented by the signed verifier
access-size API before any conversion, and adds a verifier regression test
that expects:
R1 memory size 4294967292 is too large
Security and reachability:
This is reachable from BPF-loadable contexts that can supply program BTF
and BPF-to-BPF global subprogram calls: direct CAP_BPF or CAP_SYS_ADMIN
callers, explicit BPF token delegation, or privileged BPF loader services
that accept user-controlled BPF objects. The delegated-loader case is
relevant to bpfman/bpfd-style deployments where an API/RBAC boundary can
ask a privileged daemon to perform the BTF and program load. The issue is
not reachable by ordinary unprivileged users on systems where unprivileged
BPF is disabled.
Validation performed:
- vulnerable QEMU guest: raw-BTF reproducer accepted
- patched QEMU guest: raw-BTF reproducer rejected the oversized size
- git diff --check
- scripts/checkpatch.pl --strict
- git apply --check on a clean tree
- clean worktree object build:
kernel/bpf/verifier.o kernel/bpf/btf.o
- git send-email --dry-run
Full BPF selftests were not run in this environment because clang is not
installed.
Taegu Ha (1):
bpf: reject overlarge global subprog argument sizes
kernel/bpf/verifier.c | 7 ++++++-
.../bpf/progs/verifier_global_subprogs.c | 17 +++++++++++++++++
2 files changed, 23 insertions(+), 1 deletion(-)
--
2.43.0