All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next v1 00/14] Follow ups for verifier errors set
@ 2026-08-16  1:57 Kumar Kartikeya Dwivedi
  2026-08-16  1:57 ` [PATCH bpf-next v1 01/14] bpf: Correct verifier diagnostic attribution for stack reads Kumar Kartikeya Dwivedi
                   ` (13 more replies)
  0 siblings, 14 replies; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

Some follow up changes based on comments from Eduard, Sashiko, and BPF
CI Bot. See commits for details.

Kumar Kartikeya Dwivedi (14):
  bpf: Correct verifier diagnostic attribution for stack reads
  selftests/bpf: Test verifier stack-read diagnostic attribution
  bpf: Preserve R0 lineage across helper calls
  bpf: Drop dead spill diagnostic condition
  bpf: Use canonical stack argument names in diagnostics
  bpf: Correct kfunc argument diagnostics
  selftests/bpf: Test kfunc argument diagnostics
  bpf: Report non-sleepable kfunc programs accurately
  selftests/bpf: Test non-sleepable kfunc context
  bpf: Correct Program Structure diagnostic context
  bpf: Preserve source attribution without source text
  selftests/bpf: Test Program Structure diagnostic context
  bpf: Distinguish function references in policy diagnostics
  selftests/bpf: Test pseudo-function policy diagnostics

 kernel/bpf/btf.c                              |   8 +-
 kernel/bpf/cfg.c                              |   6 +-
 kernel/bpf/diagnostics.c                      |  21 +-
 kernel/bpf/verifier.c                         | 180 ++++++++++++------
 .../testing/selftests/bpf/progs/dynptr_fail.c |   5 +
 tools/testing/selftests/bpf/progs/irq.c       |  13 ++
 .../selftests/bpf/progs/iters_state_safety.c  |   3 +
 .../selftests/bpf/progs/preempt_lock.c        |  15 ++
 .../bpf/progs/refcounted_kptr_fail.c          |   9 +
 .../selftests/bpf/progs/verifier_cfg.c        |  40 ++++
 .../selftests/bpf/progs/verifier_gotox.c      |   2 +
 .../selftests/bpf/progs/verifier_loops1.c     |   1 +
 .../selftests/bpf/progs/verifier_unpriv.c     |  18 ++
 .../selftests/bpf/progs/verifier_xadd.c       |  27 +++
 14 files changed, 275 insertions(+), 73 deletions(-)


base-commit: c93cbdb13f995f87b5356329b3fe551c80bb482d
-- 
2.53.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 01/14] bpf: Correct verifier diagnostic attribution for stack reads
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  6:34   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 02/14] selftests/bpf: Test verifier stack-read diagnostic attribution Kumar Kartikeya Dwivedi
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Sashiko, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

Verifier memory diagnostics currently label every fixed-offset stack
read rejected by check_stack_read_fixed_off() as uninitialized. Dynptr,
iterator, and IRQ-flag slots instead contain initialized verifier-managed
state, so the report incorrectly suggests initialization or CAP_PERFMON.

The variable-offset read without a destination register is reached by
atomic read-modify-write instructions, but its diagnostic attributes the
access to a helper.

Classify rejected stack reads by slot type. Retain the existing
uninitialized report for STACK_INVALID, and describe verifier-managed
slots as opaque state. Describe the variable-offset read as an atomic
operation while leaving the existing verifier messages unchanged.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://lore.kernel.org/bpf/20260815065956.49D2B1F000E9@smtp.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/verifier.c | 63 ++++++++++++++++++++++++++++++-------------
 1 file changed, 45 insertions(+), 18 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index d17f14b35b79..5d0a2d3ef594 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3817,19 +3817,46 @@ static int mark_reg_stack_read(struct bpf_verifier_env *env,
 	return 0;
 }
 
-static void bpf_diag_stack_read_uninit(struct bpf_verifier_env *env, int off, int i,
-				       int size)
+static void bpf_diag_stack_read_invalid(struct bpf_verifier_env *env, int off, int i, int size,
+					enum bpf_stack_slot_type type)
 {
-	const char *reason;
+	const char *problem, *reason, *suggestion, *kind;
+
+	if (type == STACK_INVALID) {
+		reason = bpf_diag_fmt(
+			env, "This rejected read uses %d bytes at stack offset %d, but byte %d in that range is uninitialized on this path. "
+			"Programs loaded with CAP_PERFMON can be allowed to read uninitialized stack bytes, but this program is being rejected without that allowance.",
+			size, off, i);
+		bpf_diag_memory(
+			env, env->insn_idx, "uninitialized stack read", reason,
+			"Initialize every byte in the stack range before reading it, adjust the offset and size so the read covers only initialized bytes, "
+			"or load with CAP_PERFMON if uninitialized stack reads are intended.");
+		return;
+	}
 
-	reason = bpf_diag_fmt(env,
-			      "This rejected read uses %d bytes at stack offset %d, but byte %d in that range is uninitialized on this path. "
-		"Programs loaded with CAP_PERFMON can be allowed to read uninitialized stack bytes, but this program is being rejected without that allowance.",
-		size, off, i);
-	bpf_diag_memory(
-		env, env->insn_idx, "uninitialized stack read", reason,
-		"Initialize every byte in the stack range before reading it, adjust the offset and size so the read covers only initialized bytes, "
-		"or load with CAP_PERFMON if uninitialized stack reads are intended.");
+	switch (type) {
+	case STACK_DYNPTR:
+		kind = "dynptr";
+		suggestion = "Use dynptr helpers or kfuncs to access the object represented by the dynptr instead of reading the dynptr state directly.";
+		break;
+	case STACK_ITER:
+		kind = "iterator";
+		suggestion = "Use iterator kfuncs to advance or destroy the iterator instead of reading its state directly.";
+		break;
+	case STACK_IRQ_FLAG:
+		kind = "IRQ flag";
+		suggestion = "Pass the saved IRQ flag to the matching restore kfunc instead of reading its state directly.";
+		break;
+	default:
+		return;
+	}
+
+	problem = bpf_diag_fmt(env, "direct read of %s stack state", kind);
+	reason = bpf_diag_fmt(
+		env, "This rejected read uses %d bytes at stack offset %d, but byte %d in that range belongs to verifier-managed %s state. "
+		"This state has an opaque representation that BPF programs cannot read directly.",
+		size, off, i, kind);
+	bpf_diag_memory(env, env->insn_idx, problem, reason, suggestion);
 }
 
 /* Read the stack at 'off' and put the results into the register indicated by
@@ -3921,7 +3948,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
 					} else {
 						verbose(env, "invalid read from stack off %d+%d size %d\n",
 							off, i, size);
-						bpf_diag_stack_read_uninit(env, off, i, size);
+						bpf_diag_stack_read_invalid(env, off, i, size, type);
 					}
 					return -EACCES;
 				}
@@ -3980,7 +4007,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
 			} else {
 				verbose(env, "invalid read from stack off %d+%d size %d\n",
 					off, i, size);
-				bpf_diag_stack_read_uninit(env, off, i, size);
+				bpf_diag_stack_read_invalid(env, off, i, size, type);
 			}
 			return -EACCES;
 		}
@@ -4079,13 +4106,13 @@ static int check_stack_read(struct bpf_verifier_env *env,
 		tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
 		verbose(env, "variable offset stack pointer cannot be passed into helper function; var_off=%s off=%d size=%d\n",
 			tn_buf, off, size);
-		reason = bpf_diag_fmt(env,
-				      "The helper would access the stack through variable offset %s plus fixed offset %d and size %d. "
-			"Helper stack memory arguments require a constant stack offset and a precise initialized range.",
+		reason = bpf_diag_fmt(
+			env, "The atomic operation would access the stack through variable offset %s plus fixed offset %d and size %d. "
+			"Atomic stack operations require a constant stack offset and a precise initialized range.",
 			tn_buf, off, size);
 		bpf_diag_memory(
-			env, env->insn_idx, "variable stack access", reason,
-			"Use a fixed stack offset for helper memory arguments, or copy the needed bytes into a fixed stack slot first.");
+			env, env->insn_idx, "variable-offset atomic stack access", reason,
+			"Use a fixed stack offset for the atomic operation, selecting the target stack slot on separate control-flow paths if necessary.");
 		return -EACCES;
 	}
 	/* Variable offset is prohibited for unprivileged mode for simplicity
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 02/14] selftests/bpf: Test verifier stack-read diagnostic attribution
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
  2026-08-16  1:57 ` [PATCH bpf-next v1 01/14] bpf: Correct verifier diagnostic attribution for stack reads Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  2:45   ` bot+bpf-ci
  2026-08-16  6:35   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 03/14] bpf: Preserve R0 lineage across helper calls Kumar Kartikeya Dwivedi
                   ` (11 subsequent siblings)
  13 siblings, 2 replies; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

Verifier diagnostics distinguish uninitialized stack bytes from opaque
dynptr, iterator, and IRQ-flag state, and identify variable-offset atomic
stack accesses without changing the existing verbose messages.

Add output assertions to the existing dynptr and iterator rejection
cases. Add a direct IRQ-flag read and a variable-offset atomic stack
access to cover the other classifications. Retain an assertion for the
legacy helper-worded verbose message in the atomic test.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 .../testing/selftests/bpf/progs/dynptr_fail.c |  3 +++
 tools/testing/selftests/bpf/progs/irq.c       | 13 +++++++++
 .../selftests/bpf/progs/iters_state_safety.c  |  3 +++
 .../selftests/bpf/progs/verifier_xadd.c       | 27 +++++++++++++++++++
 4 files changed, 46 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
index beaa73dc35f5..72aa6b5a877b 100644
--- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
@@ -560,6 +560,9 @@ int global(void *ctx)
 /* A direct read should fail */
 SEC("?raw_tp")
 __failure __msg("invalid read from stack")
+__msg("Verification failed: Memory Safety: Direct read of dynptr stack state")
+__msg("verifier-managed dynptr state")
+__msg("Use dynptr helpers or kfuncs")
 int invalid_read1(void *ctx)
 {
 	struct bpf_dynptr ptr;
diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c
index a4a007866a33..8d2b50d11fa4 100644
--- a/tools/testing/selftests/bpf/progs/irq.c
+++ b/tools/testing/selftests/bpf/progs/irq.c
@@ -14,6 +14,19 @@ extern int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void *unsafe_ptr
 struct bpf_res_spin_lock lockA __hidden SEC(".data.A");
 struct bpf_res_spin_lock lockB __hidden SEC(".data.B");
 
+SEC("?tc")
+__failure __msg("invalid read from stack")
+__msg("Verification failed: Memory Safety: Direct read of IRQ flag stack state")
+__msg("verifier-managed IRQ flag state")
+__msg("Pass the saved IRQ flag to the matching restore kfunc")
+int irq_flag_direct_read(struct __sk_buff *ctx)
+{
+	unsigned long flags;
+
+	bpf_local_irq_save(&flags);
+	return flags;
+}
+
 SEC("?tc")
 __failure __msg("R1 doesn't point to an irq flag on stack")
 int irq_save_bad_arg(struct __sk_buff *ctx)
diff --git a/tools/testing/selftests/bpf/progs/iters_state_safety.c b/tools/testing/selftests/bpf/progs/iters_state_safety.c
index 646026430e9b..4723ae578e53 100644
--- a/tools/testing/selftests/bpf/progs/iters_state_safety.c
+++ b/tools/testing/selftests/bpf/progs/iters_state_safety.c
@@ -332,6 +332,9 @@ int next_after_destroy_fail(void *ctx)
 
 SEC("?raw_tp")
 __failure __msg("invalid read from stack")
+__msg("Verification failed: Memory Safety: Direct read of iterator stack state")
+__msg("verifier-managed iterator state")
+__msg("Use iterator kfuncs")
 int __naked read_from_iter_slot_fail(void)
 {
 	asm volatile (
diff --git a/tools/testing/selftests/bpf/progs/verifier_xadd.c b/tools/testing/selftests/bpf/progs/verifier_xadd.c
index 05a0a55adb45..f2430b9a0218 100644
--- a/tools/testing/selftests/bpf/progs/verifier_xadd.c
+++ b/tools/testing/selftests/bpf/progs/verifier_xadd.c
@@ -121,4 +121,31 @@ l0_%=:	r0 = 42;					\
 "	::: __clobber_all);
 }
 
+SEC("tc")
+__description("xadd with variable stack offset")
+__failure
+__msg("variable offset stack pointer cannot be passed into helper function")
+__msg("Verification failed: Memory Safety: Variable-offset atomic stack access")
+__msg("The atomic operation would access the stack")
+__msg("Use a fixed stack offset for the atomic operation")
+__naked void xadd_variable_stack_offset(void)
+{
+	asm volatile ("					\
+	r1 = 0;						\
+	*(u64 *)(r10 - 16) = r1;			\
+	*(u64 *)(r10 - 8) = r1;				\
+	call %[bpf_get_prandom_u32];			\
+	r0 &= 8;					\
+	r1 = r10;					\
+	r1 += -16;					\
+	r1 += r0;					\
+	r2 = 1;						\
+	lock *(u64 *)(r1 + 0) += r2;			\
+	r0 = 0;						\
+	exit;						\
+"	:
+	: __imm(bpf_get_prandom_u32)
+	: __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 03/14] bpf: Preserve R0 lineage across helper calls
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
  2026-08-16  1:57 ` [PATCH bpf-next v1 01/14] bpf: Correct verifier diagnostic attribution for stack reads Kumar Kartikeya Dwivedi
  2026-08-16  1:57 ` [PATCH bpf-next v1 02/14] selftests/bpf: Test verifier stack-read diagnostic attribution Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  2:30   ` bot+bpf-ci
  2026-08-16  6:36   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 04/14] bpf: Drop dead spill diagnostic condition Kumar Kartikeya Dwivedi
                   ` (10 subsequent siblings)
  13 siblings, 2 replies; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Sashiko, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

check_helper_call() clears all caller-saved registers before taking the
diagnostic snapshot of R0. This records NOT_INIT as the old state for every
helper return and loses the lineage of the value held in R0 before the call.
bpf_diag_record_caller_saved() deliberately skips R0 because the paired
modification scope is responsible for it.

Open the R0 modification scope before clearing caller-saved registers,
matching the kfunc, ld_abs, and subprogram call paths.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://lore.kernel.org/bpf/20260815073833.A93A91F000E9@smtp.kernel.org/
Link: https://lore.kernel.org/bpf/48e6f021b89562f68850fe21ef8c78719819b04cf9c4e4f50bc791937d37ace8@mail.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/verifier.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5d0a2d3ef594..7ef324e384f4 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11024,13 +11024,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 
 	/* reset caller saved regs */
 	bpf_diag_record_caller_saved(env, regs);
+	bpf_diag_mod_begin(env, &regs[BPF_REG_0], NULL, BPF_DIAG_MOD_WRITE);
 	for (i = 0; i < CALLER_SAVED_REGS; i++) {
 		bpf_mark_reg_not_init(env, &regs[caller_saved[i]]);
 		check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK);
 	}
 	invalidate_outgoing_stack_args(env, cur_func(env));
 
-	bpf_diag_mod_begin(env, &regs[BPF_REG_0], NULL, BPF_DIAG_MOD_WRITE);
 	/* update return register (already marked as written above) */
 	ret_type = fn->ret_type;
 	ret_flag = type_flag(ret_type);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 04/14] bpf: Drop dead spill diagnostic condition
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (2 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 03/14] bpf: Preserve R0 lineage across helper calls Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  6:39   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 05/14] bpf: Use canonical stack argument names in diagnostics Kumar Kartikeya Dwivedi
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

