From: Andrii Nakryiko <andrii.nakryiko@gmail.com>
To: Marcus Wichelmann <marcus.wichelmann@hetzner-cloud.de>
Cc: Jordan Rome <linux@jordanrome.com>,
bpf@vger.kernel.org, linux-mm@kvack.org,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Kernel Team <kernel-team@fb.com>,
Andrew Morton <akpm@linux-foundation.org>,
Shakeel Butt <shakeel.butt@linux.dev>,
Alexander Potapenko <glider@google.com>
Subject: Re: [bpf-next v8 3/3] selftests/bpf: Add tests for bpf_copy_from_user_task_str
Date: Fri, 21 Feb 2025 10:26:48 -0800 [thread overview]
Message-ID: <CAEf4BzYu9R0_0YghpXaE5-Ojds7W7eURyp+3BsaC4BHp=ZVszg@mail.gmail.com> (raw)
In-Reply-To: <386d3514-1822-45a2-a2c5-1567a0d599a5@hetzner-cloud.de>
On Fri, Feb 21, 2025 at 7:01 AM Marcus Wichelmann
<marcus.wichelmann@hetzner-cloud.de> wrote:
>
> Hi,
>
> I'm not sure what I'm doing wrong, but after rebasing on latest bpf-next
> which includes this patch, I'm no longer able to build the bpf selftests:
>
> # pushd tools/testing/selftests/bpf/
> # make -j80
> [...]
> GEN-SKEL [test_progs] bpf_iter_task_vmas.skel.h
> CLNG-BPF [test_progs] bpf_iter_tasks.bpf.o
> progs/bpf_iter_tasks.c:98:8: error: call to undeclared function 'bpf_copy_from_user_task_str'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
> 98 | ret = bpf_copy_from_user_task_str((char *)task_str1, sizeof(task_str1), ptr, task, 0);
> | ^
> 1 error generated.
> make: *** [Makefile:733: /root/linux/tools/testing/selftests/bpf/bpf_iter_tasks.bpf.o] Error 1
>
> I suppose the function definition should be in the vmlinux.h?
>
Yes, it should be in vmlinux.h, and if you don't have it, then you
must have a bit too old pahole.
$ git tag --contains ce4d0bc0200e3
v1.27
v1.28
> # grep bpf_copy tools/include/vmlinux.h
> typedef u64 (*btf_bpf_copy_from_user)(void *, u32, const void *);
> typedef u64 (*btf_bpf_copy_from_user_task)(void *, u32, const void *, struct task_struct *, u64);
>
> The kernel built from this revision is booted while trying to compile
> the selftests. I can also see that the kfunc is there when dumping without "format c":
>
> # bpftool btf dump file /sys/kernel/btf/vmlinux | grep bpf_copy_from_user_task_str
> [116060] FUNC 'bpf_copy_from_user_task_str' type_id=116059 linkage=static
>
> But when dumping the vmlinux headers with "format c", I cannot see the kfunc.
> I'm not sure if this is normal:
>
> # bpftool btf dump file /sys/kernel/btf/vmlinux format c | grep bpf_copy_from_user_task_str
> #
>
> CONFIG_BPF SYSCALL is enabled. Are there other config options that
> have to be enabled that I may be missing?
>
> I'm trying this on a aarch64 system. I also tried to fully clean
> my working tree using `git clean -d -x -f`, which didn't help
> either.
>
> Thanks!
> Marcus
>
>
> Am 13.02.25 um 16:21 schrieb Jordan Rome:
> > 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@jordanrome.com>
> > ---
> > .../selftests/bpf/prog_tests/bpf_iter.c | 68 +++++++++++
> > .../selftests/bpf/prog_tests/read_vsyscall.c | 1 +
> > .../selftests/bpf/progs/bpf_iter_tasks.c | 110 ++++++++++++++++++
> > .../selftests/bpf/progs/read_vsyscall.c | 11 +-
> > 4 files changed, 188 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..add4a18c33bd 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
> > @@ -323,19 +323,87 @@ static void test_task_pidfd(void)
> > static void test_task_sleepable(void)
> > {
> > struct bpf_iter_tasks *skel;
> > + int pid, status, err, data_pipe[2], finish_pipe[2], c;
> > + char *test_data = NULL;
> > + char *test_data_long = NULL;
> > + char *data[2];
> > +
> > + if (!ASSERT_OK(pipe(data_pipe), "data_pipe") ||
> > + !ASSERT_OK(pipe(finish_pipe), "finish_pipe"))
> > + return;
> >
> > skel = bpf_iter_tasks__open_and_load();
> > if (!ASSERT_OK_PTR(skel, "bpf_iter_tasks__open_and_load"))
> > return;
> >
> > + pid = fork();
> > + if (!ASSERT_GE(pid, 0, "fork"))
> > + return;
> > +
> > + if (pid == 0) {
> > + /* child */
> > + close(data_pipe[0]);
> > + close(finish_pipe[1]);
> > +
> > + test_data = malloc(sizeof(char) * 10);
> > + strncpy(test_data, "test_data", 10);
> > + test_data[9] = '\0';
> > +
> > + test_data_long = malloc(sizeof(char) * 5000);
> > + for (int i = 0; i < 5000; ++i) {
> > + if (i % 2 == 0)
> > + test_data_long[i] = 'b';
> > + else
> > + test_data_long[i] = 'a';
> > + }
> > + test_data_long[4999] = '\0';
> > +
> > + data[0] = test_data;
> > + data[1] = test_data_long;
> > +
> > + write(data_pipe[1], &data, sizeof(data));
> > +
> > + /* keep child alive until after the test */
> > + err = read(finish_pipe[0], &c, 1);
> > + if (err != 1)
> > + exit(-1);
> > +
> > + close(data_pipe[1]);
> > + close(finish_pipe[0]);
> > + _exit(0);
> > + }
> > +
> > + /* parent */
> > + close(data_pipe[1]);
> > + close(finish_pipe[0]);
> > +
> > + err = read(data_pipe[0], &data, sizeof(data));
> > + ASSERT_EQ(err, sizeof(data), "read_check");
> > +
> > + skel->bss->user_ptr = data[0];
> > + skel->bss->user_ptr_long = data[1];
> > + skel->bss->pid = pid;
> > +
> > 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);
> > +
> > + write(finish_pipe[1], &c, 1);
> > + err = waitpid(pid, &status, 0);
> > + ASSERT_EQ(err, pid, "waitpid");
> > + ASSERT_EQ(status, 0, "zero_child_exit");
> > +
> > + close(data_pipe[0]);
> > + close(finish_pipe[1]);
> > }
> >
> > static void test_task_stack(void)
> > 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..966ee5a7b066 100644
> > --- a/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c
> > +++ b/tools/testing/selftests/bpf/progs/bpf_iter_tasks.c
> > @@ -9,6 +9,13 @@ char _license[] SEC("license") = "GPL";
> > uint32_t tid = 0;
> > int num_unknown_tid = 0;
> > int num_known_tid = 0;
> > +void *user_ptr = 0;
> > +void *user_ptr_long = 0;
> > +uint32_t pid = 0;
> > +
> > +static char big_str1[5000];
> > +static char big_str2[5005];
> > +static char big_str3[4996];
> >
> > SEC("iter/task")
> > int dump_task(struct bpf_iter__task *ctx)
> > @@ -35,7 +42,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 +53,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 +90,106 @@ 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' || task_str1[0] != '\0') {
> > + 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' || task_str1[0] != '\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);
> > + /* only need to do the task pid check once */
> > + if (bpf_strncmp(task_str2, 10, "test_data\0") != 0 || ret != 10 || task->tgid != pid) {
> > + BPF_SEQ_PRINTF(seq, "%s\n", info);
> > + return 0;
> > + }
> > +
> > + /* Shorter length than the string */
> > + ret = bpf_copy_from_user_task_str((char *)task_str3, 2, user_ptr, task, 0);
> > + if (bpf_strncmp(task_str3, 2, "t\0") != 0 || ret != 2) {
> > + 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') {
> > + BPF_SEQ_PRINTF(seq, "%s\n", info);
> > + return 0;
> > + }
> > +
> > + /* Longer length than the string past a page boundary */
> > + ret = bpf_copy_from_user_task_str(big_str1, 5000, user_ptr, task, 0);
> > + if (bpf_strncmp(big_str1, 10, "test_data\0") != 0 || ret != 10) {
> > + BPF_SEQ_PRINTF(seq, "%s\n", info);
> > + return 0;
> > + }
> > +
> > + /* String that crosses a page boundary */
> > + ret = bpf_copy_from_user_task_str(big_str1, 5000, user_ptr_long, task, BPF_F_PAD_ZEROS);
> > + if (bpf_strncmp(big_str1, 4, "baba") != 0 || ret != 5000
> > + || bpf_strncmp(big_str1 + 4996, 4, "bab\0") != 0) {
> > + BPF_SEQ_PRINTF(seq, "%s\n", info);
> > + return 0;
> > + }
> > +
> > + for (int i = 0; i < 4999; ++i) {
> > + if (i % 2 == 0) {
> > + if (big_str1[i] != 'b') {
> > + BPF_SEQ_PRINTF(seq, "%s\n", info);
> > + return 0;
> > + }
> > + } else {
> > + if (big_str1[i] != 'a') {
> > + BPF_SEQ_PRINTF(seq, "%s\n", info);
> > + return 0;
> > + }
> > + }
> > + }
> > +
> > + /* Longer length than the string that crosses a page boundary */
> > + ret = bpf_copy_from_user_task_str(big_str2, 5005, user_ptr_long, task, BPF_F_PAD_ZEROS);
> > + if (bpf_strncmp(big_str2, 4, "baba") != 0 || ret != 5000
> > + || bpf_strncmp(big_str2 + 4996, 5, "bab\0\0") != 0) {
> > + BPF_SEQ_PRINTF(seq, "%s\n", info);
> > + return 0;
> > + }
> > +
> > + /* Shorter length than the string that crosses a page boundary */
> > + ret = bpf_copy_from_user_task_str(big_str3, 4996, user_ptr_long, task, 0);
> > + if (bpf_strncmp(big_str3, 4, "baba") != 0 || ret != 4996
> > + || bpf_strncmp(big_str3 + 4992, 4, "bab\0") != 0) {
> > + BPF_SEQ_PRINTF(seq, "%s\n", info);
> > + return 0;
> > + }
> > +
> > + ++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..395591374d4f 100644
> > --- a/tools/testing/selftests/bpf/progs/read_vsyscall.c
> > +++ b/tools/testing/selftests/bpf/progs/read_vsyscall.c
> > @@ -8,14 +8,16 @@
> >
> > 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;
> >
> > SEC("fentry/" SYS_PREFIX "sys_nanosleep")
> > int do_probe_read(void *ctx)
> > @@ -47,6 +49,11 @@ 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);
> >
> > return 0;
> > }
> > --
> > 2.43.5
> >
> >
>
> --
> Best regards,
> Marcus Wichelmann
> Linux Networking Specialist
> Team SDN
>
> ______________________________
>
> Hetzner Cloud GmbH
> Feringastraße 12A
> 85774 Unterföhring
> Germany
>
> Phone: +49 89 381690 150
> E-Mail: marcus.wichelmann@hetzner-cloud.de
>
> Handelsregister München HRB 226782
> Geschäftsführer: Sebastian Färber, Markus Kalmuk
>
> ------------------
> For information on the processing of your personal
> data in the context of this contact, please see
> https://hetzner-cloud.de/datenschutz
> ------------------
>
next prev parent reply other threads:[~2025-02-21 18:27 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-13 15:21 [bpf-next v8 1/3] mm: add copy_remote_vm_str Jordan Rome
2025-02-13 15:21 ` [bpf-next v8 2/3] bpf: Add bpf_copy_from_user_task_str kfunc Jordan Rome
2025-02-13 15:21 ` [bpf-next v8 3/3] selftests/bpf: Add tests for bpf_copy_from_user_task_str Jordan Rome
2025-02-21 15:00 ` Marcus Wichelmann
2025-02-21 18:26 ` Andrii Nakryiko [this message]
2025-02-22 13:19 ` Marcus Wichelmann
2025-02-19 23:33 ` [bpf-next v8 1/3] mm: add copy_remote_vm_str Shakeel Butt
2025-02-20 0:19 ` Andrew Morton
2025-02-20 1:02 ` Andrii Nakryiko
2025-02-20 11:22 ` Jordan Rome
2025-02-20 0:18 ` Andrew Morton
2025-02-20 1:02 ` Andrii Nakryiko
2025-02-20 1:20 ` patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAEf4BzYu9R0_0YghpXaE5-Ojds7W7eURyp+3BsaC4BHp=ZVszg@mail.gmail.com' \
--to=andrii.nakryiko@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=glider@google.com \
--cc=kernel-team@fb.com \
--cc=linux-mm@kvack.org \
--cc=linux@jordanrome.com \
--cc=marcus.wichelmann@hetzner-cloud.de \
--cc=shakeel.butt@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox