Fix bpf_loop syzbot report
Subsystems (5)
Kumar Kartikeya Dwivedi
maintainercover Fix bpf_loop syzbot report
Needs Eduard's ack. Fix for the report in
https://lore.kernel.org/bpf/[email protected].
Kumar Kartikeya Dwivedi (2):
bpf: Reject non-scalar bpf_loop iteration counts selftests/bpf: Test pointer bpf_loop iteration count rejection
include/linux/bpf.h | 1 + kernel/bpf/bpf_iter.c | 2 +- kernel/bpf/verifier.c | 1 + .../bpf/progs/verifier_iterating_callbacks.c | 17 +++++++++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-)
base-commit: b75a000f2ac15f4778ddd6d9298d60b24ad776fa
Signature · 1 line
2.53.0
Kumar Kartikeya Dwivedi
maintainerPATCH 1/2 bpf: Reject non-scalar bpf_loop iteration counts
bpf_loop() declares its nr_loops argument as ARG_ANYTHING. Privileged programs may pass pointer values to such arguments, so check_func_arg() lets a pointer-valued R1 reach the helper-specific checks.
Since commit bb124da69c47 ("bpf: keep track of max number of bpf_loop callback iterations"), the verifier marks R1 precise and reads its upper bound to limit callback simulation. Precision backtracking only accepts scalar registers, so passing a pointer instead triggers the "backtracking misuse" verifier warning. Kernels with panic_on_warn enabled subsequently panic.
Introduce ARG_SCALAR for helper arguments that only accept scalar values and use it for bpf_loop() nr_loops. Generic helper argument validation then rejects pointers before loop inlining and precision processing.
--- include/linux/bpf.h | 1 + kernel/bpf/bpf_iter.c | 2 +- kernel/bpf/verifier.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-)
include/linux/bpf.h +1 -0
@@ -894,6 +894,7 @@ enum bpf_arg_type {ARG_PTR_TO_CTX ,/* pointer to context */ ARG_ANYTHING ,/* any (initialized) argument is ok */ +ARG_SCALAR ,/* scalar argument */ ARG_PTR_TO_SPIN_LOCK ,/* pointer to bpf_spin_lock */ ARG_PTR_TO_SOCK_COMMON ,/* pointer to sock_common */ ARG_PTR_TO_SOCKET, /* pointer to bpf_sock (fullsock) */
kernel/bpf/bpf_iter.c +1 -1
@@ -754,7 +754,7 @@ const struct bpf_func_proto bpf_loop_proto = { .func = bpf_loop, .gpl_only = false, .ret_type = RET_INTEGER, - .arg1_type = ARG_ANYTHING, + .arg1_type = ARG_SCALAR, .arg2_type = ARG_PTR_TO_FUNC, .arg3_type = ARG_PTR_TO_STACK_OR_NULL, .arg4_type = ARG_ANYTHING,
kernel/bpf/verifier.c +1 -0
@@ -8211,6 +8211,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_MEM_SIZE] = &scalar_types, [ARG_MEM_SIZE_OR_ZERO] = &scalar_types, [ARG_CONST_ALLOC_SIZE_OR_ZERO] = &scalar_types, + [ARG_SCALAR] = &scalar_types, [ARG_CONST_MAP_PTR] = &const_map_ptr_types, [ARG_PTR_TO_CTX] = &context_types, [ARG_PTR_TO_SOCK_COMMON] = &sock_types,
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH bpf v1 1/2] bpf: Reject non-scalar bpf_loop iteration counts
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing negative bounds checks for enum array indices in memcg BPF kfuncs (bpf_mem_cgroup_memory_events and bpf_mem_cgroup_vm_events). --
commit 3f8d69cede626ae022617ccb30f54b8f41f90edd
Author: Kumar Kartikeya Dwivedi <[email protected]>
bpf: Reject non-scalar bpf_loop iteration counts
This commit fixes a verifier warning and subsequent panic triggered when pointer values are passed to the bpf_loop() nr_loops argument. It introduces ARG_SCALAR to ensure generic helper argument validation rejects pointers before loop inlining and precision processing.
include/linux/bpf.h enum bpf_arg_type { · line 897
Quoted 9 lines
include/linux/bpf.h +1
-0@@ -894,6 +894,7 @@ enum bpf_arg_type {ARG_PTR_TO_CTX ,/* pointer to context */ ARG_ANYTHING ,/* any (initialized) argument is ok */ + ARG_SCALAR, /* scalar argument */
[Severity: High]
This isn't a bug introduced by this patch, but while reviewing the addition of ARG_SCALAR and how the verifier handles scalar arguments, a pre-existing missing bounds check was noticed in the memory cgroup kfuncs.
Could negative enum values passed by untrusted BPF programs cause an out-of-bounds read in the memcg BPF kfuncs?
Looking at mm/bpf_memcontrol.c:bpf_mem_cgroup_memory_events():
if (unlikely(event >= MEMCG_NR_MEMORY_EVENTS)) return (unsigned long)-1; return atomic_long_read(&memcg->memory_events[event]);
And similarly in mm/bpf_memcontrol.c:bpf_mem_cgroup_vm_events(), which exposes validation logic from mm/memcontrol.c:memcg_vm_event_item_valid():
if (idx >= NR_VM_EVENT_ITEMS) return false; return !BAD_STAT_IDX(memcg_events_index(idx));
Because the BPF verifier enforces scalar types but does not validate enum ranges, a BPF program can pass a negative integer as the event parameter. The bounds checks use signed comparisons without a lower bound (< 0) check, so negative values will bypass the validation (e.g., -1 >= 4 evaluates to false).
Can this lead to an out-of-bounds array access on kernel memory when the negative value is used as an index into memcg->memory_events?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Kumar Kartikeya Dwivedi
maintainerRe: [PATCH bpf v1 1/2] bpf: Reject non-scalar bpf_loop iteration counts
Quoted 51 lines · sashiko-bot
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing negative bounds checks for enum array indices in memcg BPF kfuncs (bpf_mem_cgroup_memory_eventsandbpf_mem_cgroup_vm_events). --commit
3f8d69cede626ae022617ccb30f54b8f41f90edd
Author: Kumar Kartikeya Dwivedi <[email protected]>bpf: Reject non-scalar
bpf_loopiteration countsThis commit fixes a verifier warning and subsequent panic triggered when pointer values are passed to the
bpf_loop()nr_loopsargument. It introducesARG_SCALARto ensure generic helper argument validation rejects pointers before loop inlining and precision processing.include/linux/bpf.h enum bpf_arg_type { · line 897
Quoted 9 lines
include/linux/bpf.h +1
-0@@ -894,6 +894,7 @@ enum bpf_arg_type {ARG_PTR_TO_CTX ,/* pointer to context */ ARG_ANYTHING ,/* any (initialized) argument is ok */ + ARG_SCALAR, /* scalar argument */[Severity: High]
This isn't a bug introduced by this patch, but while reviewing the addition ofARG_SCALARand how the verifier handles scalar arguments, a pre-existing missing bounds check was noticed in the memory cgroup kfuncs.Could negative enum values passed by untrusted BPF programs cause an out-of-bounds read in the memcg BPF kfuncs?
Looking at mm/bpf_memcontrol.c:bpf_mem_cgroup_memory_events():
if (unlikely(event >= MEMCG_NR_MEMORY_EVENTS)) return (unsigned long)-1; return atomic_long_read(&memcg->memory_events[event]);And similarly in mm/bpf_memcontrol.c:bpf_mem_cgroup_vm_events(), which exposes validation logic from mm/memcontrol.c:memcg_vm_event_item_valid():
if (idx >= NR_VM_EVENT_ITEMS) return false; return !BAD_STAT_IDX(memcg_events_index(idx));
Quoted 6 lines
Because the BPF verifier enforces scalar types but does not validate enum ranges, a BPF program can pass a negative integer as the event parameter. The bounds checks use signed comparisons without a lower bound (< 0) check, so negative values will bypass the validation (e.g., -1 >= 4 evaluates to false).
My understanding is that since enum values are non-neggative, the enum type is treated unsigned by default. But I think it might make sense to just cast explicitly since Sashiko keeps repeating this concern and it is probably clearer for a reader (I forgot enum values would be unsigned when all enum constants are non-negative myself).
Quoted 2 lines
Can this lead to an out-of-bounds array access on kernel memory when the negative value is used as an index into
memcg->memory_events?
Re: [PATCH bpf v1 1/2] bpf: Reject non-scalar bpf_loop iteration counts
In reply to Kumar Kartikeya DwivediQuoted 15 lines · Kumar Kartikeya Dwivedi
bpf_loop()declares itsnr_loopsargument asARG_ANYTHING. Privileged programs may pass pointer values to such arguments, socheck_func_arg()lets a pointer-valued R1 reach the helper-specific checks.Since commit
bb124da69c47("bpf: keep track of max number ofbpf_loopcallback iterations"), the verifier marks R1 precise and reads its upper bound to limit callback simulation. Precision backtracking only accepts scalar registers, so passing a pointer instead triggers the "backtracking misuse" verifier warning. Kernels withpanic_on_warnenabled subsequently panic.Introduce
ARG_SCALARfor helper arguments that only accept scalar values and use it forbpf_loop()nr_loops. Generic helper argument validation then rejects pointers before loop inlining and precision processing.
Quoted 5 lines
Fixes bb124da69c47 ("bpf: keep track of max number of bpf_loop callback iterations")Reported-by [email protected]Signed-off-by Kumar Kartikeya Dwivedi <[email protected]>---
Looks like there are no other instances of this bug.
Kumar Kartikeya Dwivedi
maintainerPATCH 2/2 selftests/bpf: Test pointer bpf_loop iteration count rejection
In reply to Kumar Kartikeya DwivediAdd a verifier test that leaves the raw tracepoint context pointer in R1 when calling bpf_loop(). This is the smallest trigger for the incorrect precision backtracking: it reuses an existing callback and needs no maps or userspace setup.
Expect an ordinary scalar-type rejection. Without the verifier fix, the test instead reaches precision backtracking and reports an internal "backtracking misuse" error.
--- .../bpf/progs/verifier_iterating_callbacks.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c +17 -0
@@ -168,6 +168,23 @@ static int iter_limit_cb(__u32 idx, struct num_context *ctx)return 0 ; } +SEC("?raw_tp") +__failure __msg("R1 type=ctx expected=scalar") +__naked void bpf_loop_reject_pointer(void) +{ + asmvolatile ( +"r2 = %[iter_limit_cb];" +"r3 = 0;" +"r4 = 0;" +"call %[bpf_loop];" +"exit;" + : + : __imm_ptr(iter_limit_cb), +__imm (bpf_loop) + : __clobber_common + ); +} + SEC("?raw_tp") __successint bpf_loop_iter_limit_ok (void *unused)
Signature · 1 line
2.53.0
Re: [PATCH bpf v1 2/2] selftests/bpf: Test pointer bpf_loop iteration count rejection
Quoted 11 lines · Kumar Kartikeya Dwivedi
Add a verifier test that leaves the raw tracepoint context pointer in R1 when calling
bpf_loop(). This is the smallest trigger for the incorrect precision backtracking: it reuses an existing callback and needs no maps or userspace setup.Expect an ordinary scalar-type rejection. Without the verifier fix, the test instead reaches precision backtracking and reports an internal "backtracking misuse" error.
Signed-off-by Kumar Kartikeya Dwivedi <[email protected]>---
...
tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c static int iter_limit_cb(__u32 idx, struct num_context *ctx) · line 172
Quoted 6 lines
tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c +0
-0@@ -168,6 +168,23 @@ static int iter_limit_cb(__u32 idx, struct num_context *ctx) return 0; }tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c +2
-0+SEC("?raw_tp") +__failure __msg("R1 type=ctx expected=scalar")
I switched to matching new and shiny error messages (:
...
This series was applied to bpf/bpf.git (master) by Eduard Zingerman <[email protected]>:
Hello:
This series was applied to bpf/bpf.git (master)
by Eduard Zingerman <[email protected]>:
Quoted 8 lines · On Sat, 5 Sep 2026 03:47:32 +0200 you wrote:
Needs Eduard's ack. Fix for the report in
https://lore.kernel.org/bpf/[email protected].Kumar Kartikeya Dwivedi (2):
bpf: Reject non-scalarbpf_loopiteration counts selftests/bpf: Test pointerbpf_loopiteration count rejection[...]
Here is the summary with links:
- [bpf,v1,1/2] bpf: Reject non-scalar bpf_loop iteration counts
https://git.kernel.org/bpf/bpf/c/c3fd8e5fd100 - [bpf,v1,2/2] selftests/bpf: Test pointer bpf_loop iteration count rejection https://git.kernel.org/bpf/bpf/c/bde8901ea142
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html