Add a success case that uses an escaped clone slice while the shared ring buffer reservation is still live, and a failure case that releases the original dynptr before using the escaped slice. Together these cases verify that subprogram return neither invalidates the slice too early nor lets it survive the shared reference release. Assisted-by: LLM Signed-off-by: Xu Yunxiang --- .../testing/selftests/bpf/progs/dynptr_fail.c | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index 1cd61d72c166f..0704662cd32f3 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -1892,6 +1892,52 @@ int clone_invalidate4(void *ctx) return 0; } +static __noinline void clone_slice_in_subprog(struct bpf_dynptr *ptr, int **data) +{ + struct bpf_dynptr clone; + + bpf_dynptr_clone(ptr, &clone); + *data = bpf_dynptr_data(&clone, 0, sizeof(val)); +} + +/* A slice that escapes the clone's call frame remains valid while the + * shared ringbuf reservation is live. + */ +SEC("?raw_tp") +__success +int clone_slice_returned_frame_valid(void *ctx) +{ + struct bpf_dynptr ptr; + int *data = NULL; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + clone_slice_in_subprog(&ptr, &data); + if (data) + *data = 123; + bpf_ringbuf_submit_dynptr(&ptr, 0); + + return 0; +} + +/* Releasing the shared reservation must invalidate a slice that escaped + * from a clone's call frame. + */ +SEC("?raw_tp") +__failure __msg("invalid mem access 'scalar'") +int clone_slice_returned_frame_invalid(void *ctx) +{ + struct bpf_dynptr ptr; + int *data = NULL; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + clone_slice_in_subprog(&ptr, &data); + bpf_ringbuf_submit_dynptr(&ptr, 0); + if (data) + *data = 123; + + return 0; +} + /* Invalidating a dynptr should invalidate any data slices * of its parent */ -- 2.43.0