diag_record_mod() appears to allow identical spill events to be suppressed,
but diag_mod_keeps_lineage() only accepts register write events. The spill
producer also supplies a stack target and an explicit origin, so a spill can
never satisfy this conjunction.

Restrict the condition to writes to reflect the filter's actual contract and
avoid suggesting that it applies to spills.

Link: https://lore.kernel.org/bpf/48e6f021b89562f68850fe21ef8c78719819b04cf9c4e4f50bc791937d37ace8@mail.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/diagnostics.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
index 33b7d9e8e2c3..37ed22a764e0 100644
--- a/kernel/bpf/diagnostics.c
+++ b/kernel/bpf/diagnostics.c
@@ -1531,8 +1531,7 @@ static void diag_record_mod(struct bpf_verifier_env *env, u32 insn_idx,
 	} else if (diag_mod_insn_origin(env, insn_idx, &target, &event.mod.origin)) {
 		event.mod.origin_valid = true;
 	}
-	if (old_reg && new_reg &&
-	    (reason == BPF_DIAG_MOD_WRITE || reason == BPF_DIAG_MOD_SPILL) &&
+	if (old_reg && new_reg && reason == BPF_DIAG_MOD_WRITE &&
 	    !memcmp(&event.mod.old, &event.mod.new, sizeof(event.mod.old)) &&
 	    !event.mod.origin_valid &&
 	    diag_mod_keeps_lineage(env, &event))
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 05/14] bpf: Use canonical stack argument names in diagnostics
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (3 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 04/14] bpf: Drop dead spill diagnostic condition Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  6:40   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 06/14] bpf: Correct kfunc argument diagnostics Kumar Kartikeya Dwivedi
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

The main diagnostic identifies the first outgoing stack slot as stack
argument 1 and the sixth function argument. The causal history instead
labels the same value as stack arg6, making it look like a different slot.

Render causal-history targets in the verifier's canonical stack-argument
location form. The first outgoing slot is now shown as *(R11-8), matching
reg_arg_name(), while the main diagnostic retains its fuller slot and
ordinal description.

Link: https://lore.kernel.org/bpf/eb1be5327d136b7e5bd6d68e76fef6de20c40790.camel@gmail.com/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/diagnostics.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
index 37ed22a764e0..2c475174a640 100644
--- a/kernel/bpf/diagnostics.c
+++ b/kernel/bpf/diagnostics.c
@@ -2163,7 +2163,7 @@ static const char *diag_mod_target_desc(struct bpf_verifier_env *env,
 	case BPF_DIAG_MOD_TARGET_REG:
 		return bpf_diag_fmt(env, "R%u", target->regno);
 	case BPF_DIAG_MOD_TARGET_STACK_ARG:
-		return bpf_diag_fmt(env, "stack arg%d", diag_stack_argno(target->stack_arg));
+		return bpf_diag_fmt(env, "*(R11-%u)", (target->stack_arg + 1) * BPF_REG_SIZE);
 	case BPF_DIAG_MOD_TARGET_STACK_SLOT:
 		return bpf_diag_fmt(env, "stack slot fp%d", -(target->spi + 1) * BPF_REG_SIZE);
 	default:
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 06/14] bpf: Correct kfunc argument diagnostics
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (4 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 05/14] bpf: Use canonical stack argument names in diagnostics Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  2:45   ` bot+bpf-ci
  2026-08-16  6:52   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 07/14] selftests/bpf: Test " Kumar Kartikeya Dwivedi
                   ` (7 subsequent siblings)
  13 siblings, 2 replies; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

The Call Type Safety diagnostics mishandle three kfunc argument classes.

BTF type ID 0 represents void, but btf_show_name() also uses zero to end
type traversal. A pointer that resolves to void therefore loses its pointee
name and is rendered as "()". End traversal directly for concrete terminal
types, but resolve referenced types before testing for ID zero, and name the
void terminal type explicitly. Format the complete parameter pointer type
for nullable kfunc arguments, so void pointers are reported as (void *).

Also add the missing structured report when an __szk memory-size argument is
not a verifier-known constant. Describe the generic bpf_refcount_acquire()
contract without deriving an object type from its void pointer prototype.

Link: https://lore.kernel.org/bpf/668871823f90f69896d3db27b56db2f53e481162.camel@gmail.com/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/btf.c      |  8 ++++----
 kernel/bpf/verifier.c | 22 +++++++++++++---------
 2 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 5b9d767895c9..6967d48bba49 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -1169,19 +1169,19 @@ static const char *btf_show_name(struct btf_show *show)
 			id = t->type;
 			break;
 		default:
-			id = 0;
-			break;
+			goto resolved;
 		}
+		t = btf_type_skip_qualifiers(show->btf, id);
 		if (!id)
 			break;
-		t = btf_type_skip_qualifiers(show->btf, id);
 	}
 	/* We may not be able to represent this type; bail to be safe */
 	if (i == BTF_SHOW_MAX_ITER)
 		return "";
 
+resolved:
 	if (!name)
-		name = btf_name_by_offset(show->btf, t->name_off);
+		name = btf_type_is_void(t) ? "void" : btf_name_by_offset(show->btf, t->name_off);
 
 	switch (BTF_INFO_KIND(t->info)) {
 	case BTF_KIND_STRUCT:
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7ef324e384f4..da2ec0655b17 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -12653,12 +12653,12 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 		    !type_may_be_null(kf_arg_type)) {
 			const char *expected_type;
 
-			expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
+			expected_type = bpf_diag_fmt_btf_type(env, btf, args[i].type);
 			verbose(env, "Possibly NULL pointer passed to trusted %s\n",
 				reg_arg_name(env, argno));
 			bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
 					      "Add a NULL check and call the kfunc only on the non-NULL path.",
-					      "the pointer may be NULL, but this kfunc requires a non-NULL pointer to %s",
+					      "the pointer may be NULL, but this kfunc requires a non-NULL value of type %s",
 					      expected_type);
 			return -EACCES;
 		}
@@ -13095,8 +13095,14 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 			break;
 		case KF_ARG_CONST_MEM_SIZE:
 			ret = process_const_arg(env, reg, argno, meta);
-			if (ret < 0)
+			if (ret < 0) {
+				if (ret == -EINVAL)
+					bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
+							      "Pass a compile-time constant or a value the verifier can prove is constant at this call.",
+							      "the kfunc requires this memory size to be a verifier-known constant, but %s is variable on this path",
+							      reg_arg_name(env, argno));
 				return ret;
+			}
 			fallthrough;
 		case KF_ARG_MEM_SIZE:
 		{
@@ -13160,15 +13166,13 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
 			break;
 		case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
 			if (!type_is_ptr_alloc_obj(reg->type)) {
-				const char *expected_type;
-
-				expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
 				verbose(env, "%s is neither owning or non-owning ref\n",
 					reg_arg_name(env, argno));
 				bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
-						      "Pass a pointer returned by the matching BPF object allocation or lookup operation for this kfunc.",
-						      "the kfunc expects a pointer to BPF-managed refcounted object type %s, but this argument is not such an object pointer",
-						      expected_type);
+						      "Pass an owning or non-owning pointer to a BPF-managed object containing a bpf_refcount field.",
+						      "the kfunc expects a pointer to a BPF-managed refcounted object, but %s is %s",
+						      reg_arg_name(env, argno),
+						      bpf_diag_reg_type_plain(env, reg->type));
 				return -EINVAL;
 			}
 			if (!type_is_non_owning_ref(reg->type))
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 07/14] selftests/bpf: Test kfunc argument diagnostics
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (5 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 06/14] bpf: Correct kfunc argument diagnostics Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  6:53   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 08/14] bpf: Report non-sleepable kfunc programs accurately Kumar Kartikeya Dwivedi
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

Extend existing negative kfunc programs to assert that BTF void is rendered
as void and that variable __szk arguments receive a structured constant-size
diagnostic.

Also pass a context pointer to bpf_refcount_acquire() and verify that the
report describes the generic refcounted-object contract and the actual
argument type. Retain the legacy verbose-message assertions.

Link: https://lore.kernel.org/bpf/3eda33675965763aa9b2e6a5784f32b34a6a83988a55fbea98b0dbd0cf3b088d@mail.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 tools/testing/selftests/bpf/progs/dynptr_fail.c          | 2 ++
 tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c | 9 +++++++++
 2 files changed, 11 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
index 72aa6b5a877b..9418dfe4d7b7 100644
--- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
@@ -1593,6 +1593,7 @@ __u32 hdr_size = sizeof(struct ethhdr);
 /* Can't pass in variable-sized len to bpf_dynptr_slice */
 SEC("?tc")
 __failure __msg("must be a known constant")
