diff options
| author | Nuoqi Gui <gnq25@mails.tsinghua.edu.cn> | 2026-06-06 18:50:37 +0800 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-06-06 16:45:25 -0700 |
| commit | 37363191cbe8f83586ad6a818460d010070ead00 (patch) | |
| tree | 56ab69d8bdedde389739ab2e1b4829622f4c9a67 /include/linux/debugobjects.h | |
| parent | 8ddce416797b7454ba1df855821b02c6e43b5a0e (diff) | |
bpf: Fold reg->var_off into PTR_TO_FLOW_KEYS bounds check
Constant pointer arithmetic on a PTR_TO_FLOW_KEYS register lands the
constant in reg->var_off (e.g. flow_keys(imm=4096)), but the
PTR_TO_FLOW_KEYS path in check_mem_access() passes only insn->off to
check_flow_keys_access() and never folds reg->var_off.value. The
verifier therefore accepts an access that, at runtime, dereferences past
struct bpf_flow_keys -- a verifier/runtime divergence that yields an
out-of-bounds read and write of kernel stack memory.
Commit 022ac0750883 ("bpf: use reg->var_off instead of reg->off for
pointers") removed the generic "off += reg->off" that check_mem_access()
applied before the per-type dispatch and replaced it with per-path
folding of reg->var_off.value (for example the ctx path now folds the
register offset via check_ctx_access()). The PTR_TO_FLOW_KEYS path was
not given the equivalent fold, so a constant offset that used to be
folded and rejected is now silently accepted:
before 022ac0750883: the offset stays in reg->off and is folded
generically, so the access is checked with off=4096 and rejected.
after 022ac0750883: the offset lands in reg->var_off, the flow_keys
path checks off=0 and accepts; at runtime the access dereferences
base + 0x1000.
For a BPF_PROG_TYPE_FLOW_DISSECTOR program the following is accepted:
r2 = *(u64 *)(r1 + 144) ; R2=flow_keys (PTR_TO_FLOW_KEYS)
r2 += 0x1000 ; R2=flow_keys(imm=4096), accepted
r0 = *(u64 *)(r2 + 0) ; accepted, var_off.value=0x1000 ignored
while the equivalent insn->off form
r0 = *(u64 *)(r2 + 0x1000)
has the same effective offset but is correctly rejected with
"invalid access to flow keys off=4096 size=8", which isolates the defect
to the missing var_off fold. Once attached as a flow dissector, the
accepted program reads kernel stack past struct bpf_flow_keys (a
kernel-stack / KASLR information leak) and can likewise write past it,
corrupting kernel memory.
Fix it by folding reg->var_off.value into the offset before the bounds
check and rejecting non-constant offsets, mirroring the other pointer
types (e.g. check_ctx_access()).
Fixes: 022ac0750883 ("bpf: use reg->var_off instead of reg->off for pointers")
Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260606-c3-01-v3-v3-1-97c51f592f15@mails.tsinghua.edu.cn
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'include/linux/debugobjects.h')
0 files changed, 0 insertions, 0 deletions
