Re: [bpf-next v2 2/2] selftests/bpf: Add tests for bpf_copy_from_user_task_str

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

 



On Mon, Jan 6, 2025 at 6:20 PM Jordan Rome <linux@xxxxxxxxxxxxxx> wrote:
>
> This adds tests for both the happy path and the
> error path (with and without the BPF_F_PAD_ZEROS flag).
>
> Signed-off-by: Jordan Rome <linux@xxxxxxxxxxxxxx>
> ---
>  .../selftests/bpf/prog_tests/bpf_iter.c       |  7 +++
>  .../selftests/bpf/prog_tests/read_vsyscall.c  |  1 +
>  .../selftests/bpf/progs/bpf_iter_tasks.c      | 55 +++++++++++++++++++
>  .../selftests/bpf/progs/read_vsyscall.c       |  6 +-
>  4 files changed, 67 insertions(+), 2 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
> index 6f1bfacd7375..8ed864793bd1 100644
> --- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
> @@ -34,6 +34,8 @@
>  #include "bpf_iter_ksym.skel.h"
>  #include "bpf_iter_sockmap.skel.h"
>
> +static char test_data[] = "test_data";
> +
>  static void test_btf_id_or_null(void)
>  {
>         struct bpf_iter_test_kern3 *skel;
> @@ -328,12 +330,17 @@ static void test_task_sleepable(void)
>         if (!ASSERT_OK_PTR(skel, "bpf_iter_tasks__open_and_load"))
>                 return;
>
> +       skel->bss->user_ptr = test_data;
>         do_dummy_read(skel->progs.dump_task_sleepable);
>
>         ASSERT_GT(skel->bss->num_expected_failure_copy_from_user_task, 0,
>                   "num_expected_failure_copy_from_user_task");
>         ASSERT_GT(skel->bss->num_success_copy_from_user_task, 0,
>                   "num_success_copy_from_user_task");
> +       ASSERT_GT(skel->bss->num_expected_failure_copy_from_user_task_str, 0,
> +                 "num_expected_failure_copy_from_user_task_str");
> +       ASSERT_GT(skel->bss->num_success_copy_from_user_task_str, 0,
> +                 "num_success_copy_from_user_task_str");
>
>         bpf_iter_tasks__destroy(skel);
>  }
> diff --git a/tools/testing/selftests/bpf/prog_tests/read_vsyscall.c b/tools/testing/selftests/bpf/prog_tests/read_vsyscall.c
> index c7b9ba8b1d06..a8d1eaa67020 100644
> --- a/tools/testing/selftests/bpf/prog_tests/read_vsyscall.c
> +++ b/tools/testing/selftests/bpf/prog_tests/read_vsyscall.c
> @@ -24,6 +24,7 @@ struct read_ret_desc {
>         { .name = "copy_from_user", .ret = -EFAULT },
>         { .name = "copy_from_user_task", .ret = -EFAULT },
>         { .name = "copy_from_user_str", .ret = -EFAULT },
> +       { .name = "copy_from_user_task_str", .ret = -EFAULT },
>  };
>
>  void test_read_vsyscall(void)
> diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c b/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c
> index bc10c4e4b4fa..90691e34b915 100644
> --- a/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c
> +++ b/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c
> @@ -9,6 +9,7 @@ char _license[] SEC("license") = "GPL";
>  uint32_t tid = 0;
>  int num_unknown_tid = 0;
>  int num_known_tid = 0;
> +void *user_ptr = 0;
>
>  SEC("iter/task")
>  int dump_task(struct bpf_iter__task *ctx)
> @@ -35,7 +36,9 @@ int dump_task(struct bpf_iter__task *ctx)
>  }
>
>  int num_expected_failure_copy_from_user_task = 0;
> +int num_expected_failure_copy_from_user_task_str = 0;
>  int num_success_copy_from_user_task = 0;
> +int num_success_copy_from_user_task_str = 0;
>
>  SEC("iter.s/task")
>  int dump_task_sleepable(struct bpf_iter__task *ctx)
> @@ -44,6 +47,9 @@ int dump_task_sleepable(struct bpf_iter__task *ctx)
>         struct task_struct *task = ctx->task;
>         static const char info[] = "    === END ===";
>         struct pt_regs *regs;
> +       char task_str1[10] = "aaaaaaaaaa";
> +       char task_str2[10], task_str3[10];
> +       char task_str4[20] = "aaaaaaaaaaaaaaaaaaaa";
>         void *ptr;
>         uint32_t user_data = 0;
>         int ret;
> @@ -78,8 +84,57 @@ int dump_task_sleepable(struct bpf_iter__task *ctx)
>                 BPF_SEQ_PRINTF(seq, "%s\n", info);
>                 return 0;
>         }
> +
>         ++num_success_copy_from_user_task;
>
> +       /* Read an invalid pointer and ensure we get an error */
> +       ptr = NULL;
> +       ret = bpf_copy_from_user_task_str((char *)task_str1, sizeof(task_str1), ptr, task, 0);
> +       if (ret >= 0 || task_str1[9] != 'a') {
> +               BPF_SEQ_PRINTF(seq, "%s\n", info);
> +               return 0;
> +       }
> +
> +       /* Read an invalid pointer and ensure we get error with pad zeros flag */
> +       ptr = NULL;
> +       ret = bpf_copy_from_user_task_str((char *)task_str1, sizeof(task_str1), ptr, task, BPF_F_PAD_ZEROS);
> +       if (ret >= 0 || task_str1[9] != '\0') {
> +               BPF_SEQ_PRINTF(seq, "%s\n", info);
> +               return 0;
> +       }
> +
> +       ++num_expected_failure_copy_from_user_task_str;
> +
> +       /* Same length as the string */
> +       ret = bpf_copy_from_user_task_str((char *)task_str2, 10, user_ptr, task, 0);
> +       if (bpf_strncmp(task_str2, 10, "test_data\0") != 0 || ret != 10) {
> +               BPF_SEQ_PRINTF(seq, "%s\n", info);
> +               return 0;
> +       }
> +
> +       /* Shorter length than the string */
> +       ret = bpf_copy_from_user_task_str((char *)task_str3, 9, user_ptr, task, 0);
> +       if (bpf_strncmp(task_str3, 9, "test_dat\0") != 0 || ret != 9) {
> +               BPF_SEQ_PRINTF(seq, "%s\n", info);
> +               return 0;
> +       }
> +
> +       /* Longer length than the string */
> +       ret = bpf_copy_from_user_task_str((char *)task_str4, 20, user_ptr, task, 0);
> +       if (bpf_strncmp(task_str4, 10, "test_data\0") != 0 || ret != 10 || task_str4[sizeof(task_str4) - 1] != 'a') {
> +               BPF_SEQ_PRINTF(seq, "%s\n", info);
> +               return 0;
> +       }
> +
> +       /* Longer length than the string with pad zeros flag */
> +       ret = bpf_copy_from_user_task_str((char *)task_str4, 20, user_ptr, task, BPF_F_PAD_ZEROS);
> +       if (bpf_strncmp(task_str4, 10, "test_data\0") != 0 || ret != 10 || task_str4[sizeof(task_str4) - 1] != '\0') {

looks like a long string, please check 100 character limit

> +               BPF_SEQ_PRINTF(seq, "%s\n", info);
> +               return 0;

nit: this BPF_SEQ_PRINTF() + return 0 repetition is... repetitive :)
`goto drop_out;` maybe?

> +       }
> +
> +       ++num_success_copy_from_user_task_str;
> +
>         if (ctx->meta->seq_num == 0)
>                 BPF_SEQ_PRINTF(seq, "    tgid      gid     data\n");
>
> diff --git a/tools/testing/selftests/bpf/progs/read_vsyscall.c b/tools/testing/selftests/bpf/progs/read_vsyscall.c
> index 39ebef430059..623c1c5bd2d0 100644
> --- a/tools/testing/selftests/bpf/progs/read_vsyscall.c
> +++ b/tools/testing/selftests/bpf/progs/read_vsyscall.c
> @@ -8,14 +8,15 @@
>
>  int target_pid = 0;
>  void *user_ptr = 0;
> -int read_ret[9];
> +int read_ret[10];
>
>  char _license[] SEC("license") = "GPL";
>
>  /*
> - * This is the only kfunc, the others are helpers
> + * These are the kfuncs, the others are helpers
>   */
>  int bpf_copy_from_user_str(void *dst, u32, const void *, u64) __weak __ksym;
> +int bpf_copy_from_user_task_str(void *dst, u32, const void *, struct task_struct *, u64) __weak __ksym;

these definitions should be coming from vmlinux.h, no need to add them
manually anymore

>
>  SEC("fentry/" SYS_PREFIX "sys_nanosleep")
>  int do_probe_read(void *ctx)
> @@ -47,6 +48,7 @@ int do_copy_from_user(void *ctx)
>         read_ret[7] = bpf_copy_from_user_task(buf, sizeof(buf), user_ptr,
>                                               bpf_get_current_task_btf(), 0);
>         read_ret[8] = bpf_copy_from_user_str((char *)buf, sizeof(buf), user_ptr, 0);
> +       read_ret[9] = bpf_copy_from_user_task_str((char *)buf, sizeof(buf), user_ptr, bpf_get_current_task_btf(), 0);

please drop all those (char *) casts, in C any pointer is implicitly
castable to `void *` and `void *` is (implicitly) castable to any
other pointer. C++ is stricter, but in C it's canonical to not do
casting

>
>         return 0;
>  }
> --
> 2.43.5
>





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux