All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Eduard Zingerman <eddyz87@gmail.com>,
	Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andrii@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Emil Tsalapatis <emil@etsalapatis.com>,
	kkd@meta.com, kernel-team@meta.com
Subject: [PATCH bpf-next v3 06/17] bpf: Track verifier reference diagnostic events
Date: Mon, 13 Jul 2026 17:38:55 +0200	[thread overview]
Message-ID: <20260713153910.2556007-7-memxor@gmail.com> (raw)
In-Reply-To: <20260713153910.2556007-1-memxor@gmail.com>

Add reference acquire and release events to diagnostic history so Resource
Lifetime Safety reports can show the lifetime of a specific reference id along
the path.

Record acquisitions after the verifier assigns the reference id. Record
releases only after release_reference_nomark() succeeds, including the
kptr_xchg RCU conversion path and owning-to-non-owning conversion path that
consume an owning reference.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/diagnostics.c | 63 ++++++++++++++++++++++++++++++++++++++++
 kernel/bpf/diagnostics.h |  2 ++
 kernel/bpf/verifier.c    | 32 +++++++++++++++-----
 3 files changed, 90 insertions(+), 7 deletions(-)

diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
index 1a45ec926c71..4c1fbabf98d1 100644
--- a/kernel/bpf/diagnostics.c
+++ b/kernel/bpf/diagnostics.c
@@ -50,6 +50,8 @@ struct bpf_diag_reg_snapshot {
 enum bpf_diag_history_kind {
 	BPF_DIAG_HISTORY_BRANCH,
 	BPF_DIAG_HISTORY_MOD,
+	BPF_DIAG_HISTORY_REF_ACQUIRE,
+	BPF_DIAG_HISTORY_REF_RELEASE,
 };
 
 struct bpf_diag_event_hdr {
@@ -75,6 +77,10 @@ struct bpf_diag_history_event {
 			u8 reason;
 			bool origin_valid;
 		} mod;
+		struct {
+			struct bpf_diag_event_hdr hdr;
+			u32 ref_id;
+		} ref;
 	};
 };
 
@@ -82,6 +88,7 @@ enum bpf_diag_history_scope {
 	BPF_DIAG_HISTORY_SCOPE_ALL,
 	BPF_DIAG_HISTORY_SCOPE_REG,
 	BPF_DIAG_HISTORY_SCOPE_STACK_ARG,
+	BPF_DIAG_HISTORY_SCOPE_REF,
 };
 
 struct bpf_diag_history_opts {
@@ -89,6 +96,7 @@ struct bpf_diag_history_opts {
 	u32 frameno;
 	int regno;
 	int stack_arg_slot;
+	u32 ref_id;
 };
 
 static void diag_print_history(struct bpf_verifier_env *env,
@@ -923,6 +931,31 @@ void bpf_diag_record_mod(struct bpf_verifier_env *env, u32 insn_idx,
 	diag_append_history(env, &event);
 }
 
+static void diag_record_ref(struct bpf_verifier_env *env, u32 insn_idx, u8 kind, u32 ref_id)
+{
+	struct bpf_diag_history_event event = {
+		.ref = {
+			.hdr = {
+				.insn_idx = insn_idx,
+				.kind = kind,
+			},
+			.ref_id = ref_id,
+		},
+	};
+
+	diag_append_history(env, &event);
+}
+
+void bpf_diag_record_ref_acquire(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id)
+{
+	diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_ACQUIRE, ref_id);
+}
+
+void bpf_diag_record_ref_release(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id)
+{
+	diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_RELEASE, ref_id);
+}
+
 struct bpf_diag_history_filter {
 	const struct bpf_diag_history_opts *opts;
 	unsigned long *lineage;
@@ -1074,11 +1107,23 @@ static int diag_history_start_idx(const struct bpf_diag_log *log,
 				  const struct bpf_diag_history_filter *filter)
 {
 	const struct bpf_diag_history_opts *opts = filter->opts;
+	int i;
 
 	if (!opts || opts->scope == BPF_DIAG_HISTORY_SCOPE_ALL)
 		return 0;
 	if (filter->lineage_valid)
 		return filter->lineage_start;
+	if (opts->scope != BPF_DIAG_HISTORY_SCOPE_REF)
+		return 0;
+
+	for (i = log->cnt; i > 0; i--) {
+		const struct bpf_diag_history_event *event;
+
+		event = diag_history_event(log, i - 1);
+		if (event->kind == BPF_DIAG_HISTORY_REF_ACQUIRE &&
+		    event->ref.ref_id == opts->ref_id)
+			return i - 1;
+	}
 
 	return 0;
 }
@@ -1096,6 +1141,10 @@ static bool diag_history_event_visible(const struct bpf_diag_history_event *even
 		return true;
 	case BPF_DIAG_HISTORY_MOD:
 		return filter->lineage_valid && test_bit(idx, filter->lineage);
+	case BPF_DIAG_HISTORY_REF_ACQUIRE:
+	case BPF_DIAG_HISTORY_REF_RELEASE:
+		return opts->scope == BPF_DIAG_HISTORY_SCOPE_REF &&
+		       event->ref.ref_id == opts->ref_id;
 	default:
 		return false;
 	}
@@ -1383,6 +1432,16 @@ static void diag_print_mod(struct bpf_verifier_env *env, const struct bpf_diag_h
 			       fmt->old_buf, fmt->new_buf);
 }
 