+__msg("requires this memory size to be a verifier-known constant")
 int dynptr_slice_var_len1(struct __sk_buff *skb)
 {
 	struct bpf_dynptr ptr;
@@ -1612,6 +1613,7 @@ int dynptr_slice_var_len1(struct __sk_buff *skb)
 /* Can't pass in variable-sized len to bpf_dynptr_slice */
 SEC("?tc")
 __failure __msg("must be a known constant")
+__msg("requires this memory size to be a verifier-known constant")
 int dynptr_slice_var_len2(struct __sk_buff *skb)
 {
 	char buffer[sizeof(struct ethhdr)] = {};
diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
index 024ef2aae200..eaaed0859f94 100644
--- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
@@ -63,6 +63,7 @@ long rbtree_refcounted_node_ref_escapes(void *ctx)
 
 SEC("?tc")
 __failure __msg("Possibly NULL pointer passed to trusted R1")
+__msg("requires a non-NULL value of type (void *)")
 long refcount_acquire_maybe_null(void *ctx)
 {
 	struct node_acquire *n, *m;
@@ -80,6 +81,14 @@ long refcount_acquire_maybe_null(void *ctx)
 	return 0;
 }
 
+SEC("?tc")
+__failure __msg("R1 is neither owning or non-owning ref")
+__msg("expects a pointer to a BPF-managed refcounted object, but R1 is a context pointer")
+long refcount_acquire_non_object(void *ctx)
+{
+	return bpf_refcount_acquire(ctx) != NULL;
+}
+
 SEC("?tc")
 __failure __msg("Unreleased reference id=3 alloc_insn={{[0-9]+}}")
 long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx)
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 08/14] bpf: Report non-sleepable kfunc programs accurately
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (6 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 07/14] selftests/bpf: Test " Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  2:30   ` bot+bpf-ci
  2026-08-16  7:32   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 09/14] selftests/bpf: Test non-sleepable kfunc context Kumar Kartikeya Dwivedi
                   ` (5 subsequent siblings)
  13 siblings, 2 replies; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

A sleepable kfunc call can fail either because the program is not sleepable
or because an otherwise sleepable program has entered a non-sleepable
critical section. check_kfunc_call() checks these conditions separately. The
first check is only gated by in_sleepable(), so the shared diagnostic can
blame an active RCU, preemption-disabled, IRQ-disabled, or locked region even
though leaving that region would not make the program sleepable. Adding a
second diagnostic entry point only to force the program context would
duplicate the API.

Reject the call once based on in_sleepable_context(). Teach the shared
bpf_diag_ctx_forbidden() reporter to prefer the non-sleepable program when the
current verifier state is not sleepable; otherwise preserve the RCU, preempt,
IRQ, and lock priority for active contexts. Select the kfunc message and
suggestion according to that cause, and align the helper and global-function
descriptions with the same priority.

This avoids a diagnostic-only wrapper while retaining context history for
sleepable programs that enter a forbidden region.

Link: https://lore.kernel.org/bpf/2e42a1a2bf45f4d2aba7495bdc9f147558055740e2f3c8b9dae255f6c57fc13c@mail.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/diagnostics.c |  4 +++-
 kernel/bpf/verifier.c    | 34 ++++++++++++++++++----------------
 2 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
index 2c475174a640..df9259fa0ea7 100644
--- a/kernel/bpf/diagnostics.c
+++ b/kernel/bpf/diagnostics.c
@@ -1083,7 +1083,9 @@ void bpf_diag_ctx_forbidden(struct bpf_verifier_env *env, u32 insn_idx,
 	const char *constraint, *context;
 	u32 depth;
 
-	if (env->cur_state->active_rcu_locks)
+	if (!env->cur_state->in_sleepable)
+		ctx_kind = BPF_DIAG_CONTEXT_NONE;
+	else if (env->cur_state->active_rcu_locks)
 		ctx_kind = BPF_DIAG_CONTEXT_RCU;
 	else if (env->cur_state->active_preempt_locks)
 		ctx_kind = BPF_DIAG_CONTEXT_PREEMPT;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index da2ec0655b17..3de9e4f617b6 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9912,7 +9912,7 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 				sub_name, non_sleepable_context_description(env));
 			operation = bpf_diag_fmt(env, "sleepable global function %s()", sub_name);
 			bpf_diag_ctx_forbidden(env, *insn_idx, operation,
-				"Move the call outside the critical section, or use a non-sleepable function.");
+				"Call the function from a sleepable program outside any critical section, or use a non-sleepable function.");
 			return -EINVAL;
 		}
 
@@ -10731,6 +10731,8 @@ static inline bool in_sleepable_context(struct bpf_verifier_env *env)
 
 static const char *non_sleepable_context_description(struct bpf_verifier_env *env)
 {
+	if (!in_sleepable(env))
+		return "non-sleepable prog";
 	if (env->cur_state->active_rcu_locks)
 		return "rcu_read_lock region";
 	if (env->cur_state->active_preempt_locks)
@@ -10739,7 +10741,7 @@ static const char *non_sleepable_context_description(struct bpf_verifier_env *en
 		return "IRQ-disabled region";
 	if (env->cur_state->active_locks)
 		return "lock region";
-	return "non-sleepable prog";
+	return "non-sleepable context";
 }
 
 static int release_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
@@ -10835,7 +10837,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 		operation = bpf_diag_fmt(env, "sleepable helper %s#%d",
 					 func_id_name(func_id), func_id);
 		bpf_diag_ctx_forbidden(env, insn_idx, operation,
-			"Move the helper call outside the critical section, or use a non-sleepable helper.");
+			"Call the helper from a sleepable program outside any critical section, or use a non-sleepable helper.");
 		return -EINVAL;
 	}
 
@@ -13760,11 +13762,20 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 	}
 
 	sleepable = bpf_is_kfunc_sleepable(&meta);
-	if (sleepable && !in_sleepable(env)) {
-		verbose(env, "program must be sleepable to call sleepable kfunc %s\n", func_name);
+	if (sleepable && !in_sleepable_context(env)) {
+		const char *suggestion;
+
+		if (in_sleepable(env)) {
+			verbose(env, "kernel func %s is sleepable within %s\n",
+				func_name, non_sleepable_context_description(env));
+			suggestion = "Move the kfunc call outside the critical section, or use a non-sleepable kfunc.";
+		} else {
+			verbose(env, "program must be sleepable to call sleepable kfunc %s\n",
+				func_name);
+			suggestion = "Mark the program sleepable if the program type allows it, or use a non-sleepable kfunc.";
+		}
 		operation = bpf_diag_fmt(env, "sleepable kfunc %s", func_name);
-		bpf_diag_ctx_forbidden(env, insn_idx, operation,
-			"Mark the program sleepable if the program type allows it, or use a non-sleepable kfunc.");
+		bpf_diag_ctx_forbidden(env, insn_idx, operation, suggestion);
 		return -EACCES;
 	}
 
@@ -13864,15 +13875,6 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 			invalidate_rcu_protected_refs(env);
 	}
 
-	if (sleepable && !in_sleepable_context(env)) {
-		verbose(env, "kernel func %s is sleepable within %s\n",
-			func_name, non_sleepable_context_description(env));
-		operation = bpf_diag_fmt(env, "sleepable kfunc %s", func_name);
-		bpf_diag_ctx_forbidden(env, insn_idx, operation,
-			"Move the kfunc call outside the critical section, or use a non-sleepable kfunc.");
-		return -EACCES;
-	}
-
 	if (in_rbtree_lock_required_cb(env) && (rcu_lock || rcu_unlock)) {
 		verbose(env, "Calling bpf_rcu_read_{lock,unlock} in unnecessary rbtree callback\n");
 		return -EACCES;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 09/14] selftests/bpf: Test non-sleepable kfunc context
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (7 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 08/14] bpf: Report non-sleepable kfunc programs accurately Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  2:30   ` bot+bpf-ci
  2026-08-16  7:37   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context Kumar Kartikeya Dwivedi
                   ` (4 subsequent siblings)
  13 siblings, 2 replies; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

Exercise a non-sleepable tracing program that enters an RCU read lock region
before calling a sleepable kfunc. Assert both the legacy verifier message and
the structured reason based on the program's sleepability.

This distinguishes the program-level rejection from the later check for a
sleepable program calling an operation inside an active critical section.

Link: https://lore.kernel.org/bpf/2e42a1a2bf45f4d2aba7495bdc9f147558055740e2f3c8b9dae255f6c57fc13c@mail.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 tools/testing/selftests/bpf/progs/preempt_lock.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/preempt_lock.c b/tools/testing/selftests/bpf/progs/preempt_lock.c
index 6d5fce7e6ffc..83c911494a34 100644
--- a/tools/testing/selftests/bpf/progs/preempt_lock.c
+++ b/tools/testing/selftests/bpf/progs/preempt_lock.c
@@ -6,6 +6,8 @@
 #include "bpf_experimental.h"
 
 extern int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void *unsafe_ptr__ign, u64 flags) __weak __ksym;
+extern void bpf_rcu_read_lock(void) __ksym;
+extern void bpf_rcu_read_unlock(void) __ksym;
 
 SEC("?tc")
 __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
@@ -127,6 +129,19 @@ int preempt_sleepable_kfunc(void *ctx)
 	return 0;
 }
 
+SEC("?fentry/" SYS_PREFIX "sys_getpgid")
+__failure __msg("program must be sleepable to call sleepable kfunc bpf_copy_from_user_str")
+__msg("cannot be used in non-sleepable program")
+int non_sleepable_kfunc_in_rcu(void *ctx)
+{
+	u32 data;
+
+	bpf_rcu_read_lock();
+	bpf_copy_from_user_str(&data, sizeof(data), NULL, 0);
+	bpf_rcu_read_unlock();
+	return 0;
+}
+
 int __noinline preempt_global_subprog(void)
 {
 	preempt_balance_subprog();
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (8 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 09/14] selftests/bpf: Test non-sleepable kfunc context Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  2:45   ` bot+bpf-ci
  2026-08-16  7:58   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 11/14] bpf: Preserve source attribution without source text Kumar Kartikeya Dwivedi
                   ` (3 subsequent siblings)
  13 siblings, 2 replies; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

Program Structure reports have three attribution gaps. A missing jump table
is reported at the beginning of its subprogram rather than at the gotox that
needs the table, recursive-call details are present only in the legacy log,
and the early subprogram-layout checks run before BTF line information is
installed.

Pass the failing gotox instruction into the jump-table lookup and include both
ends of a recursive edge in the structured reason.

The BTF validator needs the discovered subprogram boundaries together with
the LD_ABS and tail-call properties collected during the layout scan. Split
that property collection from layout validation, then validate BTF before
reporting layout errors. This makes validated source information available to
the jump-boundary and fallthrough reports without changing either check.

Link: https://lore.kernel.org/bpf/cf2f420c2b21de440a7dc51b1565c0f06d4b539640ee5c03384e5d77bcfb5686@mail.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/cfg.c      |  6 +++---
 kernel/bpf/verifier.c | 47 ++++++++++++++++++++++++++++++++-----------
 2 files changed, 38 insertions(+), 15 deletions(-)

diff --git a/kernel/bpf/cfg.c b/kernel/bpf/cfg.c
index 0f13c13f4133..95c59f6cf70a 100644
--- a/kernel/bpf/cfg.c
+++ b/kernel/bpf/cfg.c
@@ -287,7 +287,7 @@ static struct bpf_iarray *jt_from_map(struct bpf_map *map)
  * combined jump table in jt->items (allocated with kvcalloc)
  */
 static struct bpf_iarray *jt_from_subprog(struct bpf_verifier_env *env,
-					  int subprog_start, int subprog_end)
+					  int insn_idx, int subprog_start, int subprog_end)
 {
 	struct bpf_iarray *jt = NULL;
 	struct bpf_map *map;
@@ -327,7 +327,7 @@ static struct bpf_iarray *jt_from_subprog(struct bpf_verifier_env *env,
 	if (!jt) {
 		verbose(env, "no jump tables found for subprog starting at %u\n", subprog_start);
 		bpf_diag_program_structure(
-			env, subprog_start, "missing jump table",
+			env, insn_idx, "missing jump table",
 			"Make sure subprograms containing gotox instructions are accompanied by jump tables referencing these subprograms.",
 			"No jump table was found for the subprogram that starts at instruction %u.",
 			subprog_start);
@@ -349,7 +349,7 @@ create_jt(int t, struct bpf_verifier_env *env)
 	subprog = bpf_find_containing_subprog(env, t);
 	subprog_start = subprog->start;
 	subprog_end = (subprog + 1)->start;
-	jt = jt_from_subprog(env, subprog_start, subprog_end);
+	jt = jt_from_subprog(env, t, subprog_start, subprog_end);
 	if (IS_ERR(jt))
 		return jt;
 
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 3de9e4f617b6..d2f08c6612c6 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2995,15 +2995,13 @@ static int add_kfuncs(struct bpf_verifier_env *env)
 	return 0;
 }
 
-static int check_subprogs(struct bpf_verifier_env *env)
+static void find_subprog_properties(struct bpf_verifier_env *env)
 {
-	int i, subprog_start, subprog_end, off, cur_subprog = 0;
+	int i, subprog_end, cur_subprog = 0;
 	struct bpf_subprog_info *subprog = env->subprog_info;
 	struct bpf_insn *insn = env->prog->insnsi;
 	int insn_cnt = env->prog->len;
 
-	/* now check that all jumps are within the same subprog */
-	subprog_start = subprog[cur_subprog].start;
 	subprog_end = subprog[cur_subprog + 1].start;
 	for (i = 0; i < insn_cnt; i++) {
 		u8 code = insn[i].code;
@@ -3017,6 +3015,27 @@ static int check_subprogs(struct bpf_verifier_env *env)
 		if (BPF_CLASS(code) == BPF_LD &&
 		    (BPF_MODE(code) == BPF_ABS || BPF_MODE(code) == BPF_IND))
 			subprog[cur_subprog].has_ld_abs = true;
+		if (i == subprog_end - 1) {
+			cur_subprog++;
+			if (cur_subprog < env->subprog_cnt)
+				subprog_end = subprog[cur_subprog + 1].start;
+		}
+	}
+}
+
+static int check_subprogs(struct bpf_verifier_env *env)
+{
+	int i, subprog_start, subprog_end, off, cur_subprog = 0;
+	struct bpf_subprog_info *subprog = env->subprog_info;
+	struct bpf_insn *insn = env->prog->insnsi;
+	int insn_cnt = env->prog->len;
+
+	/* now check that all jumps are within the same subprog */
+	subprog_start = subprog[cur_subprog].start;
+	subprog_end = subprog[cur_subprog + 1].start;
+	for (i = 0; i < insn_cnt; i++) {
+		u8 code = insn[i].code;
+
 		if (BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32)
 			goto next;
 		if (BPF_OP(code) == BPF_CALL)
@@ -3038,9 +3057,10 @@ static int check_subprogs(struct bpf_verifier_env *env)
 		}
 next:
 		if (i == subprog_end - 1) {
-			/* to avoid fall-through from one subprog into another
+			/*
+			 * To avoid fall-through from one subprog into another,
 			 * the last insn of the subprog should be either exit
-			 * or unconditional jump back or bpf_throw call
+			 * or unconditional jump back or bpf_throw call.
 			 */
 			if (code != (BPF_JMP | BPF_EXIT) &&
 			    code != (BPF_JMP32 | BPF_JA) &&
@@ -3126,8 +3146,9 @@ static int sort_subprogs_topo(struct bpf_verifier_env *env)
 					bpf_diag_program_structure(
 						env, idx, "recursive subprogram call",
 						"Rewrite the recursion as an explicit bounded loop, or split the logic so subprogram calls do not form a cycle.",
-						"This bpf2bpf call would make the subprogram call graph recursive. "
-						"The verifier requires a finite, acyclic call graph so it can bound stack depth and analysis.");
+						"The call from %s() to %s() would make the subprogram call graph recursive. "
+						"The verifier requires a finite, acyclic call graph so it can bound stack depth and analysis.",
+						bpf_subprog_name(env, cur), bpf_subprog_name(env, callee));
 					ret = -EINVAL;
 					goto out;
 				}
@@ -21124,17 +21145,19 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
 	if (ret < 0)
 		goto skip_full_check;
 
-	/* Discover all subprograms before validating their layout and BTF. */
+	/* Discover all subprograms and collect the properties needed by BTF validation. */
 	ret = add_subprogs(env);
 	if (ret < 0)
 		goto skip_full_check;
 
-	ret = check_subprogs(env);
+	find_subprog_properties(env);
+
+	/* Validate BTF and apply CO-RE before reporting subprogram layout errors. */
+	ret = bpf_check_btf_info(env, attr, uattr);
 	if (ret < 0)
 		goto skip_full_check;
 
-	/* Validate BTF against the complete subprogram layout and apply CO-RE. */
-	ret = bpf_check_btf_info(env, attr, uattr);
+	ret = check_subprogs(env);
 	if (ret < 0)
 		goto skip_full_check;
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 11/14] bpf: Preserve source attribution without source text
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (9 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  8:01   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 12/14] selftests/bpf: Test Program Structure diagnostic context Kumar Kartikeya Dwivedi
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

GCC emits BTF line records with a file name and line number, but leaves the
source line string empty. bpf_diag_source() currently treats that empty string
as if the complete line record were unavailable, so diagnostics fall back to
an instruction number and discard the function, file, and line attribution.

Print the available source location before deciding whether source context can
be rendered. When source text is absent, omit only the source context and retain
the diagnostic annotation and instruction context.

Fixes: b9c5d822f677 ("bpf: Add source and instruction diagnostic context")
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/diagnostics.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
index df9259fa0ea7..44d0b7c5f05f 100644
--- a/kernel/bpf/diagnostics.c
+++ b/kernel/bpf/diagnostics.c
@@ -833,11 +833,9 @@ static void bpf_diag_source(struct bpf_verifier_env *env, u32 insn_idx, const ch
 	linfo = bpf_find_linfo(env->prog, insn_idx);
 	if (btf && linfo)
 		bpf_get_linfo_source(btf, linfo, &src);
-	if (!src.file || !*src.file || !src.line || !*src.line) {
+	if (!src.file || !*src.file) {
 		diag_write(env, "  insn %u\n", insn_idx);
-		diag_print_source_annotation(env, 0, 0, label, msg);
-		diag_print_insn_context(env, insn_idx, disasm_lines);
-		goto out_restore;
+		goto out_annotation;
 	}
 
 	subprog = bpf_find_containing_subprog(env, insn_idx);
@@ -847,6 +845,8 @@ static void bpf_diag_source(struct bpf_verifier_env *env, u32 insn_idx, const ch
 		diag_write(env, "  %s @ %s:%d:%d\n", func, src.file, src.line_num, src.line_col);
 	else
 		diag_write(env, "  %s:%d:%d\n", src.file, src.line_num, src.line_col);
+	if (!src.line || !*src.line)
+		goto out_annotation;
 
 	start_line = src.line_num - BPF_DIAG_CONTEXT;
 	end_line = src.line_num + BPF_DIAG_CONTEXT;
@@ -889,7 +889,11 @@ static void bpf_diag_source(struct bpf_verifier_env *env, u32 insn_idx, const ch
 			diag_print_source_annotation(env, width, indent, label, msg);
 	}
 	diag_print_insn_context(env, insn_idx, disasm_lines);
+	goto out_restore;
 
+out_annotation:
+	diag_print_source_annotation(env, 0, 0, label, msg);
+	diag_print_insn_context(env, insn_idx, disasm_lines);
 out_restore:
 	diag_fmt_restore(env, mark);
 }
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 12/14] selftests/bpf: Test Program Structure diagnostic context
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (10 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 11/14] bpf: Preserve source attribution without source text Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  8:06   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 13/14] bpf: Distinguish function references in policy diagnostics Kumar Kartikeya Dwivedi
  2026-08-16  1:57 ` [PATCH bpf-next v1 14/14] selftests/bpf: Test pseudo-function " Kumar Kartikeya Dwivedi
  13 siblings, 1 reply; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

Exercise each corrected Program Structure report. Place a missing-table gotox
after another instruction so its attribution differs from the subprogram
start, and assert that the recursive-call reason names both ends of the edge.

Add malformed subprogram layouts for a branch crossing a subprogram boundary
and a subprogram that falls through its end. Both cases carry BTF line records
and assert that their structured reports include the corresponding source
function and file.

Link: https://lore.kernel.org/bpf/cf2f420c2b21de440a7dc51b1565c0f06d4b539640ee5c03384e5d77bcfb5686@mail.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 .../selftests/bpf/progs/verifier_cfg.c        | 40 +++++++++++++++++++
 .../selftests/bpf/progs/verifier_gotox.c      |  2 +
 .../selftests/bpf/progs/verifier_loops1.c     |  1 +
 3 files changed, 43 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/verifier_cfg.c b/tools/testing/selftests/bpf/progs/verifier_cfg.c
index c1f55e1d80a4..4416d915cdf3 100644
--- a/tools/testing/selftests/bpf/progs/verifier_cfg.c
+++ b/tools/testing/selftests/bpf/progs/verifier_cfg.c
@@ -55,6 +55,46 @@ __naked void out_of_range_jump2(void)
 "	::: __clobber_all);
 }
 
+static __naked __noinline __used int cross_subprog_target(void)
+{
+	asm volatile ("					\
+	r0 = 0;						\
+	exit;						\
+"	::: __clobber_all);
+}
+
+SEC("socket")
+__description("jump across subprogram boundary")
+__failure __msg("jump out of range from insn 1")
+__msg("jump_across_subprog_boundary @ verifier_cfg.c")
+__naked void jump_across_subprog_boundary(void)
+{
+	asm volatile ("					\
+	call cross_subprog_target;			\
+	goto +1;					\
+	exit;						\
+"	::: __clobber_all);
+}
+
+static __naked __noinline __used int fallthrough_subprog(void)
+{
+	asm volatile ("					\
+	r0 = 0;						\
+"	::: __clobber_all);
+}
+
+SEC("socket")
+__description("subprogram fallthrough")
+__failure __msg("last insn is not an exit or jmp")
+__msg("fallthrough_subprog @ verifier_cfg.c")
+__naked void subprog_fallthrough(void)
+{
+	asm volatile ("					\
+	call fallthrough_subprog;			\
+	exit;						\
+"	::: __clobber_all);
+}
+
 SEC("socket")
 __description("loop (back-edge)")
 __failure __msg("unreachable insn 1")
diff --git a/tools/testing/selftests/bpf/progs/verifier_gotox.c b/tools/testing/selftests/bpf/progs/verifier_gotox.c
index 5b18c9a27717..a835a4871021 100644
--- a/tools/testing/selftests/bpf/progs/verifier_gotox.c
+++ b/tools/testing/selftests/bpf/progs/verifier_gotox.c
@@ -53,9 +53,11 @@ DEFINE_SIMPLE_JUMP_TABLE_PROG(reserved_field_non_zero_imm, BPF_REG_0, 0, 1, __fa
  */
 SEC("socket")
 __failure __msg("no jump tables found for subprog starting at 0")
+__msg(">>> 1 | (0d) gotox r0")
 __naked void jump_table_no_jump_table(void)
 {
 	asm volatile ("						\
+	r0 = 0;							\
 	.8byte %[gotox_r0];					\
 	r0 = 1;							\
 	exit;							\
diff --git a/tools/testing/selftests/bpf/progs/verifier_loops1.c b/tools/testing/selftests/bpf/progs/verifier_loops1.c
index d248ce877f14..d1ec19b7f66b 100644
--- a/tools/testing/selftests/bpf/progs/verifier_loops1.c
+++ b/tools/testing/selftests/bpf/progs/verifier_loops1.c
@@ -139,6 +139,7 @@ SEC("tracepoint")
 __description("bounded recursion")
 __failure
 __msg("recursive call from")
+__msg("The call from bounded_recursion__1() to bounded_recursion__1() would make")
 __naked void bounded_recursion(void)
 {
 	asm volatile ("					\
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 13/14] bpf: Distinguish function references in policy diagnostics
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (11 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 12/14] selftests/bpf: Test Program Structure diagnostic context Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  8:09   ` Eduard Zingerman
  2026-08-16  1:57 ` [PATCH bpf-next v1 14/14] selftests/bpf: Test pseudo-function " Kumar Kartikeya Dwivedi
  13 siblings, 1 reply; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

add_subprogs() rejects both BPF-to-BPF calls and BPF_PSEUDO_FUNC loads for
unprivileged programs. The latter loads a subprogram address for use as a
callback, but its Policy report currently describes it as a function call and
suggests avoiding calls that the program does not contain.

Select the operation and suggestion from the instruction kind. Preserve the
existing call wording for BPF_PSEUDO_CALL, and describe BPF_PSEUDO_FUNC as a
BPF function reference.

Link: https://lore.kernel.org/bpf/d02e6a6d3b2dc43a207b8ba836ce62497b250dede9252e7409c5212201c794b7@mail.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/verifier.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index d2f08c6612c6..bc7c1163ab1c 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2912,6 +2912,7 @@ static int add_subprogs(struct bpf_verifier_env *env)
 	struct bpf_subprog_info *subprog = env->subprog_info;
 	int i, ret, insn_cnt = env->prog->len, ex_cb_insn;
 	struct bpf_insn *insn = env->prog->insnsi;
+	const char *operation, *suggestion;
 
 	/* Add entry function. */
 	ret = add_subprog(env, 0);
@@ -2923,11 +2924,18 @@ static int add_subprogs(struct bpf_verifier_env *env)
 			continue;
 
 		if (!env->bpf_capable) {
+			if (bpf_pseudo_func(insn)) {
+				operation = "BPF function reference";
+				suggestion = "Load this program with the required capability, or avoid BPF function references in unprivileged programs.";
+			} else {
+				operation = "BPF-to-BPF function call";
+				suggestion = "Load this program with the required capability, or avoid BPF-to-BPF function calls in unprivileged programs.";
+			}
 			verbose(env, "loading/calling other bpf or kernel functions are allowed for CAP_BPF and CAP_SYS_ADMIN\n");
 			bpf_diag_policy(
-				env, i, "BPF-to-BPF function call",
+				env, i, operation,
 				"loading or calling other BPF functions requires CAP_BPF or CAP_SYS_ADMIN",
-				"Load this program with the required capability, or avoid BPF-to-BPF function calls in unprivileged programs.");
+				suggestion);
 			return -EPERM;
 		}
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH bpf-next v1 14/14] selftests/bpf: Test pseudo-function policy diagnostics
  2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
                   ` (12 preceding siblings ...)
  2026-08-16  1:57 ` [PATCH bpf-next v1 13/14] bpf: Distinguish function references in policy diagnostics Kumar Kartikeya Dwivedi
@ 2026-08-16  1:57 ` Kumar Kartikeya Dwivedi
  2026-08-16  2:45   ` bot+bpf-ci
  13 siblings, 1 reply; 37+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-08-16  1:57 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

Load a socket-filter program that passes a callback to bpf_loop() without
making a BPF-to-BPF call. Verify that the privileged load succeeds and the
unprivileged Policy report identifies the BPF function reference at its
ldimm64 instruction.

Also reject the inaccurate BPF-to-BPF call wording in the portion of the log
covered by the structured report.

Link: https://lore.kernel.org/bpf/d02e6a6d3b2dc43a207b8ba836ce62497b250dede9252e7409c5212201c794b7@mail.kernel.org/
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 .../selftests/bpf/progs/verifier_unpriv.c      | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/verifier_unpriv.c b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
index 42de5cff7e52..3069e70fbcbd 100644
--- a/tools/testing/selftests/bpf/progs/verifier_unpriv.c
+++ b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
@@ -96,6 +96,24 @@ __naked void pseudo_btf_id_log_masks_address(void)
 	: __clobber_all);
 }
 
+static int pseudo_func_callback(__u32 index, void *ctx)
+{
+	return 0;
+}
+
+SEC("socket")
+__description("unpriv: pseudo function policy diagnostic")
+__success __failure_unpriv
+__msg_unpriv("loading/calling other bpf or kernel functions")
+__not_msg_unpriv("BPF-to-BPF function call")
+__msg_unpriv("policy check failed for BPF function reference")
+__msg_unpriv("avoid BPF function references in unprivileged")
+int unpriv_pseudo_func_policy(void *ctx)
+{
+	bpf_loop(1, pseudo_func_callback, NULL, 0);
+	return 0;
+}
+
 SEC("socket")
 __description("unpriv: return pointer")
 __success __failure_unpriv __msg_unpriv("R0 leaks addr")
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 09/14] selftests/bpf: Test non-sleepable kfunc context
  2026-08-16  1:57 ` [PATCH bpf-next v1 09/14] selftests/bpf: Test non-sleepable kfunc context Kumar Kartikeya Dwivedi
@ 2026-08-16  2:30   ` bot+bpf-ci
  2026-08-16  7:37   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: bot+bpf-ci @ 2026-08-16  2:30 UTC (permalink / raw)
  To: memxor, bpf
  Cc: ast, andrii, daniel, eddyz87, emil, kkd, kernel-team, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 1078 bytes --]

> selftests/bpf: Test non-sleepable kfunc context
>
> Exercise a non-sleepable tracing program that enters an RCU read lock region
> before calling a sleepable kfunc. Assert both the legacy verifier message and
> the structured reason based on the program's sleepability.
>
> This distinguishes the program-level rejection from the later check for a
> sleepable program calling an operation inside an active critical section.

This isn't a bug, but since the previous patch folded both diagnostics into
one site in check_kfunc_call(), would it read more clearly to say this
distinguishes the program-level rejection from the in-critical-section
rejection, rather than from 'the later check'?

The wording reads as left over from the pre-unification code layout and may
send a reader looking for a second call site that no longer exists.


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31921026518

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 08/14] bpf: Report non-sleepable kfunc programs accurately
  2026-08-16  1:57 ` [PATCH bpf-next v1 08/14] bpf: Report non-sleepable kfunc programs accurately Kumar Kartikeya Dwivedi
@ 2026-08-16  2:30   ` bot+bpf-ci
  2026-08-16  7:32   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: bot+bpf-ci @ 2026-08-16  2:30 UTC (permalink / raw)
  To: memxor, bpf
  Cc: ast, andrii, daniel, eddyz87, emil, kkd, kernel-team, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 3959 bytes --]

> diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
> index 2c475174a640..df9259fa0ea7 100644
> --- a/kernel/bpf/diagnostics.c
> +++ b/kernel/bpf/diagnostics.c
> @@ -1083,7 +1083,9 @@ void bpf_diag_ctx_forbidden(struct bpf_verifier_env *env, u32 insn_idx,
>  	const char *constraint, *context;
>  	u32 depth;
>
> -	if (env->cur_state->active_rcu_locks)
> +	if (!env->cur_state->in_sleepable)
> +		ctx_kind = BPF_DIAG_CONTEXT_NONE;
> +	else if (env->cur_state->active_rcu_locks)
>  		ctx_kind = BPF_DIAG_CONTEXT_RCU;
>  	else if (env->cur_state->active_preempt_locks)
>  		ctx_kind = BPF_DIAG_CONTEXT_PREEMPT;
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index da2ec0655b17..3de9e4f617b6 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c

[ ... ]

> @@ -10731,6 +10731,8 @@ static inline bool in_sleepable_context(struct bpf_verifier_env *env)
>
>  static const char *non_sleepable_context_description(struct bpf_verifier_env *env)
>  {
> +	if (!in_sleepable(env))
> +		return "non-sleepable prog";
>  	if (env->cur_state->active_rcu_locks)
>  		return "rcu_read_lock region";
>  	if (env->cur_state->active_preempt_locks)
> @@ -10739,7 +10741,7 @@ static const char *non_sleepable_context_description(struct bpf_verifier_env *en
>  		return "IRQ-disabled region";
>  	if (env->cur_state->active_locks)
>  		return "lock region";
> -	return "non-sleepable prog";
> +	return "non-sleepable context";

This isn't a bug, but with the new !in_sleepable(env) early return, the
final return "non-sleepable context"; looks unreachable given all three
callers guard on !in_sleepable_context(env) - is the fallback still
needed, or could it be dropped (or kept as the single non-sleepable case)?

[ ... ]

> @@ -10835,7 +10837,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
>  		operation = bpf_diag_fmt(env, "sleepable helper %s#%d",
>  					 func_id_name(func_id), func_id);
>  		bpf_diag_ctx_forbidden(env, insn_idx, operation,
> -			"Move the helper call outside the critical section, or use a non-sleepable helper.");
> +			"Call the helper from a sleepable program outside any critical section, or use a non-sleepable helper.");
>  		return -EINVAL;
>  	}

[ ... ]

> @@ -13760,11 +13762,20 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
>  	}
>
>  	sleepable = bpf_is_kfunc_sleepable(&meta);
> -	if (sleepable && !in_sleepable(env)) {
> -		verbose(env, "program must be sleepable to call sleepable kfunc %s\n", func_name);
> +	if (sleepable && !in_sleepable_context(env)) {
> +		const char *suggestion;
> +
> +		if (in_sleepable(env)) {
> +			verbose(env, "kernel func %s is sleepable within %s\n",
> +				func_name, non_sleepable_context_description(env));
> +			suggestion = "Move the kfunc call outside the critical section, or use a non-sleepable kfunc.";
> +		} else {
> +			verbose(env, "program must be sleepable to call sleepable kfunc %s\n",
> +				func_name);
> +			suggestion = "Mark the program sleepable if the program type allows it, or use a non-sleepable kfunc.";
> +		}
>  		operation = bpf_diag_fmt(env, "sleepable kfunc %s", func_name);
> -		bpf_diag_ctx_forbidden(env, insn_idx, operation,
> -			"Mark the program sleepable if the program type allows it, or use a non-sleepable kfunc.");
> +		bpf_diag_ctx_forbidden(env, insn_idx, operation, suggestion);
>  		return -EACCES;
>  	}

This isn't a bug, but check_kfunc_call() now picks the suggestion per
cause - would it read better for the helper and global-function sites to
do the same instead of merging both causes into one sentence, since "from
a sleepable program" does not apply when the program is already sleepable?


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31921026518

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 03/14] bpf: Preserve R0 lineage across helper calls
  2026-08-16  1:57 ` [PATCH bpf-next v1 03/14] bpf: Preserve R0 lineage across helper calls Kumar Kartikeya Dwivedi
@ 2026-08-16  2:30   ` bot+bpf-ci
  2026-08-16  6:12     ` Eduard Zingerman
  2026-08-16  6:36   ` Eduard Zingerman
  1 sibling, 1 reply; 37+ messages in thread
From: bot+bpf-ci @ 2026-08-16  2:30 UTC (permalink / raw)
  To: memxor, bpf
  Cc: sashiko-bot, ast, andrii, daniel, eddyz87, emil, kkd, kernel-team,
	ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
	ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 4149 bytes --]

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5d0a2d3ef594..7ef324e384f4 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -11024,13 +11024,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
>
>  	/* reset caller saved regs */
>  	bpf_diag_record_caller_saved(env, regs);
> +	bpf_diag_mod_begin(env, &regs[BPF_REG_0], NULL, BPF_DIAG_MOD_WRITE);
>  	for (i = 0; i < CALLER_SAVED_REGS; i++) {
>  		bpf_mark_reg_not_init(env, &regs[caller_saved[i]]);
>  		check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK);
>  	}
>  	invalidate_outgoing_stack_args(env, cur_func(env));
>
> -	bpf_diag_mod_begin(env, &regs[BPF_REG_0], NULL, BPF_DIAG_MOD_WRITE);
>  	/* update return register (already marked as written above) */
>  	ret_type = fn->ret_type;
>  	ret_flag = type_flag(ret_type);

Does this produce the correct diagnostic message for void helpers? The
new bpf_diag_mod_begin() is now opened unconditionally for all helpers,
including those with RET_VOID. Because the snapshot is taken before the
caller-saved clearing loop, a void helper now generates a history event
with R0's real pre-call value as old and NOT_INIT as new, with reason
BPF_DIAG_MOD_WRITE.

Looking at the return type handling:

  switch (base_type(ret_type)) {
  ...
  case RET_VOID:
      regs[BPF_REG_0].type = NOT_INIT;
      break;
  ...
  bpf_diag_mod_end(env);

And the diagnostic rendering in diag_print_mod():

  bpf_diag_source(env, event->insn_idx, label,
                  "%s changed from %s to %s", target_desc, old, new);

So a call to bpf_spin_lock(), bpf_spin_unlock(), bpf_ringbuf_submit(),
bpf_ringbuf_discard(), bpf_ringbuf_submit_dynptr(),
bpf_ringbuf_discard_dynptr() or bpf_tail_call() would now report
"update: R0 changed from <live value> to <invalid>", attributing the
loss of R0 to a value update by a helper that returns nothing, instead
of to the caller-saved clobber.

The correct rendering for caller-saved invalidation is one reason code
away: "R0: call invalidated this caller-saved register; previous value
was <live value>".

The commit message states the new ordering matches the kfunc, ld_abs,
and subprogram call paths, but check_func_call() explicitly
distinguishes the void case:

  if (returns_void)
      bpf_diag_record_scrub(env, &caller->regs[BPF_REG_0],
                            BPF_DIAG_MOD_CALLER_SAVED);
  else
      bpf_diag_mod_begin(env, &caller->regs[BPF_REG_0], NULL,
                         BPF_DIAG_MOD_WRITE);
  clear_caller_saved_regs(env, caller->regs);
  invalidate_outgoing_stack_args(env, cur_func(env));

Could check_helper_call() gate the bpf_diag_mod_begin() call the same
way using base_type(fn->ret_type) == RET_VOID? The impact is limited to
diagnostic text only - no bpf_reg_state, verifier decision, or
memory-safety behaviour changes - but the misattribution would be new.

---

>     bpf: Preserve R0 lineage across helper calls
>
>     check_helper_call() clears all caller-saved registers before taking the
>     diagnostic snapshot of R0. This records NOT_INIT as the old state for every
>     helper return and loses the lineage of the value held in R0 before the call.
>     bpf_diag_record_caller_saved() deliberately skips R0 because the paired
>     modification scope is responsible for it.
>
>     Open the R0 modification scope before clearing caller-saved registers,
>     matching the kfunc, ld_abs, and subprogram call paths.
>
>     Reported-by: Sashiko <sashiko-bot@kernel.org>
>     Link: https://lore.kernel.org/bpf/20260815073833.A93A91F000E9@smtp.kernel.org/
>     Link: https://lore.kernel.org/bpf/48e6f021b89562f68850fe21ef8c78719819b04cf9c4e4f50bc791937d37ace8@mail.kernel.org/
>     Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>

This looks like a bug fix. Should this include:

  Fixes: af4ea6e20fff ("bpf: Track verifier register diagnostic events")


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31921026518

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 14/14] selftests/bpf: Test pseudo-function policy diagnostics
  2026-08-16  1:57 ` [PATCH bpf-next v1 14/14] selftests/bpf: Test pseudo-function " Kumar Kartikeya Dwivedi
@ 2026-08-16  2:45   ` bot+bpf-ci
  0 siblings, 0 replies; 37+ messages in thread
From: bot+bpf-ci @ 2026-08-16  2:45 UTC (permalink / raw)
  To: memxor, bpf
  Cc: ast, andrii, daniel, eddyz87, emil, kkd, kernel-team, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 2378 bytes --]

> Load a socket-filter program that passes a callback to bpf_loop() without
> making a BPF-to-BPF call. Verify that the privileged load succeeds and the
> unprivileged Policy report identifies the BPF function reference at its
> ldimm64 instruction.

