Re: [PATCH bpf-next v1 4/6] selftests/bpf: Cover the user ringbuf callback dynptr lifetime

From: bot+bpf-ci

Date: Mon Sep 21 2026 - 21:49:30 EST


> commit ffea6db696c062005bd2724d8b3888fa7eaa4768
> Author: Ihor Solodrai <ihor.solodrai@xxxxxxxxx>
> Date: Mon Sep 21 18:03:31 2026 -0700
>
> selftests/bpf: Cover the user ringbuf callback dynptr lifetime
>
> Add a rejection test for each route the bpf_user_ringbuf_drain() callback
> dynptr can take out of its frame:
>
> - the CONST_PTR_TO_DYNPTR register parked in callback_ctx
> - a bpf_dynptr_data() slice
> - a bpf_dynptr_slice() slice
> - a bpf_dynptr_clone() written into the caller's frame
> - a slice taken from that clone after the drain returns
> - an inner drain's dynptr escaping into an outer callback
>
> The first also checks that the diagnostic names the callback.
>
> bpf_throw() from the callback reaches check_reference_leak() with the
> frame reference still live, and is rejected afterwards by
> check_max_stack_depth(). It matches that rejection in full, because
> "bpf_throw" alone also matches the reference-leak wording the callback
> must not produce.
>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@xxxxxxxxx>

This isn't a bug, but the changelog says "The first" also checks the
diagnostic names the callback, yet four of the six programs match "the
callback that owned this value returned" - would it help to say that the
parked-dynptr/slice/nested routes all pin that wording and only the clone
routes differ?

> diff --git a/tools/testing/selftests/bpf/progs/exceptions_fail.c b/tools/testing/selftests/bpf/progs/exceptions_fail.c
> index 22503cf62e9f..86a0667ba348 100644
> --- a/tools/testing/selftests/bpf/progs/exceptions_fail.c
> +++ b/tools/testing/selftests/bpf/progs/exceptions_fail.c

[ ... ]

> diff --git a/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c b/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c
> index c0d0422b8030..a8d3acfa2bd2 100644
> --- a/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c
> +++ b/tools/testing/selftests/bpf/progs/user_ringbuf_fail.c
> @@ -1,9 +1,11 @@
> // SPDX-License-Identifier: GPL-2.0
> /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
>
> +#include <stdbool.h>
> #include <linux/bpf.h>
> #include <bpf/bpf_helpers.h>
> #include "bpf_misc.h"
> +#include "bpf_kfuncs.h"
>
> char _license[] SEC("license") = "GPL";

[ ... ]

> @@ -243,3 +245,144 @@ int user_ringbuf_callback_const_ptr_to_dynptr_reg_off(void *ctx)
> callback_adjust_bpf_dynptr_reg_off, NULL, 0);
> return 0;
> }
> +
> +/* The sample goes back to the producer as soon as the callback returns. */
> +struct dynptr_ctx {
> + struct bpf_dynptr *saved;
> +};
> +
> +static long callback_park_dynptr(struct bpf_dynptr *dynptr, void *context)
> +{
> + struct dynptr_ctx *c = context;
> +
> + c->saved = dynptr;
> + return 0;
> +}

[ ... ]

> +static long callback_park_inner(struct bpf_dynptr *dynptr, void *context)
> +{
> + struct dynptr_ctx *c = context;
> +
> + c->saved = dynptr;
> + return 0;
> +}

This isn't a bug, but callback_park_inner looks identical to
callback_park_dynptr - could the nested test pass callback_park_dynptr to
the inner drain instead, the way callback_park_clone is already shared by
the two clone tests?

> +
> +/* An inner drain's dynptr must not escape into the outer callback either. */
> +static long callback_park_outer(struct bpf_dynptr *dynptr, void *context)
> +{
> + struct dynptr_ctx inner = {};
> + char buf[8] = {};
> +
> + bpf_user_ringbuf_drain(&user_ringbuf, callback_park_inner, &inner, 0);
> + if (inner.saved)
> + bpf_dynptr_read(buf, sizeof(buf), inner.saved, 0, 0);
> + return buf[0] ? 1 : 0;
> +}
> +
> +SEC("?raw_tp")
> +__failure __msg("the callback that owned this value returned")
> +int user_ringbuf_callback_nested_park_inner(void *ctx)
> +{
> + bpf_user_ringbuf_drain(&user_ringbuf, callback_park_outer, NULL, 0);
> + return 0;
> +}


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/35674974944