+static void diag_print_ref_event(struct bpf_verifier_env *env,
+				 const struct bpf_diag_history_event *event)
+{
+	const char *label;
+
+	label = event->kind == BPF_DIAG_HISTORY_REF_ACQUIRE ? "acquired" : "released";
+	bpf_diag_report_source(env, event->insn_idx, label, "owned resource (id=%u)",
+			       event->ref.ref_id);
+}
+
 static void diag_print_history(struct bpf_verifier_env *env,
 			       const struct bpf_diag_history_opts *opts)
 {
@@ -1442,6 +1501,10 @@ static void diag_print_history(struct bpf_verifier_env *env,
 		case BPF_DIAG_HISTORY_MOD:
 			diag_print_mod(env, event);
 			break;
+		case BPF_DIAG_HISTORY_REF_ACQUIRE:
+		case BPF_DIAG_HISTORY_REF_RELEASE:
+			diag_print_ref_event(env, event);
+			break;
 		default:
 			break;
 		}
diff --git a/kernel/bpf/diagnostics.h b/kernel/bpf/diagnostics.h
index 440142b09e7a..13b6f5c8f8da 100644
--- a/kernel/bpf/diagnostics.h
+++ b/kernel/bpf/diagnostics.h
@@ -106,5 +106,7 @@ void bpf_diag_record_mod(struct bpf_verifier_env *env, u32 insn_idx,
 			 struct bpf_diag_mod_target target, enum bpf_diag_mod_reason reason,
 			 const struct bpf_reg_state *old_reg, const struct bpf_reg_state *new_reg,
 			 const struct bpf_diag_mod_target *origin);
+void bpf_diag_record_ref_acquire(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id);
+void bpf_diag_record_ref_release(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id);
 
 #endif /* __BPF_DIAGNOSTICS_H */
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 4a468299f05e..24bbeee3396e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -208,7 +208,8 @@ struct bpf_verifier_stack_elem {
 #define BPF_PRIV_STACK_MIN_SIZE		64
 
 static int acquire_reference(struct bpf_verifier_env *env, int insn_idx, int parent_id);
-static int release_reference_nomark(struct bpf_verifier_state *state, int id);
+static int __release_reference_nomark(struct bpf_verifier_state *state, int id);
+static int release_reference_nomark(struct bpf_verifier_env *env, int id);
 static int release_reference(struct bpf_verifier_env *env, int id);
 static void invalidate_non_owning_refs(struct bpf_verifier_env *env);
 static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env);
@@ -1442,6 +1443,7 @@ static int acquire_reference(struct bpf_verifier_env *env, int insn_idx, int par
 	s->type = REF_TYPE_PTR;
 	s->id = ++env->id_gen;
 	s->parent_id = parent_id;
+	bpf_diag_record_ref_acquire(env, insn_idx, s->id);
 	return s->id;
 }
 
@@ -9232,7 +9234,7 @@ static void mark_pkt_end(struct bpf_verifier_state *vstate, int regn, bool range
 		reg->range = AT_PKT_END;
 }
 
-static int release_reference_nomark(struct bpf_verifier_state *state, int id)
+static int __release_reference_nomark(struct bpf_verifier_state *state, int id)
 {
 	int i;
 
@@ -9247,6 +9249,16 @@ static int release_reference_nomark(struct bpf_verifier_state *state, int id)
 	return -EINVAL;
 }
 
+static int release_reference_nomark(struct bpf_verifier_env *env, int id)
+{
+	int err;
+
+	err = __release_reference_nomark(env->cur_state, id);
+	if (!err)
+		bpf_diag_record_ref_release(env, env->insn_idx, id);
+	return err;
+}
+
 static int idstack_push(struct bpf_idmap *idmap, u32 id)
 {
 	int i;
@@ -9289,8 +9301,10 @@ static int release_reference(struct bpf_verifier_env *env, int id)
 	if (err)
 		return err;
 
-	if (find_reference_state(vstate, id))
-		WARN_ON_ONCE(release_reference_nomark(vstate, id));
+	if (find_reference_state(vstate, id)) {
+		err = release_reference_nomark(env, id);
+		WARN_ON_ONCE(err);
+	}
 
 	while ((id = idstack_pop(idstack))) {
 		/*
@@ -9423,7 +9437,9 @@ static int ref_convert_alloc_rcu_protected(struct bpf_verifier_env *env, u32 id)
 	struct bpf_reg_state *reg;
 	int err;
 
-	err = release_reference_nomark(env->cur_state, id);
+	err = release_reference_nomark(env, id);
+	if (err)
+		return err;
 
 	bpf_for_each_reg_in_vstate(env->cur_state, state, reg, ({
 		if (reg->id != id)
@@ -11906,8 +11922,10 @@ static void ref_convert_owning_non_owning(struct bpf_verifier_env *env, u32 id)
 {
 	struct bpf_func_state *unused;
 	struct bpf_reg_state *reg;
+	int err;
 
-	WARN_ON_ONCE(release_reference_nomark(env->cur_state, id));
+	err = release_reference_nomark(env, id);
+	WARN_ON_ONCE(err);
 
 	bpf_for_each_reg_in_vstate(env->cur_state, unused, reg, ({
 		if (reg->id == id) {
@@ -16135,7 +16153,7 @@ static void mark_ptr_or_null_regs(struct bpf_verifier_state *vstate, u32 regno,
 		 * No one could have freed the reference state before
 		 * doing the NULL check.
 		 */
-		WARN_ON_ONCE(release_reference_nomark(vstate, id));
+		WARN_ON_ONCE(__release_reference_nomark(vstate, id));
 
 	bpf_for_each_reg_in_vstate(vstate, state, reg, ({
 		mark_ptr_or_null_reg(state, reg, id, is_null);
-- 
2.53.0


  parent reply	other threads:[~2026-07-13 15:39 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-13 15:38 [PATCH bpf-next v3 00/17] Redesign Verification Errors Kumar Kartikeya Dwivedi
2026-07-13 15:38 ` [PATCH bpf-next v3 01/17] bpf: Add verifier diagnostics report helpers Kumar Kartikeya Dwivedi
2026-07-13 15:50   ` sashiko-bot
2026-07-13 15:38 ` [PATCH bpf-next v3 02/17] bpf: Add source and instruction diagnostic context Kumar Kartikeya Dwivedi
2026-07-13 15:38 ` [PATCH bpf-next v3 03/17] bpf: Add verifier diagnostic event log Kumar Kartikeya Dwivedi
2026-07-13 15:54   ` sashiko-bot
2026-07-13 15:38 ` [PATCH bpf-next v3 04/17] bpf: Prune verifier diagnostics when switching paths Kumar Kartikeya Dwivedi
2026-07-13 16:02   ` sashiko-bot
2026-07-13 15:38 ` [PATCH bpf-next v3 05/17] bpf: Track verifier register diagnostic events Kumar Kartikeya Dwivedi
2026-07-13 16:06   ` sashiko-bot
2026-07-13 15:38 ` Kumar Kartikeya Dwivedi [this message]
2026-07-13 15:38 ` [PATCH bpf-next v3 07/17] bpf: Track verifier context " Kumar Kartikeya Dwivedi
2026-07-13 15:38 ` [PATCH bpf-next v3 08/17] bpf: Report Register Type Safety errors Kumar Kartikeya Dwivedi
2026-07-13 15:38 ` [PATCH bpf-next v3 09/17] bpf: Report Memory Safety bounds errors Kumar Kartikeya Dwivedi
2026-07-13 15:38 ` [PATCH bpf-next v3 10/17] bpf: Report Resource Lifetime reference leaks Kumar Kartikeya Dwivedi
2026-07-13 16:04   ` sashiko-bot
2026-07-13 15:39 ` [PATCH bpf-next v3 11/17] bpf: Report Call Type Safety argument errors Kumar Kartikeya Dwivedi
2026-07-13 15:51   ` sashiko-bot
2026-07-13 15:39 ` [PATCH bpf-next v3 12/17] bpf: Report Execution Context Safety errors Kumar Kartikeya Dwivedi
2026-07-13 15:53   ` sashiko-bot
2026-07-13 15:39 ` [PATCH bpf-next v3 13/17] bpf: Report Program Structure CFG errors Kumar Kartikeya Dwivedi
2026-07-13 15:39 ` [PATCH bpf-next v3 14/17] bpf: Report Policy helper and kfunc errors Kumar Kartikeya Dwivedi
2026-07-13 16:09   ` sashiko-bot
2026-07-13 15:39 ` [PATCH bpf-next v3 15/17] bpf: Report Verifier Limit errors Kumar Kartikeya Dwivedi
2026-07-13 15:39 ` [PATCH bpf-next v3 16/17] bpf: Report Verifier Internal errors Kumar Kartikeya Dwivedi
2026-07-13 15:39 ` [PATCH bpf-next v3 17/17] bpf: Gate verifier diagnostics on log level Kumar Kartikeya Dwivedi
2026-07-14  3:36   ` kernel test robot
2026-07-14  6:10 ` [syzbot ci] Re: Redesign Verification Errors syzbot 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=20260713153910.2556007-7-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.