]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: Allow overwriting referenced dynptr when refcnt > 1
authorAmery Hung <ameryhung@gmail.com>
Mon, 6 Apr 2026 15:05:47 +0000 (08:05 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 8 Apr 2026 01:20:49 +0000 (18:20 -0700)
The verifier currently does not allow overwriting a referenced dynptr's
stack slot to prevent resource leak. This is because referenced dynptr
holds additional resources that requires calling specific helpers to
release. This limitation can be relaxed when there are multiple copies
of the same dynptr. Whether it is the orignial dynptr or one of its
clones, as long as there exists at least one other dynptr with the same
ref_obj_id (to be used to release the reference), its stack slot should
be allowed to be overwritten.

Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Amery Hung <ameryhung@gmail.com>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260406150548.1354271-2-ameryhung@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index 40584ab48fb49238048beacf326cb3a5341c9744..594260c1f382a39d10ebce3c1eea6c1b21a3df36 100644 (file)
@@ -936,8 +936,27 @@ static int destroy_if_dynptr_stack_slot(struct bpf_verifier_env *env,
                spi = spi + 1;
 
        if (dynptr_type_refcounted(state->stack[spi].spilled_ptr.dynptr.type)) {
-               verbose(env, "cannot overwrite referenced dynptr\n");
-               return -EINVAL;
+               int ref_obj_id = state->stack[spi].spilled_ptr.ref_obj_id;
+               int ref_cnt = 0;
+
+               /*
+                * A referenced dynptr can be overwritten only if there is at
+                * least one other dynptr sharing the same ref_obj_id,
+                * ensuring the reference can still be properly released.
+                */
+               for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) {
+                       if (state->stack[i].slot_type[0] != STACK_DYNPTR)
+                               continue;
+                       if (!state->stack[i].spilled_ptr.dynptr.first_slot)
+                               continue;
+                       if (state->stack[i].spilled_ptr.ref_obj_id == ref_obj_id)
+                               ref_cnt++;
+               }
+
+               if (ref_cnt <= 1) {
+                       verbose(env, "cannot overwrite referenced dynptr\n");
+                       return -EINVAL;
+               }
        }
 
        mark_stack_slot_scratched(env, spi);