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 v2 03/17] bpf: Add verifier diagnostic event log
Date: Fri, 19 Jun 2026 22:59:16 +0200 [thread overview]
Message-ID: <20260619205934.1312876-4-memxor@gmail.com> (raw)
In-Reply-To: <20260619205934.1312876-1-memxor@gmail.com>
Add an environment-owned diagnostic history for verifier reports. Event
payloads keep the user-facing branch history shape, but storage lives in
bpf_verifier_env instead of verifier states so explored states do not copy
diagnostic buffers.
Grow the event array as entries are appended and keep saved positions as array
indices. Later patches can truncate back to those positions when verifier
search backtracks. Add the branch event renderer now, while leaving branch
recording to the follow-up patch that wires active-path pruning.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
kernel/bpf/diagnostics.c | 182 +++++++++++++++++++++++++++++++++------
kernel/bpf/diagnostics.h | 19 ++++
2 files changed, 174 insertions(+), 27 deletions(-)
diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
index 534a7bc58781..fa5a25b314a0 100644
--- a/kernel/bpf/diagnostics.c
+++ b/kernel/bpf/diagnostics.c
@@ -69,6 +69,12 @@ struct bpf_diag_insn_ctx {
struct bpf_diag_insn_buf buf;
};
+struct bpf_diag_log {
+ struct bpf_diag_history_event *events;
+ u32 cnt;
+ u32 cap;
+};
+
struct bpf_diag_scratch {
char str[BPF_DIAG_SCRATCH_STR_CNT][BPF_DIAG_SCRATCH_STR_LEN];
struct bpf_diag_source source;
@@ -77,6 +83,7 @@ struct bpf_diag_scratch {
};
struct bpf_diag {
+ struct bpf_diag_log log;
struct bpf_diag_scratch scratch;
};
@@ -155,6 +162,51 @@ const char *bpf_diag_scratch_printf(struct bpf_verifier_env *env,
return buf;
}
+static void bpf_diag_write(struct bpf_verifier_env *env, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!bpf_diag_enabled(env))
+ return;
+
+ va_start(args, fmt);
+ bpf_verifier_vlog(&env->log, fmt, args);
+ va_end(args);
+}
+
+static struct bpf_diag_log *bpf_diag_event_log(struct bpf_verifier_env *env)
+{
+ struct bpf_diag *diag = bpf_diag_env(env);
+
+ return diag ? &diag->log : NULL;
+}
+
+u64 bpf_diag_event_log_pos(struct bpf_verifier_env *env)
+{
+ struct bpf_diag *diag = bpf_diag_env(env);
+
+ if (!diag)
+ return 0;
+ return diag->log.cnt;
+}
+
+void bpf_diag_event_log_reset(struct bpf_verifier_env *env, u64 pos)
+{
+ struct bpf_diag *diag = env->diag;
+ struct bpf_diag_log *log;
+ u64 end;
+
+ if (!diag)
+ return;
+
+ log = &diag->log;
+ end = log->cnt;
+ if (WARN_ON_ONCE(pos > end))
+ pos = end;
+
+ log->cnt = pos;
+}
+
void bpf_diag_free(struct bpf_verifier_env *env)
{
struct bpf_diag *diag = env->diag;
@@ -162,21 +214,46 @@ void bpf_diag_free(struct bpf_verifier_env *env)
if (!diag)
return;
+ kfree(diag->log.events);
kfree(diag);
env->diag = NULL;
}
-static void bpf_diag_log(struct bpf_verifier_env *env, const char *fmt, ...)
+static const struct bpf_diag_history_event *
+bpf_diag_history_event(const struct bpf_diag_log *log, u32 idx)
{
- va_list args;
+ return &log->events[idx];
+}
- if (!bpf_diag_enabled(env))
+static void bpf_diag_append_history(struct bpf_verifier_env *env,
+ const struct bpf_diag_history_event *event)
+{
+ struct bpf_diag_history_event *events;
+ struct bpf_diag_log *log;
+ u32 cap;
+
+ log = bpf_diag_event_log(env);
+ if (!log)
return;
- va_start(args, fmt);
- bpf_verifier_vlog(&env->log, fmt, args);
- va_end(args);
+ if (log->cnt < log->cap) {
+ log->events[log->cnt++] = *event;
+ return;
+ }
+
+ cap = log->cap ? log->cap * 2 : 64;
+ if (cap < log->cap)
+ return;
+
+ events = krealloc_array(log->events, cap, sizeof(*events),
+ GFP_KERNEL_ACCOUNT);
+ if (!events)
+ return;
+ log->events = events;
+ log->cap = cap;
+ log->events[log->cnt++] = *event;
}
+
static void bpf_diag_print_wrapped_prefixed(struct bpf_verifier_env *env,
const char *first_prefix,
const char *next_prefix,
@@ -203,7 +280,7 @@ static void bpf_diag_print_wrapped_prefixed(struct bpf_verifier_env *env,
last_space > 0)
len = last_space;
- bpf_diag_log(env, "%s%.*s\n", prefix, len, line);
+ bpf_diag_write(env, "%s%.*s\n", prefix, len, line);
text = line + len;
while (*text == ' ')
@@ -232,8 +309,8 @@ static void bpf_diag_vprint_indented(struct bpf_verifier_env *env,
buf = kvasprintf(GFP_KERNEL_ACCOUNT, fmt, args);
if (!buf) {
- bpf_diag_log(env, "%s<failed to allocate diagnostic text>\n",
- BPF_DIAG_TEXT_INDENT);
+ bpf_diag_write(env, "%s<failed to allocate diagnostic text>\n",
+ BPF_DIAG_TEXT_INDENT);
return;
}
@@ -513,13 +590,14 @@ static void bpf_diag_print_source_insn_line(struct bpf_verifier_env *env,
source_prefix, source_line_width,
line->line_num, line->line);
- bpf_diag_log(env, " %-*s%*s", BPF_DIAG_SOURCE_LANE_WIDTH,
- source_lane, BPF_DIAG_COLUMN_GAP, "");
+ bpf_diag_write(env, " %-*s%*s", BPF_DIAG_SOURCE_LANE_WIDTH,
+ source_lane, BPF_DIAG_COLUMN_GAP, "");
if (diag_insn->valid)
- bpf_diag_log(env, "%s%*d | %s",
- diag_insn->idx == focus_insn_idx ? ">>> " : " ",
- insn_width, diag_insn->idx, diag_insn->text);
- bpf_diag_log(env, "\n");
+ bpf_diag_write(env, "%s%*d | %s",
+ diag_insn->idx == focus_insn_idx ?
+ ">>> " : " ", insn_width, diag_insn->idx,
+ diag_insn->text);
+ bpf_diag_write(env, "\n");
}
void bpf_diag_report_header(struct bpf_verifier_env *env,
@@ -534,13 +612,13 @@ void bpf_diag_report_header(struct bpf_verifier_env *env,
problem = problem ?: "";
if (!problem[0]) {
- bpf_diag_log(env, "\nVerification failed: %s\n", category);
+ bpf_diag_write(env, "\nVerification failed: %s\n", category);
return;
}
first = toupper(problem[0]);
- bpf_diag_log(env, "\nVerification failed: %s: %c%s\n", category,
- first, problem + 1);
+ bpf_diag_write(env, "\nVerification failed: %s: %c%s\n", category,
+ first, problem + 1);
}
static void bpf_diag_report_reason(struct bpf_verifier_env *env,
@@ -554,7 +632,7 @@ static void bpf_diag_report_section(struct bpf_verifier_env *env,
if (!bpf_diag_enabled(env))
return;
- bpf_diag_log(env, "\n%s:\n", title);
+ bpf_diag_write(env, "\n%s:\n", title);
}
static void bpf_diag_report_reason(struct bpf_verifier_env *env,
@@ -585,7 +663,7 @@ static void bpf_diag_report_suggestion(struct bpf_verifier_env *env,
va_start(args, fmt);
bpf_diag_vprint_indented(env, fmt, args);
va_end(args);
- bpf_diag_log(env, "\n");
+ bpf_diag_write(env, "\n");
}
static void bpf_diag_print_source_annotation(struct bpf_verifier_env *env,
@@ -610,8 +688,8 @@ static void bpf_diag_print_source_annotation(struct bpf_verifier_env *env,
line_width - 8));
text = kasprintf(GFP_KERNEL_ACCOUNT, "%s: %s", label, msg);
if (!text) {
- bpf_diag_log(env, " %*s | %*s^-- %s\n",
- line_width + 4, "", indent, "", label);
+ bpf_diag_write(env, " %*s | %*s^-- %s\n",
+ line_width + 4, "", indent, "", label);
return;
}
@@ -660,18 +738,18 @@ void bpf_diag_report_source(struct bpf_verifier_env *env, u32 insn_idx,
memset(diag_insn, 0, sizeof(scratch->insns));
if (!bpf_diag_get_source(env, insn_idx, src)) {
- bpf_diag_log(env, " insn %u\n", insn_idx);
+ bpf_diag_write(env, " insn %u\n", insn_idx);
bpf_diag_print_source_annotation(env, 0, 0, label, msg);
goto out_free_msg;
}
func = bpf_diag_func_name(env, insn_idx);
if (func && *func)
- bpf_diag_log(env, " %s @ %s:%d:%d\n", func, src->file,
- src->line_num, src->line_col);
+ bpf_diag_write(env, " %s @ %s:%d:%d\n", func, src->file,
+ src->line_num, src->line_col);
else
- bpf_diag_log(env, " %s:%d:%d\n", src->file, src->line_num,
- src->line_col);
+ bpf_diag_write(env, " %s:%d:%d\n", src->file, src->line_num,
+ src->line_col);
start_line = src->line_num - BPF_DIAG_SOURCE_CONTEXT;
end_line = src->line_num + BPF_DIAG_SOURCE_CONTEXT;
@@ -704,3 +782,53 @@ void bpf_diag_report_source(struct bpf_verifier_env *env, u32 insn_idx,
out_free_msg:
kfree(msg);
}
+
+void bpf_diag_record_branch(struct bpf_verifier_env *env, u32 insn_idx,
+ bool cond_true)
+{
+ struct bpf_diag_history_event event = {
+ .insn_idx = insn_idx,
+ .kind = BPF_DIAG_HISTORY_BRANCH,
+ .branch.cond_true = cond_true,
+ };
+
+ bpf_diag_append_history(env, &event);
+}
+
+void bpf_diag_print_history(struct bpf_verifier_env *env)
+{
+ const struct bpf_diag_history_event *event;
+ const struct bpf_diag_log *log;
+ bool printed = false;
+ u32 i;
+
+ bpf_diag_report_section(env, "Causal path");
+
+ if (!env->diag) {
+ bpf_diag_write(env, " no recorded diagnostic events on this path\n");
+ return;
+ }
+ log = &env->diag->log;
+
+ for (i = 0; i < log->cnt; i++) {
+ event = bpf_diag_history_event(log, i);
+
+ switch (event->kind) {
+ case BPF_DIAG_HISTORY_BRANCH:
+ bpf_diag_report_source(env, event->insn_idx, "branch",
+ "explored as %s, goto %s",
+ event->branch.cond_true ? "true" :
+ "false",
+ event->branch.cond_true ? "followed" :
+ "not followed");
+ printed = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!printed)
+ bpf_diag_write(env,
+ " no retained diagnostic events on this path\n");
+}
diff --git a/kernel/bpf/diagnostics.h b/kernel/bpf/diagnostics.h
index 7f1380508789..4bc44be757c4 100644
--- a/kernel/bpf/diagnostics.h
+++ b/kernel/bpf/diagnostics.h
@@ -9,6 +9,20 @@
struct bpf_verifier_env;
+struct bpf_diag_history_event {
+ u32 insn_idx;
+ u8 kind;
+ union {
+ struct {
+ bool cond_true;
+ } branch;
+ };
+};
+
+enum bpf_diag_history_kind {
+ BPF_DIAG_HISTORY_BRANCH,
+};
+
bool bpf_diag_enabled(const struct bpf_verifier_env *env);
char *bpf_diag_scratch_buf(struct bpf_verifier_env *env,
unsigned int slot, size_t *size);
@@ -19,11 +33,16 @@ const char *bpf_diag_scratch_printf(struct bpf_verifier_env *env,
unsigned int slot,
const char *fmt, ...)
__printf(3, 4);
+u64 bpf_diag_event_log_pos(struct bpf_verifier_env *env);
+void bpf_diag_event_log_reset(struct bpf_verifier_env *env, u64 pos);
void bpf_diag_free(struct bpf_verifier_env *env);
void bpf_diag_report_header(struct bpf_verifier_env *env,
const char *category, const char *problem);
void bpf_diag_report_source(struct bpf_verifier_env *env, u32 insn_idx,
const char *label, const char *fmt, ...)
__printf(4, 5);
+void bpf_diag_record_branch(struct bpf_verifier_env *env, u32 insn_idx,
+ bool cond_true);
+void bpf_diag_print_history(struct bpf_verifier_env *env);
#endif /* __BPF_DIAGNOSTICS_H */
--
2.53.0
next prev parent reply other threads:[~2026-06-19 20:59 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-19 20:59 [PATCH bpf-next v2 00/17] Redesign Verification Errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 01/17] bpf: Add verifier diagnostics report helpers Kumar Kartikeya Dwivedi
2026-06-19 21:09 ` sashiko-bot
2026-06-19 20:59 ` [PATCH bpf-next v2 02/17] bpf: Add source and instruction diagnostic context Kumar Kartikeya Dwivedi
2026-06-19 21:46 ` bot+bpf-ci
2026-06-19 20:59 ` Kumar Kartikeya Dwivedi [this message]
2026-06-19 21:46 ` [PATCH bpf-next v2 03/17] bpf: Add verifier diagnostic event log bot+bpf-ci
2026-06-19 20:59 ` [PATCH bpf-next v2 04/17] bpf: Prune verifier diagnostics on backtracking Kumar Kartikeya Dwivedi
2026-06-19 21:46 ` bot+bpf-ci
2026-06-19 20:59 ` [PATCH bpf-next v2 05/17] bpf: Track verifier register diagnostic events Kumar Kartikeya Dwivedi
2026-06-19 21:18 ` sashiko-bot
2026-06-19 23:35 ` Alexei Starovoitov
2026-06-19 20:59 ` [PATCH bpf-next v2 06/17] bpf: Track verifier reference " Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 07/17] bpf: Track verifier context " Kumar Kartikeya Dwivedi
2026-06-19 21:13 ` sashiko-bot
2026-06-19 21:19 ` Kumar Kartikeya Dwivedi
2026-06-19 21:46 ` bot+bpf-ci
2026-06-19 20:59 ` [PATCH bpf-next v2 08/17] bpf: Report Register Type Safety errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 09/17] bpf: Report Memory Safety bounds errors Kumar Kartikeya Dwivedi
2026-06-19 21:46 ` bot+bpf-ci
2026-06-19 23:40 ` Alexei Starovoitov
2026-06-19 20:59 ` [PATCH bpf-next v2 10/17] bpf: Report Resource Lifetime reference leaks Kumar Kartikeya Dwivedi
2026-06-19 21:12 ` sashiko-bot
2026-06-19 23:42 ` Alexei Starovoitov
2026-06-19 20:59 ` [PATCH bpf-next v2 11/17] bpf: Report Call Type Safety argument errors Kumar Kartikeya Dwivedi
2026-06-19 21:47 ` bot+bpf-ci
2026-06-19 20:59 ` [PATCH bpf-next v2 12/17] bpf: Report Execution Context Safety errors Kumar Kartikeya Dwivedi
2026-06-19 21:19 ` sashiko-bot
2026-06-19 23:44 ` Alexei Starovoitov
2026-06-19 20:59 ` [PATCH bpf-next v2 13/17] bpf: Report Program Structure CFG errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 14/17] bpf: Report Policy helper and kfunc errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 15/17] bpf: Report Verifier Limit errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 16/17] bpf: Report Verifier Internal errors Kumar Kartikeya Dwivedi
2026-06-19 20:59 ` [PATCH bpf-next v2 17/17] bpf: Gate verifier diagnostics on log level Kumar Kartikeya Dwivedi
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=20260619205934.1312876-4-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox