Skip to contentSkip to conversation

Fix bpf_loop syzbot report

PATCH Applied Kumar Kartikeya Dwivedi 4 participants 8 messages Sep 5 – Sep 6

Subsystems (5)
Kselftest BPF BPF selftests BPF core +1 more subsystems
lore
Share & tools
lore

Kumar Kartikeya Dwivedi

author maintainer
#0 lore raw

cover 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
author maintainer
#1 lore raw

PATCH 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.

Fixes bb124da69c47 ("bpf: keep track of max number of bpf_loop callback iterations")
Reported-by [email protected]
---
 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
index b7dbf3d9b5c0..e57af902560c 100644
@@ -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
index 14a5fdfa0421..b40eb404adab 100644
@@ -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
index 1c3039f3fc32..4638a2f85d0f 100644
@@ -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
#2 lore raw

Re: [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
index 3a7eb2185c354..591dfab3e706c 100644
@@ -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
author maintainer
#3 lore raw

Re: [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_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
index 3a7eb2185c354..591dfab3e706c 100644
@@ -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));
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?

maintainer Acked-by on v1 1/2
#4 lore raw

Re: [PATCH bpf v1 1/2] bpf: Reject non-scalar bpf_loop iteration counts

In reply to Kumar Kartikeya Dwivedi
Quoted 15 lines · Kumar Kartikeya Dwivedi

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.

Quoted 5 lines
Fixes bb124da69c47 ("bpf: keep track of max number of bpf_loop callback iterations")
Reported-by [email protected]

---

Looks like there are no other instances of this bug.

author maintainer
#5 lore raw

PATCH 2/2 selftests/bpf: Test pointer bpf_loop iteration count rejection

In reply to 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.

---
 .../bpf/progs/verifier_iterating_callbacks.c    | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
tools/testing/selftests/bpf/progs/verifier_iterating_callbacks.c +17 -0
index 75dd922e4e9f..1fbcc5228306 100644
@@ -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)
+{
+	asm volatile (
+		"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")
 __success
 int bpf_loop_iter_limit_ok(void *unused)
Signature · 1 line
2.53.0
maintainer Acked-by on v1 2/2
#6 lore raw

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.

---

...

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 (:

...

#7 lore raw
In reply to Kumar Kartikeya Dwivedi
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-scalar bpf_loop iteration counts selftests/bpf: Test pointer bpf_loop iteration 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