This isn't a bug, but the changelog says the report is verified to identify
the reference "at its ldimm64 instruction", though the added test asserts no
location at all -- only the three wording substrings.

Looking at the verification flow, prog->aux->linfo is assigned by
check_btf_line() in kernel/bpf/check_btf.c, reached from
bpf_check_btf_info() at kernel/bpf/verifier.c:21164, which runs after
add_subprogs() at line 21157. So bpf_find_linfo() returns NULL and
bpf_diag_source() takes its fallback branch, emitting a bare "insn %u" with
no function/file/line and no Source context block.

Would it be worth either asserting the instruction location the changelog
mentions, or softening the wording -- given that linfo is not yet parsed
when add_subprogs() runs, the "At" section here can only print a bare
insn N?

> diff --git a/tools/testing/selftests/bpf/progs/verifier_unpriv.c b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
> index 42de5cff7e52..3069e70fbcbd 100644
> --- a/tools/testing/selftests/bpf/progs/verifier_unpriv.c
> +++ b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
> @@ -96,6 +96,24 @@ __naked void pseudo_btf_id_log_masks_address(void)
>  	: __clobber_all);
>  }
>
> +static int pseudo_func_callback(__u32 index, void *ctx)
> +{
> +	return 0;
> +}
> +
> +SEC("socket")
> +__description("unpriv: pseudo function policy diagnostic")
> +__success __failure_unpriv
> +__msg_unpriv("loading/calling other bpf or kernel functions")
> +__not_msg_unpriv("BPF-to-BPF function call")
> +__msg_unpriv("policy check failed for BPF function reference")
> +__msg_unpriv("avoid BPF function references in unprivileged")
> +int unpriv_pseudo_func_policy(void *ctx)
> +{
> +	bpf_loop(1, pseudo_func_callback, NULL, 0);
> +	return 0;
> +}
> +
>  SEC("socket")
>  __description("unpriv: return pointer")
>  __success __failure_unpriv __msg_unpriv("R0 leaks addr")


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31921026518

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 02/14] selftests/bpf: Test verifier stack-read diagnostic attribution
  2026-08-16  1:57 ` [PATCH bpf-next v1 02/14] selftests/bpf: Test verifier stack-read diagnostic attribution Kumar Kartikeya Dwivedi
@ 2026-08-16  2:45   ` bot+bpf-ci
  2026-08-16  6:35   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: bot+bpf-ci @ 2026-08-16  2:45 UTC (permalink / raw)
  To: memxor, bpf
  Cc: ast, andrii, daniel, eddyz87, emil, kkd, kernel-team, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 1297 bytes --]

> selftests/bpf: Test verifier stack-read diagnostic attribution
>
> Verifier diagnostics distinguish uninitialized stack bytes from opaque
> dynptr, iterator, and IRQ-flag state, and identify variable-offset atomic
> stack accesses without changing the existing verbose messages.
>
> Add output assertions to the existing dynptr and iterator rejection
> cases. Add a direct IRQ-flag read and a variable-offset atomic stack
> access to cover the other classifications. Retain an assertion for the
> legacy helper-worded verbose message in the atomic test.
>
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>

This isn't a bug, but would it be worth adding one assertion on the
retained uninitialized-stack-read report as well? The commit adds test
coverage for STACK_DYNPTR, STACK_ITER, STACK_IRQ_FLAG and the
variable-offset atomic path, but leaves the STACK_INVALID arm unpinned.
If a later refactor changes the uninitialized-read wording to reuse the
new verifier-managed state classification, the change would go unnoticed
in the test suite.


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31921026518

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 06/14] bpf: Correct kfunc argument diagnostics
  2026-08-16  1:57 ` [PATCH bpf-next v1 06/14] bpf: Correct kfunc argument diagnostics Kumar Kartikeya Dwivedi
@ 2026-08-16  2:45   ` bot+bpf-ci
  2026-08-16  6:50     ` Eduard Zingerman
  2026-08-16  6:52   ` Eduard Zingerman
  1 sibling, 1 reply; 37+ messages in thread
From: bot+bpf-ci @ 2026-08-16  2:45 UTC (permalink / raw)
  To: memxor, bpf
  Cc: ast, andrii, daniel, eddyz87, emil, kkd, kernel-team, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 2131 bytes --]

> diff --git kernel/bpf/verifier.c kernel/bpf/verifier.c
> index 7ef324e384f4..da2ec0655b17 100644
> --- kernel/bpf/verifier.c
> +++ kernel/bpf/verifier.c

[ ... ]

> @@ -12653,12 +12653,12 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
>  		    !type_may_be_null(kf_arg_type)) {
>  			const char *expected_type;
>
> -			expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
> +			expected_type = bpf_diag_fmt_btf_type(env, btf, args[i].type);
>  			verbose(env, "Possibly NULL pointer passed to trusted %s\n",
>  				reg_arg_name(env, argno));
>  			bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
>  					      "Add a NULL check and call the kfunc only on the non-NULL path.",
> -					      "the pointer may be NULL, but this kfunc requires a non-NULL pointer to %s",
> +					      "the pointer may be NULL, but this kfunc requires a non-NULL value of type %s",
>  					      expected_type);
>  			return -EACCES;
>  		}

Switching from ref_id to args[i].type renders function pointer
parameters incorrectly. For kfuncs like bpf_task_work_schedule_signal()
that take a bpf_task_work_callback_t (which is itself a typedef to a
function pointer), btf_show_name() walks TYPEDEF -> PTR -> FUNC_PROTO,
collects the typedef name and adds one level of pointer indirection,
producing "bpf_task_work_callback_t *" instead of the correct parameter
type "bpf_task_work_callback_t".

For kfuncs like bpf_wq_set_callback() that take an unnamed function
pointer directly (PTR -> FUNC_PROTO), the FUNC_PROTO has no name, so
btf_show_name() produces the malformed "( *)".

Would it make sense to restrict the args[i].type formatting to object
pointers, or teach btf_show_name() not to add "*" for pointer typedefs
and unnamed FUNC_PROTO types? The other ref_id call sites later in the
same loop still use the pointee id, so the two conventions now coexist.


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31921026518

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context
  2026-08-16  1:57 ` [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context Kumar Kartikeya Dwivedi
@ 2026-08-16  2:45   ` bot+bpf-ci
  2026-08-16  7:58   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: bot+bpf-ci @ 2026-08-16  2:45 UTC (permalink / raw)
  To: memxor, bpf
  Cc: ast, andrii, daniel, eddyz87, emil, kkd, kernel-team, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 6777 bytes --]

> bpf: Correct Program Structure diagnostic context
>
> Program Structure reports have three attribution gaps. A missing jump table
> is reported at the beginning of its subprogram rather than at the gotox that
> needs the table, recursive-call details are present only in the legacy log,
> and the early subprogram-layout checks run before BTF line information is
> installed.
>
> Pass the failing gotox instruction into the jump-table lookup and include both
> ends of a recursive edge in the structured reason.
>
> The BTF validator needs the discovered subprogram boundaries together with
> the LD_ABS and tail-call properties collected during the layout scan. Split
> that property collection from layout validation, then validate BTF before
> reporting layout errors. This makes validated source information available to
> the jump-boundary and fallthrough reports without changing either check.
>
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>

