Re: [PATCH bpf-next v2 3/3] selftests/bpf: introduce tests for dynptr copy kfuncs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, May 2, 2025 at 12:06 PM Mykyta Yatsenko
<mykyta.yatsenko5@xxxxxxxxx> wrote:
>
> From: Mykyta Yatsenko <yatsenko@xxxxxxxx>
>
> Introduce selftests verifying newly-added dynptr copy kfuncs.
> Covering contiguous and non-contiguous memory backed dynptrs.
>
> Disable test_probe_read_user_str_dynptr that triggers bug in
> strncpy_from_user_nofault. Patch to fix the issue [1].
>
> [1] https://patchwork.kernel.org/project/linux-mm/patch/20250422131449.57177-1-mykyta.yatsenko5@xxxxxxxxx/
>
> Acked-by: Andrii Nakryiko <andrii@xxxxxxxxxx>
> Signed-off-by: Mykyta Yatsenko <yatsenko@xxxxxxxx>
> ---
>  tools/testing/selftests/bpf/DENYLIST          |   1 +
>  .../testing/selftests/bpf/prog_tests/dynptr.c |  13 ++
>  .../selftests/bpf/progs/dynptr_success.c      | 201 ++++++++++++++++++
>  3 files changed, 215 insertions(+)
>
> diff --git a/tools/testing/selftests/bpf/DENYLIST b/tools/testing/selftests/bpf/DENYLIST
> index f748f2c33b22..1789a61d0a9b 100644
> --- a/tools/testing/selftests/bpf/DENYLIST
> +++ b/tools/testing/selftests/bpf/DENYLIST
> @@ -1,5 +1,6 @@
>  # TEMPORARY
>  # Alphabetical order
> +dynptr/test_probe_read_user_str_dynptr # disabled until https://patchwork.kernel.org/project/linux-mm/patch/20250422131449.57177-1-mykyta.yatsenko5@xxxxxxxxx/ makes it into the bpf-next
>  get_stack_raw_tp    # spams with kernel warnings until next bpf -> bpf-next merge
>  stacktrace_build_id
>  stacktrace_build_id_nmi
> diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> index e29cc16124c2..62e7ec775f24 100644
> --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c
> +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c
> @@ -33,10 +33,19 @@ static struct {
>         {"test_dynptr_skb_no_buff", SETUP_SKB_PROG},
>         {"test_dynptr_skb_strcmp", SETUP_SKB_PROG},
>         {"test_dynptr_skb_tp_btf", SETUP_SKB_PROG_TP},
> +       {"test_probe_read_user_dynptr", SETUP_XDP_PROG},
> +       {"test_probe_read_kernel_dynptr", SETUP_XDP_PROG},
> +       {"test_probe_read_user_str_dynptr", SETUP_XDP_PROG},
> +       {"test_probe_read_kernel_str_dynptr", SETUP_XDP_PROG},
> +       {"test_copy_from_user_dynptr", SETUP_SYSCALL_SLEEP},
> +       {"test_copy_from_user_str_dynptr", SETUP_SYSCALL_SLEEP},
> +       {"test_copy_from_user_task_dynptr", SETUP_SYSCALL_SLEEP},
> +       {"test_copy_from_user_task_str_dynptr", SETUP_SYSCALL_SLEEP},
>  };
>
>  static void verify_success(const char *prog_name, enum test_setup_type setup_type)
>  {
> +       char user_data[384] = {[0 ... 382] = 'a', '\0'};
>         struct dynptr_success *skel;
>         struct bpf_program *prog;
>         struct bpf_link *link;
> @@ -58,6 +67,10 @@ static void verify_success(const char *prog_name, enum test_setup_type setup_typ
>         if (!ASSERT_OK(err, "dynptr_success__load"))
>                 goto cleanup;
>
> +       skel->bss->user_ptr = user_data;
> +       skel->data->test_len[0] = sizeof(user_data);
> +       memcpy(skel->bss->expected_str, user_data, sizeof(user_data));
> +
>         switch (setup_type) {
>         case SETUP_SYSCALL_SLEEP:
>                 link = bpf_program__attach(prog);
> diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c
> index e1fba28e4a86..753d35eb47d9 100644
> --- a/tools/testing/selftests/bpf/progs/dynptr_success.c
> +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c
> @@ -680,3 +680,204 @@ int test_dynptr_copy_xdp(struct xdp_md *xdp)
>         bpf_ringbuf_discard_dynptr(&ptr_buf, 0);
>         return XDP_DROP;
>  }
> +
> +void *user_ptr;
> +char expected_str[384]; /* Contains the copy of the data pointed by user_ptr */

what so magic about 384?

> +__u32 test_len[7] = {0/* placeholder */, 0, 1, 2, 255, 256, 257};
> +
> +typedef int (*bpf_read_dynptr_fn_t)(struct bpf_dynptr *dptr, u32 off,
> +                                   u32 size, const void *unsafe_ptr);
> +
> +static __always_inline void test_dynptr_probe(void *ptr, bpf_read_dynptr_fn_t bpf_read_dynptr_fn)

More __always_inline in the prog too?
Why?

> +{
> +       char buf[sizeof(expected_str)];
> +       struct bpf_dynptr ptr_buf;
> +       int i;
> +
> +       err = bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(buf), 0, &ptr_buf);
> +
> +       bpf_for(i, 0, ARRAY_SIZE(test_len)) {
> +               __u32 len = test_len[i];
> +
> +               err = err ?: bpf_read_dynptr_fn(&ptr_buf, 0, test_len[i], ptr);
> +               if (len > sizeof(buf))
> +                       break;
> +               err = err ?: bpf_dynptr_read(&buf, len, &ptr_buf, 0, 0);
> +
> +               if (err || bpf_memcmp(expected_str, buf, len))
> +                       err = 1;
> +
> +               /* Reset buffer and dynptr */
> +               __builtin_memset(buf, 0, sizeof(buf));
> +               err = err ?: bpf_dynptr_write(&ptr_buf, 0, buf, len, 0);
> +       }
> +       bpf_ringbuf_discard_dynptr(&ptr_buf, 0);
> +}
> +
> +static __always_inline void test_dynptr_probe_str(void *ptr,
> +                                                 bpf_read_dynptr_fn_t bpf_read_dynptr_fn)
> +{
> +       char buf[sizeof(expected_str)];
> +       struct bpf_dynptr ptr_buf;
> +       __u32 cnt, i;
> +
> +       bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(buf), 0, &ptr_buf);
> +
> +       bpf_for(i, 0, ARRAY_SIZE(test_len)) {
> +               __u32 len = test_len[i];
> +
> +               cnt = bpf_read_dynptr_fn(&ptr_buf, 0, len, ptr);
> +               if (cnt != len)
> +                       err = 1;
> +
> +               if (len > sizeof(buf))
> +                       continue;
> +               err = err ?: bpf_dynptr_read(&buf, len, &ptr_buf, 0, 0);
> +               if (!len)
> +                       continue;
> +               if (err || bpf_memcmp(expected_str, buf, len - 1) || buf[len - 1] != '\0')
> +                       err = 1;
> +       }
> +       bpf_ringbuf_discard_dynptr(&ptr_buf, 0);
> +}
> +
> +static __always_inline void test_dynptr_probe_xdp(struct xdp_md *xdp, void *ptr,
> +                                                 bpf_read_dynptr_fn_t bpf_read_dynptr_fn)
> +{
> +       struct bpf_dynptr ptr_xdp;
> +       char buf[sizeof(expected_str)];
> +       __u32 off, i;
> +
> +       /* Set offset near the seam between buffers */
> +       off = 3500;

what is 3500 ?





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux