All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andrii@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Emil Tsalapatis <emil@etsalapatis.com>,
	kkd@meta.com, kernel-team@meta.com
Subject: [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context
Date: Sun, 16 Aug 2026 03:57:38 +0200	[thread overview]
Message-ID: <20260816015746.2632990-11-memxor@gmail.com> (raw)
In-Reply-To: <20260816015746.2632990-1-memxor@gmail.com>

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


  parent reply	other threads:[~2026-08-16  1:58 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Kumar Kartikeya Dwivedi [this message]
2026-08-16  2:45   ` [PATCH bpf-next v1 10/14] bpf: Correct Program Structure diagnostic context 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260816015746.2632990-11-memxor@gmail.com \
    --to=memxor@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=kernel-team@meta.com \
    --cc=kkd@meta.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.