On Mon, Jun 15, 2026 at 1:57 AM Nuoqi Gui <[email protected]> wrote:
>
> bpf_rdonly_cast() is an identity operation at runtime and is also fixed
> up to a register move by the verifier. Its verifier return-state setup
> must preserve lifetime metadata that belongs to the source pointer.
>
> On this verifier model, dynptr-slice kfunc returns carry dynptr_id, while
> refcounted dynptr release invalidates aliases by ref_obj_id. Attach the
> ref_obj_id to bpf_dynptr_slice() and bpf_dynptr_slice_rdwr() returns.
> Propagate source id and release metadata through bpf_rdonly_cast().
> For typed rdonly_cast() aliases, keep the source dynptr_id in reg id so
> stack-overwrite invalidation can distinguish the originating dynptr when a
> clone keeps the ref alive.
>
> Otherwise, a cast alias can survive bpf_ringbuf_discard_dynptr() and
> remain readable after the dynptr release.
>
> Fixes: 66e3a13e7c2c ("bpf: Add bpf_dynptr_slice and bpf_dynptr_slice_rdwr")
> Fixes: a35b9af4ec2c ("bpf: Add a kfunc for generic type cast")
> Signed-off-by: Nuoqi Gui <[email protected]>
> ---
> include/linux/bpf_verifier.h | 5 +++++
> kernel/bpf/verifier.c | 36 ++++++++++++++++++++++++++++--------
> 2 files changed, 33 insertions(+), 8 deletions(-)
>
bpf_rdonly_cast() takes *any value*, garbage or not, and returns a
BTF-typed pointer that verifier and BPF JIT generated code makes sure
can never do any harm (it will return zero, if the address is wrong,
etc). There is no issue here and we should not invalidate the result
of bpf_rdonly_cast() just because some dynptr was destroyed.
> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
> index 185b2aa43a420..0bc4b40e76bd0 100644
> --- a/include/linux/bpf_verifier.h
> +++ b/include/linux/bpf_verifier.h
> @@ -1366,6 +1366,11 @@ struct bpf_kfunc_call_arg_meta {
> u32 id;
> u32 ref_obj_id;
> } initialized_dynptr;
> + struct {
> + u32 id;
> + u32 dynptr_id;
> + u32 ref_obj_id;
> + } rdonly_cast_src;
> struct {
> u8 spi;
> u8 frameno;
[...]