All three attribution gaps described here come from a8f427835394 ("bpf:
Report Program Structure CFG errors"), which added the jt_from_subprog()
report at the subprogram start, the sort_subprogs_topo() reason without
the caller and callee, and the two check_subprogs() reports that ran
before line_info was validated.  Should this carry:

  Fixes: a8f427835394 ("bpf: Report Program Structure CFG errors")

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 3de9e4f617b6..d2f08c6612c6 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c

[ ... ]

> @@ -3038,9 +3057,10 @@ static int check_subprogs(struct bpf_verifier_env *env)
>  		}
>  next:
>  		if (i == subprog_end - 1) {
> -			/* to avoid fall-through from one subprog into another
> +			/*
> +			 * To avoid fall-through from one subprog into another,
>  			 * the last insn of the subprog should be either exit
> -			 * or unconditional jump back or bpf_throw call
> +			 * or unconditional jump back or bpf_throw call.
>  			 */
>  			if (code != (BPF_JMP | BPF_EXIT) &&
>  			    code != (BPF_JMP32 | BPF_JA) &&
>  			    code != (BPF_JMP | BPF_JA)) {

[ ... ]

> @@ -21124,17 +21145,19 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
>  	if (ret < 0)
>  		goto skip_full_check;
>  
> -	/* Discover all subprograms before validating their layout and BTF. */
> +	/* Discover all subprograms and collect the properties needed by BTF validation. */
>  	ret = add_subprogs(env);
>  	if (ret < 0)
>  		goto skip_full_check;
>  
> -	ret = check_subprogs(env);
> +	find_subprog_properties(env);
> +
> +	/* Validate BTF and apply CO-RE before reporting subprogram layout errors. */
> +	ret = bpf_check_btf_info(env, attr, uattr);
>  	if (ret < 0)
>  		goto skip_full_check;
>  
> -	/* Validate BTF against the complete subprogram layout and apply CO-RE. */
> -	ret = bpf_check_btf_info(env, attr, uattr);
> +	ret = check_subprogs(env);
>  	if (ret < 0)
>  		goto skip_full_check;

Can this reorder let CO-RE relocation patching read and write one
instruction past the end of prog->insnsi[]?

bpf_check_btf_info() applies CO-RE, and check_core_relo() only bounds the
relocation target against prog->len:

kernel/bpf/check_btf.c:check_core_relo() {
	...
	if (core_relo.insn_off % 8 || core_relo.insn_off / 8 >= prog->len) {
	...
	err = bpf_core_apply(&ctx, &core_relo, i,
			     &prog->insnsi[core_relo.insn_off / 8]);
	...
}

so insn_off / 8 == prog->len - 1 is accepted, and bpf_core_patch_insn()
gets a pointer to the very last instruction.  If that instruction has
class BPF_LD, both the poison path and the normal path touch insn[1]:

tools/lib/bpf/relo_core.c:bpf_core_patch_insn() {
	...
	if (res->poison) {
poison:
		if (is_ldimm64_insn(insn))
			bpf_core_poison_insn(prog_name, relo_idx, insn_idx + 1, insn + 1);
	...
	case BPF_LD: {
		...
		insn[0].imm = new_val;
		insn[1].imm = new_val >> 32;
	...
}

bpf_core_poison_insn() stores code, dst_reg, src_reg, off and imm, so
that is a full struct bpf_insn write to insnsi[prog->len].

Was this previously prevented by check_subprogs() running first?  Its
fall-through check fires for the last instruction of the program, since
add_subprogs() sets subprog[env->subprog_cnt].start = insn_cnt:

kernel/bpf/verifier.c:check_subprogs() {
	...
	if (i == subprog_end - 1) {
		if (code != (BPF_JMP | BPF_EXIT) &&
		    code != (BPF_JMP32 | BPF_JA) &&
		    code != (BPF_JMP | BPF_JA)) {
			verbose(env, "last insn is not an exit or jmp\n");
	...
}

BPF_LD | BPF_IMM | BPF_DW is 0x18 and is not in that set, so a program
whose final instruction is the first half of a truncated LD_IMM64 was
rejected with -EINVAL before any relocation ran.

After the reorder, does anything between add_subprogs() and
check_core_relo() still reject that program?  add_subprogs() and the new
find_subprog_properties() only read insn[i] in bounds, and the dedicated
"invalid bpf_ld_imm64 insn" guard in check_and_resolve_insns(), which is
the one that tests i == insn_cnt - 1, runs later than check_subprogs()
in either ordering.

The path looks short to reach: bpf_check_btf_info() only needs
func_info_cnt or line_info_cnt to be non-zero, and check_btf_func()
early-returns when nfuncs is 0, so func_info_cnt == 0 with
line_info_cnt == 1 skips the nr_linfo/subprog_cnt agreement checks
entirely.  A single BPF_CORE_TYPE_ID_LOCAL relocation then returns from
bpf_core_calc_relo_insn() with poison and validate both false, so the
insn[1].imm store happens with no check on the contents of
insnsi[prog->len].

Does the resulting write land outside the allocation?
bpf_prog_alloc_no_stats() rounds the allocation up to a page:

kernel/bpf/core.c:bpf_prog_alloc_no_stats() {
	...
	size = round_up(size, __PAGE_SIZE);
	fp = __vmalloc(size, gfp_flags);
	...
}

where size is bpf_prog_size(insn_cnt).  For an insn_cnt that makes
bpf_prog_size() an exact multiple of PAGE_SIZE, &insnsi[prog->len] is
the first byte of the vmalloc guard page and the store faults; for other
lengths it lands in the page-rounding slack, where it is an
out-of-bounds write that will not be reported.  insn_cnt comes straight
from the load attribute, so the faulting length is easy to pick.

Would it work to keep the last-instruction part of the layout check
before bpf_check_btf_info(), or to have check_core_relo() reject a
relocation targeting the final instruction when that instruction is
BPF_LD | BPF_IMM | BPF_DW?

For what it is worth, nothing in the four commits that follow this one
restores the ordering or adds a trailing-instruction guard.


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31921026518

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 03/14] bpf: Preserve R0 lineage across helper calls
  2026-08-16  2:30   ` bot+bpf-ci
@ 2026-08-16  6:12     ` Eduard Zingerman
  0 siblings, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  6:12 UTC (permalink / raw)
  To: bot+bpf-ci, memxor, bpf
  Cc: sashiko-bot, ast, andrii, daniel, emil, kkd, kernel-team,
	martin.lau, yonghong.song, clm, ihor.solodrai

On Sun, 2026-08-16 at 02:30 +0000, bot+bpf-ci@kernel.org wrote:
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index 5d0a2d3ef594..7ef324e384f4 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -11024,13 +11024,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
> > 
> >  	/* reset caller saved regs */
> >  	bpf_diag_record_caller_saved(env, regs);
> > +	bpf_diag_mod_begin(env, &regs[BPF_REG_0], NULL, BPF_DIAG_MOD_WRITE);
> >  	for (i = 0; i < CALLER_SAVED_REGS; i++) {
> >  		bpf_mark_reg_not_init(env, &regs[caller_saved[i]]);
> >  		check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK);
> >  	}
> >  	invalidate_outgoing_stack_args(env, cur_func(env));
> > 
> > -	bpf_diag_mod_begin(env, &regs[BPF_REG_0], NULL, BPF_DIAG_MOD_WRITE);
> >  	/* update return register (already marked as written above) */
> >  	ret_type = fn->ret_type;
> >  	ret_flag = type_flag(ret_type);
> 
> Does this produce the correct diagnostic message for void helpers? The
> new bpf_diag_mod_begin() is now opened unconditionally for all helpers,
> including those with RET_VOID. Because the snapshot is taken before the
> caller-saved clearing loop, a void helper now generates a history event
> with R0's real pre-call value as old and NOT_INIT as new, with reason
> BPF_DIAG_MOD_WRITE.

This is fine.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 01/14] bpf: Correct verifier diagnostic attribution for stack reads
  2026-08-16  1:57 ` [PATCH bpf-next v1 01/14] bpf: Correct verifier diagnostic attribution for stack reads Kumar Kartikeya Dwivedi
@ 2026-08-16  6:34   ` Eduard Zingerman
  0 siblings, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  6:34 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Sashiko, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:

...

> @@ -4079,13 +4106,13 @@ static int check_stack_read(struct bpf_verifier_env *env,
>  		tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
>  		verbose(env, "variable offset stack pointer cannot be passed into helper function; var_off=%s off=%d size=%d\n",
>  			tn_buf, off, size);
> -		reason = bpf_diag_fmt(env,
> -				      "The helper would access the stack through variable offset %s plus fixed offset %d and size %d. "
> -			"Helper stack memory arguments require a constant stack offset and a precise initialized range.",
> +		reason = bpf_diag_fmt(
> +			env, "The atomic operation would access the stack through variable offset %s plus fixed offset %d and size %d. "
> +			"Atomic stack operations require a constant stack offset and a precise initialized range.",

Relying on value_regno being -1 only for atomic operations is very fragile.
Let's at-least make a comment. Or make the wording neutral,
like "instruction variable offset access ..." (best).
Or check the actual instruction and vary wording.

>  			tn_buf, off, size);
>  		bpf_diag_memory(
> -			env, env->insn_idx, "variable stack access", reason,
> -			"Use a fixed stack offset for helper memory arguments, or copy the needed bytes into a fixed stack slot first.");
> +			env, env->insn_idx, "variable-offset atomic stack access", reason,
> +			"Use a fixed stack offset for the atomic operation, selecting the target stack slot on separate control-flow paths if necessary.");
>  		return -EACCES;
>  	}
>  	/* Variable offset is prohibited for unprivileged mode for simplicity

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 02/14] selftests/bpf: Test verifier stack-read diagnostic attribution
  2026-08-16  1:57 ` [PATCH bpf-next v1 02/14] selftests/bpf: Test verifier stack-read diagnostic attribution Kumar Kartikeya Dwivedi
  2026-08-16  2:45   ` bot+bpf-ci
@ 2026-08-16  6:35   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  6:35 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:
> Verifier diagnostics distinguish uninitialized stack bytes from opaque
> dynptr, iterator, and IRQ-flag state, and identify variable-offset atomic
> stack accesses without changing the existing verbose messages.
> 
> Add output assertions to the existing dynptr and iterator rejection
> cases. Add a direct IRQ-flag read and a variable-offset atomic stack
> access to cover the other classifications. Retain an assertion for the
> legacy helper-worded verbose message in the atomic test.
> 
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 03/14] bpf: Preserve R0 lineage across helper calls
  2026-08-16  1:57 ` [PATCH bpf-next v1 03/14] bpf: Preserve R0 lineage across helper calls Kumar Kartikeya Dwivedi
  2026-08-16  2:30   ` bot+bpf-ci
@ 2026-08-16  6:36   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  6:36 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Sashiko, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:
> check_helper_call() clears all caller-saved registers before taking the
> diagnostic snapshot of R0. This records NOT_INIT as the old state for every
> helper return and loses the lineage of the value held in R0 before the call.
> bpf_diag_record_caller_saved() deliberately skips R0 because the paired
> modification scope is responsible for it.
> 
> Open the R0 modification scope before clearing caller-saved registers,
> matching the kfunc, ld_abs, and subprogram call paths.
> 
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Link: https://lore.kernel.org/bpf/20260815073833.A93A91F000E9@smtp.kernel.org/
> Link: https://lore.kernel.org/bpf/48e6f021b89562f68850fe21ef8c78719819b04cf9c4e4f50bc791937d37ace8@mail.kernel.org/
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 04/14] bpf: Drop dead spill diagnostic condition
  2026-08-16  1:57 ` [PATCH bpf-next v1 04/14] bpf: Drop dead spill diagnostic condition Kumar Kartikeya Dwivedi
@ 2026-08-16  6:39   ` Eduard Zingerman
  0 siblings, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  6:39 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:
> diag_record_mod() appears to allow identical spill events to be suppressed,
> but diag_mod_keeps_lineage() only accepts register write events. The spill
> producer also supplies a stack target and an explicit origin, so a spill can
> never satisfy this conjunction.
> 
> Restrict the condition to writes to reflect the filter's actual contract and
> avoid suggesting that it applies to spills.
> 
> Link: https://lore.kernel.org/bpf/48e6f021b89562f68850fe21ef8c78719819b04cf9c4e4f50bc791937d37ace8@mail.kernel.org/
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---
>  kernel/bpf/diagnostics.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
> index 33b7d9e8e2c3..37ed22a764e0 100644
> --- a/kernel/bpf/diagnostics.c
> +++ b/kernel/bpf/diagnostics.c
> @@ -1531,8 +1531,7 @@ static void diag_record_mod(struct bpf_verifier_env *env, u32 insn_idx,
>  	} else if (diag_mod_insn_origin(env, insn_idx, &target, &event.mod.origin)) {
>  		event.mod.origin_valid = true;
>  	}
> -	if (old_reg && new_reg &&
> -	    (reason == BPF_DIAG_MOD_WRITE || reason == BPF_DIAG_MOD_SPILL) &&
> +	if (old_reg && new_reg && reason == BPF_DIAG_MOD_WRITE &&
>  	    !memcmp(&event.mod.old, &event.mod.new, sizeof(event.mod.old)) &&
>  	    !event.mod.origin_valid &&
>  	    diag_mod_keeps_lineage(env, &event))

Q: does this filter ever fires?
   The condition appears to be very narrow.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 05/14] bpf: Use canonical stack argument names in diagnostics
  2026-08-16  1:57 ` [PATCH bpf-next v1 05/14] bpf: Use canonical stack argument names in diagnostics Kumar Kartikeya Dwivedi
@ 2026-08-16  6:40   ` Eduard Zingerman
  0 siblings, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  6:40 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:
> The main diagnostic identifies the first outgoing stack slot as stack
> argument 1 and the sixth function argument. The causal history instead
> labels the same value as stack arg6, making it look like a different slot.
> 
> Render causal-history targets in the verifier's canonical stack-argument
> location form. The first outgoing slot is now shown as *(R11-8), matching
> reg_arg_name(), while the main diagnostic retains its fuller slot and
> ordinal description.
> 
> Link: https://lore.kernel.org/bpf/eb1be5327d136b7e5bd6d68e76fef6de20c40790.camel@gmail.com/
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 06/14] bpf: Correct kfunc argument diagnostics
  2026-08-16  2:45   ` bot+bpf-ci
@ 2026-08-16  6:50     ` Eduard Zingerman
  0 siblings, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  6:50 UTC (permalink / raw)
  To: bot+bpf-ci, memxor, bpf
  Cc: ast, andrii, daniel, emil, kkd, kernel-team, martin.lau,
	yonghong.song, clm, ihor.solodrai

On Sun, 2026-08-16 at 02:45 +0000, bot+bpf-ci@kernel.org wrote:
> > diff --git kernel/bpf/verifier.c kernel/bpf/verifier.c
> > index 7ef324e384f4..da2ec0655b17 100644
> > --- kernel/bpf/verifier.c
> > +++ kernel/bpf/verifier.c
> 
> [ ... ]
> 
> > @@ -12653,12 +12653,12 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
> >  		    !type_may_be_null(kf_arg_type)) {
> >  			const char *expected_type;
> > 
> > -			expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
> > +			expected_type = bpf_diag_fmt_btf_type(env, btf, args[i].type);
> >  			verbose(env, "Possibly NULL pointer passed to trusted %s\n",
> >  				reg_arg_name(env, argno));
> >  			bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
> >  					      "Add a NULL check and call the kfunc only on the non-NULL path.",
> > -					      "the pointer may be NULL, but this kfunc requires a non-NULL pointer to %s",
> > +					      "the pointer may be NULL, but this kfunc requires a non-NULL value of type %s",
> >  					      expected_type);
> >  			return -EACCES;
> >  		}
> 
> Switching from ref_id to args[i].type renders function pointer
> parameters incorrectly. For kfuncs like bpf_task_work_schedule_signal()
> that take a bpf_task_work_callback_t (which is itself a typedef to a
> function pointer), btf_show_name() walks TYPEDEF -> PTR -> FUNC_PROTO,
> collects the typedef name and adds one level of pointer indirection,
> producing "bpf_task_work_callback_t *" instead of the correct parameter
> type "bpf_task_work_callback_t".
> 
> For kfuncs like bpf_wq_set_callback() that take an unnamed function
> pointer directly (PTR -> FUNC_PROTO), the FUNC_PROTO has no name, so
> btf_show_name() produces the malformed "( *)".

Let's keep this as a follow-up; current patch is fine.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 06/14] bpf: Correct kfunc argument diagnostics
  2026-08-16  1:57 ` [PATCH bpf-next v1 06/14] bpf: Correct kfunc argument diagnostics Kumar Kartikeya Dwivedi
  2026-08-16  2:45   ` bot+bpf-ci
@ 2026-08-16  6:52   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  6:52 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:
> The Call Type Safety diagnostics mishandle three kfunc argument classes.
> 
> BTF type ID 0 represents void, but btf_show_name() also uses zero to end
> type traversal. A pointer that resolves to void therefore loses its pointee
> name and is rendered as "()". End traversal directly for concrete terminal
> types, but resolve referenced types before testing for ID zero, and name the
> void terminal type explicitly. Format the complete parameter pointer type
> for nullable kfunc arguments, so void pointers are reported as (void *).
> 
> Also add the missing structured report when an __szk memory-size argument is
> not a verifier-known constant. Describe the generic bpf_refcount_acquire()
> contract without deriving an object type from its void pointer prototype.
> 
> Link: https://lore.kernel.org/bpf/668871823f90f69896d3db27b56db2f53e481162.camel@gmail.com/
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

...

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 07/14] selftests/bpf: Test kfunc argument diagnostics
  2026-08-16  1:57 ` [PATCH bpf-next v1 07/14] selftests/bpf: Test " Kumar Kartikeya Dwivedi
@ 2026-08-16  6:53   ` Eduard Zingerman
  0 siblings, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  6:53 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:
> Extend existing negative kfunc programs to assert that BTF void is rendered
> as void and that variable __szk arguments receive a structured constant-size
> diagnostic.
> 
> Also pass a context pointer to bpf_refcount_acquire() and verify that the
> report describes the generic refcounted-object contract and the actual
> argument type. Retain the legacy verbose-message assertions.
> 
> Link: https://lore.kernel.org/bpf/3eda33675965763aa9b2e6a5784f32b34a6a83988a55fbea98b0dbd0cf3b088d@mail.kernel.org/
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

...

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 08/14] bpf: Report non-sleepable kfunc programs accurately
  2026-08-16  1:57 ` [PATCH bpf-next v1 08/14] bpf: Report non-sleepable kfunc programs accurately Kumar Kartikeya Dwivedi
  2026-08-16  2:30   ` bot+bpf-ci
@ 2026-08-16  7:32   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  7:32 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

...

> diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
> index 2c475174a640..df9259fa0ea7 100644
> --- a/kernel/bpf/diagnostics.c
> +++ b/kernel/bpf/diagnostics.c
> @@ -1083,7 +1083,9 @@ void bpf_diag_ctx_forbidden(struct bpf_verifier_env *env, u32 insn_idx,
>  	const char *constraint, *context;
>  	u32 depth;
>  
> -	if (env->cur_state->active_rcu_locks)
> +	if (!env->cur_state->in_sleepable)
> +		ctx_kind = BPF_DIAG_CONTEXT_NONE;

Let's do what bot suggests and rely on the final 'else' instead of
adding this branch.

> +	else if (env->cur_state->active_rcu_locks)
>  		ctx_kind = BPF_DIAG_CONTEXT_RCU;
>  	else if (env->cur_state->active_preempt_locks)
>  		ctx_kind = BPF_DIAG_CONTEXT_PREEMPT;
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index da2ec0655b17..3de9e4f617b6 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -9912,7 +9912,7 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
>  				sub_name, non_sleepable_context_description(env));
>  			operation = bpf_diag_fmt(env, "sleepable global function %s()", sub_name);
>  			bpf_diag_ctx_forbidden(env, *insn_idx, operation,
> -				"Move the call outside the critical section, or use a non-sleepable function.");
> +				"Call the function from a sleepable program outside any critical section, or use a non-sleepable function.");
>  			return -EINVAL;
>  		}
>  
> @@ -10731,6 +10731,8 @@ static inline bool in_sleepable_context(struct bpf_verifier_env *env)
>  
>  static const char *non_sleepable_context_description(struct bpf_verifier_env *env)
>  {
> +	if (!in_sleepable(env))
> +		return "non-sleepable prog";

Let's drop this hunk and rely on the `return "non-sleepable context"`.
Not sure if we need to change 'prog' to 'context', tbh.

>  	if (env->cur_state->active_rcu_locks)
>  		return "rcu_read_lock region";
>  	if (env->cur_state->active_preempt_locks)
> @@ -10739,7 +10741,7 @@ static const char *non_sleepable_context_description(struct bpf_verifier_env *en
>  		return "IRQ-disabled region";
>  	if (env->cur_state->active_locks)
>  		return "lock region";
> -	return "non-sleepable prog";
> +	return "non-sleepable context";
>  }
>  
>  static int release_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,

...

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 09/14] selftests/bpf: Test non-sleepable kfunc context
  2026-08-16  1:57 ` [PATCH bpf-next v1 09/14] selftests/bpf: Test non-sleepable kfunc context Kumar Kartikeya Dwivedi
  2026-08-16  2:30   ` bot+bpf-ci
@ 2026-08-16  7:37   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  7:37 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:

...

> --- a/tools/testing/selftests/bpf/progs/preempt_lock.c
> +++ b/tools/testing/selftests/bpf/progs/preempt_lock.c
> @@ -6,6 +6,8 @@
>  #include "bpf_experimental.h"
>  
>  extern int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void *unsafe_ptr__ign, u64 flags) __weak __ksym;
> +extern void bpf_rcu_read_lock(void) __ksym;
> +extern void bpf_rcu_read_unlock(void) __ksym;
>  
>  SEC("?tc")
>  __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_preempt_disable-ed region")
> @@ -127,6 +129,19 @@ int preempt_sleepable_kfunc(void *ctx)
>  	return 0;
>  }
>  
> +SEC("?fentry/" SYS_PREFIX "sys_getpgid")
> +__failure __msg("program must be sleepable to call sleepable kfunc bpf_copy_from_user_str")
> +__msg("cannot be used in non-sleepable program")
> +int non_sleepable_kfunc_in_rcu(void *ctx)
> +{
> +	u32 data;
> +
> +	bpf_rcu_read_lock();
> +	bpf_copy_from_user_str(&data, sizeof(data), NULL, 0);
> +	bpf_rcu_read_unlock();
> +	return 0;
> +}
> +

Tbh, I'd just add two tests: one with a call inside rcu, another from
a program context and match new messages. We are going to switch away
from those anyway.

>  int __noinline preempt_global_subprog(void)
>  {
>  	preempt_balance_subprog();

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context
  2026-08-16  1:57 ` [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context Kumar Kartikeya Dwivedi
  2026-08-16  2:45   ` bot+bpf-ci
@ 2026-08-16  7:58   ` Eduard Zingerman
  1 sibling, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  7:58 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 3de9e4f617b6..d2f08c6612c6 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -2995,15 +2995,13 @@ static int add_kfuncs(struct bpf_verifier_env *env)
>  	return 0;
>  }
>  
> -static int check_subprogs(struct bpf_verifier_env *env)
> +static void find_subprog_properties(struct bpf_verifier_env *env)
>  {
> -	int i, subprog_start, subprog_end, off, cur_subprog = 0;
> +	int i, subprog_end, cur_subprog = 0;
>  	struct bpf_subprog_info *subprog = env->subprog_info;
>  	struct bpf_insn *insn = env->prog->insnsi;
>  	int insn_cnt = env->prog->len;
>  
> -	/* now check that all jumps are within the same subprog */
> -	subprog_start = subprog[cur_subprog].start;
>  	subprog_end = subprog[cur_subprog + 1].start;
>  	for (i = 0; i < insn_cnt; i++) {
>  		u8 code = insn[i].code;
> @@ -3017,6 +3015,27 @@ static int check_subprogs(struct bpf_verifier_env *env)
>  		if (BPF_CLASS(code) == BPF_LD &&
>  		    (BPF_MODE(code) == BPF_ABS || BPF_MODE(code) == BPF_IND))
>  			subprog[cur_subprog].has_ld_abs = true;
> +		if (i == subprog_end - 1) {
> +			cur_subprog++;
> +			if (cur_subprog < env->subprog_cnt)
> +				subprog_end = subprog[cur_subprog + 1].start;
> +		}

Nit: in situations like this doing two nested loops reads much better:
     for each subprog:
       for insn from star to end:
         ...

> +	}
> +}

...

> @@ -3126,8 +3146,9 @@ static int sort_subprogs_topo(struct bpf_verifier_env *env)
>  					bpf_diag_program_structure(
>  						env, idx, "recursive subprogram call",
>  						"Rewrite the recursion as an explicit bounded loop, or split the logic so subprogram calls do not form a cycle.",
> -						"This bpf2bpf call would make the subprogram call graph recursive. "
> -						"The verifier requires a finite, acyclic call graph so it can bound stack depth and analysis.");
> +						"The call from %s() to %s() would make the subprogram call graph recursive. "
> +						"The verifier requires a finite, acyclic call graph so it can bound stack depth and analysis.",
> +						bpf_subprog_name(env, cur), bpf_subprog_name(env, callee));

Nit: I'd drop this hunk, I think that initial suggestion from the bot
     was bogus. What would be really helpful is to draw the whole
     cycle, but we don't have such info here.

>  					ret = -EINVAL;
>  					goto out;
>  				}

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 11/14] bpf: Preserve source attribution without source text
  2026-08-16  1:57 ` [PATCH bpf-next v1 11/14] bpf: Preserve source attribution without source text Kumar Kartikeya Dwivedi
@ 2026-08-16  8:01   ` Eduard Zingerman
  0 siblings, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  8:01 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:
