summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmery Hung <ameryhung@gmail.com>2026-04-06 18:05:47 +0300
committerAlexei Starovoitov <ast@kernel.org>2026-04-08 04:20:49 +0300
commit017f5c4ef73c99ab4cdda3470a5310dc42094949 (patch)
treeccd3f9ac463621b21abdca7288e21226af1ca461
parentcac16ce1e3786bd98cec0c108e3bc06ed3d3c6a9 (diff)
downloadlinux-017f5c4ef73c99ab4cdda3470a5310dc42094949.tar.xz
bpf: Allow overwriting referenced dynptr when refcnt > 1
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>
-rw-r--r--kernel/bpf/verifier.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 40584ab48fb4..594260c1f382 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -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);