[PATCH bpf-next v2 04/11] bpf: Separate reference removal from descendant invalidation

From: Ihor Solodrai

Date: Fri Oct 09 2026 - 16:31:17 EST


Reference release removes a program-owned reference and invalidates all
values derived from it in one operation.

Frame-owned values will need the same descendant walk without object
release semantics. Separate the walk from reference removal and pass its
diagnostic reason explicitly. Keep object-reference removal and the
existing release reason in release_reference().

No functional change.

Signed-off-by: Ihor Solodrai <ihor.solodrai@xxxxxxxxx>
---
kernel/bpf/verifier.c | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 62b991f3c39a..88b86f658e4a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -10668,8 +10668,9 @@ static int idstack_pop(struct bpf_idmap *idmap)
return idmap->map[--idmap->cnt].old;
}

-/* Release id and objects derived from it iteratively in a DFS manner */
-static int release_reference(struct bpf_verifier_env *env, int id)
+/* Invalidate id and values derived from it iteratively in a DFS manner. */
+static int invalidate_reference(struct bpf_verifier_env *env, int id,
+ enum bpf_diag_mod_reason reason)
{
u32 mask = (1 << STACK_SPILL) | (1 << STACK_DYNPTR);
struct bpf_verifier_state *vstate = env->cur_state;
@@ -10684,11 +10685,6 @@ static int release_reference(struct bpf_verifier_env *env, int id)
if (err)
return err;

- if (find_reference_state(vstate, id)) {
- err = release_reference_nomark(env, id);
- WARN_ON_ONCE(err);
- }
-
while ((id = idstack_pop(idstack))) {
/*
* Child references are inaccessible after parent is released,
@@ -10724,14 +10720,12 @@ static int release_reference(struct bpf_verifier_env *env, int id)

if (reg->dynptr.first_slot)
dyn_stack--;
- bpf_diag_record_scrub(env, &dyn_stack[0].spilled_ptr,
- BPF_DIAG_MOD_REF_RELEASE);
- bpf_diag_record_scrub(env, &dyn_stack[1].spilled_ptr,
- BPF_DIAG_MOD_REF_RELEASE);
+ bpf_diag_record_scrub(env, &dyn_stack[0].spilled_ptr, reason);
+ bpf_diag_record_scrub(env, &dyn_stack[1].spilled_ptr, reason);
invalidate_dynptr(env, dyn_stack);
continue;
}
- bpf_diag_record_scrub(env, reg, BPF_DIAG_MOD_REF_RELEASE);
+ bpf_diag_record_scrub(env, reg, reason);
if (!stack || stack->slot_type[BPF_REG_SIZE - 1] == STACK_SPILL)
mark_reg_invalid(env, reg);
}));
@@ -10740,6 +10734,17 @@ static int release_reference(struct bpf_verifier_env *env, int id)
return 0;
}

+static int release_reference(struct bpf_verifier_env *env, int id)
+{
+ int err;
+
+ if (find_reference_state(env->cur_state, id)) {
+ err = release_reference_nomark(env, id);
+ WARN_ON_ONCE(err);
+ }
+ return invalidate_reference(env, id, BPF_DIAG_MOD_REF_RELEASE);
+}
+
static void invalidate_non_owning_refs(struct bpf_verifier_env *env)
{
struct bpf_func_state *unused;
--
2.56.0