> GCC emits BTF line records with a file name and line number, but leaves the
> source line string empty. bpf_diag_source() currently treats that empty string
> as if the complete line record were unavailable, so diagnostics fall back to
> an instruction number and discard the function, file, and line attribution.
> 
> Print the available source location before deciding whether source context can
> be rendered. When source text is absent, omit only the source context and retain
> the diagnostic annotation and instruction context.
> 
> Fixes: b9c5d822f677 ("bpf: Add source and instruction diagnostic context")
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

...

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 12/14] selftests/bpf: Test Program Structure diagnostic context
  2026-08-16  1:57 ` [PATCH bpf-next v1 12/14] selftests/bpf: Test Program Structure diagnostic context Kumar Kartikeya Dwivedi
@ 2026-08-16  8:06   ` Eduard Zingerman
  0 siblings, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  8:06 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:
> Exercise each corrected Program Structure report. Place a missing-table gotox
> after another instruction so its attribution differs from the subprogram
> start, and assert that the recursive-call reason names both ends of the edge.
> 
> Add malformed subprogram layouts for a branch crossing a subprogram boundary
> and a subprogram that falls through its end. Both cases carry BTF line records
> and assert that their structured reports include the corresponding source
> function and file.
> 
> Link: https://lore.kernel.org/bpf/cf2f420c2b21de440a7dc51b1565c0f06d4b539640ee5c03384e5d77bcfb5686@mail.kernel.org/
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH bpf-next v1 13/14] bpf: Distinguish function references in policy diagnostics
  2026-08-16  1:57 ` [PATCH bpf-next v1 13/14] bpf: Distinguish function references in policy diagnostics Kumar Kartikeya Dwivedi
@ 2026-08-16  8:09   ` Eduard Zingerman
  0 siblings, 0 replies; 37+ messages in thread
From: Eduard Zingerman @ 2026-08-16  8:09 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi, bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Emil Tsalapatis, kkd, kernel-team

On Sun, 2026-08-16 at 03:57 +0200, Kumar Kartikeya Dwivedi wrote:
> add_subprogs() rejects both BPF-to-BPF calls and BPF_PSEUDO_FUNC loads for
> unprivileged programs. The latter loads a subprogram address for use as a
> callback, but its Policy report currently describes it as a function call and
> suggests avoiding calls that the program does not contain.
> 
> Select the operation and suggestion from the instruction kind. Preserve the
> existing call wording for BPF_PSEUDO_CALL, and describe BPF_PSEUDO_FUNC as a
> BPF function reference.
> 
> Link: https://lore.kernel.org/bpf/d02e6a6d3b2dc43a207b8ba836ce62497b250dede9252e7409c5212201c794b7@mail.kernel.org/
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---

As you see fit, but I think the original bot complaint was too picky. I'd drop this patch.

...

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2026-08-16  8:09 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-16  1:57 [PATCH bpf-next v1 00/14] Follow ups for verifier errors set Kumar Kartikeya Dwivedi
2026-08-16  1:57 ` [PATCH bpf-next v1 01/14] bpf: Correct verifier diagnostic attribution for stack reads Kumar Kartikeya Dwivedi
2026-08-16  6:34   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 02/14] selftests/bpf: Test verifier stack-read diagnostic attribution Kumar Kartikeya Dwivedi
2026-08-16  2:45   ` bot+bpf-ci
2026-08-16  6:35   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 03/14] bpf: Preserve R0 lineage across helper calls Kumar Kartikeya Dwivedi
2026-08-16  2:30   ` bot+bpf-ci
2026-08-16  6:12     ` Eduard Zingerman
2026-08-16  6:36   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 04/14] bpf: Drop dead spill diagnostic condition Kumar Kartikeya Dwivedi
2026-08-16  6:39   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 05/14] bpf: Use canonical stack argument names in diagnostics Kumar Kartikeya Dwivedi
2026-08-16  6:40   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 06/14] bpf: Correct kfunc argument diagnostics Kumar Kartikeya Dwivedi
2026-08-16  2:45   ` bot+bpf-ci
2026-08-16  6:50     ` Eduard Zingerman
2026-08-16  6:52   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 07/14] selftests/bpf: Test " Kumar Kartikeya Dwivedi
2026-08-16  6:53   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 08/14] bpf: Report non-sleepable kfunc programs accurately Kumar Kartikeya Dwivedi
2026-08-16  2:30   ` bot+bpf-ci
2026-08-16  7:32   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 09/14] selftests/bpf: Test non-sleepable kfunc context Kumar Kartikeya Dwivedi
2026-08-16  2:30   ` bot+bpf-ci
2026-08-16  7:37   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context Kumar Kartikeya Dwivedi
2026-08-16  2:45   ` bot+bpf-ci
2026-08-16  7:58   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 11/14] bpf: Preserve source attribution without source text Kumar Kartikeya Dwivedi
2026-08-16  8:01   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 12/14] selftests/bpf: Test Program Structure diagnostic context Kumar Kartikeya Dwivedi
2026-08-16  8:06   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 13/14] bpf: Distinguish function references in policy diagnostics Kumar Kartikeya Dwivedi
2026-08-16  8:09   ` Eduard Zingerman
2026-08-16  1:57 ` [PATCH bpf-next v1 14/14] selftests/bpf: Test pseudo-function " Kumar Kartikeya Dwivedi
2026-08-16  2:45   ` bot+bpf-ci

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.