diff mbox series

[bpf-next,v6,09/14] selftests/bpf: Make uprobe tests use different attach functions.

Message ID 20211006185619.364369-10-fallentree@fb.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series selftests/bpf: Add parallelism to test_progs | expand

Checks

Context Check Description
netdev/cover_letter success Series has a cover letter
netdev/fixes_present success Fixes tag not required for -next series
netdev/patch_count success Link
netdev/tree_selection success Clearly marked for bpf-next
netdev/subject_prefix success Link
netdev/cc_maintainers warning 14 maintainers not CCed: linux-kselftest@vger.kernel.org jean-philippe@linaro.org netdev@vger.kernel.org shuah@kernel.org kafai@fb.com dxu@dxuuu.xyz daniel@iogearbox.net yhs@fb.com iii@linux.ibm.com john.fastabend@gmail.com jolsa@kernel.org songliubraving@fb.com kpsingh@kernel.org ast@kernel.org
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/module_param success Was 0 now: 0
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/verify_fixes success No Fixes tag
netdev/checkpatch fail ERROR: Bad function definition - int method() should probably be int method(void) ERROR: open brace '{' following function definitions go on the next line
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/header_inline success No static functions without inline keyword in header files
bpf/vmtest-bpf-next success VM_Test
bpf/vmtest-bpf-next-PR success PR summary

Commit Message

Yucong Sun Oct. 6, 2021, 6:56 p.m. UTC
From: Yucong Sun <sunyucong@gmail.com>

Using same address on different processes of the same binary often fail
with EINVAL, this patch make these tests use distinct methods, so they
can run in parallel.

Signed-off-by: Yucong Sun <sunyucong@gmail.com>
---
 tools/testing/selftests/bpf/prog_tests/attach_probe.c | 8 ++++++--
 tools/testing/selftests/bpf/prog_tests/bpf_cookie.c   | 8 ++++++--
 tools/testing/selftests/bpf/prog_tests/task_pt_regs.c | 8 ++++++--
 3 files changed, 18 insertions(+), 6 deletions(-)

Comments

Andrii Nakryiko Oct. 8, 2021, 10:27 p.m. UTC | #1
On Wed, Oct 6, 2021 at 11:56 AM Yucong Sun <fallentree@fb.com> wrote:
>
> From: Yucong Sun <sunyucong@gmail.com>
>
> Using same address on different processes of the same binary often fail
> with EINVAL, this patch make these tests use distinct methods, so they
> can run in parallel.
>
> Signed-off-by: Yucong Sun <sunyucong@gmail.com>
> ---
>  tools/testing/selftests/bpf/prog_tests/attach_probe.c | 8 ++++++--
>  tools/testing/selftests/bpf/prog_tests/bpf_cookie.c   | 8 ++++++--
>  tools/testing/selftests/bpf/prog_tests/task_pt_regs.c | 8 ++++++--
>  3 files changed, 18 insertions(+), 6 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/attach_probe.c b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
> index 6c511dcd1465..eff36ba9c148 100644
> --- a/tools/testing/selftests/bpf/prog_tests/attach_probe.c
> +++ b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
> @@ -5,6 +5,10 @@
>  /* this is how USDT semaphore is actually defined, except volatile modifier */
>  volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes")));
>
> +static int method() {

wrong style: { should be on separate line

> +       return get_base_addr();

there is nothing special about get_base_addr(), except that it's a
global function in a different file and won't be inlined, while this
method() approach has no such guarantee

I've dropped this patch for now.

But I'm surprised that attaching to the same uprobe few times doesn't
work. Song, is there anything in kernel that could cause this?


> +}
> +
>  void test_attach_probe(void)
>  {
>         DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
> @@ -33,7 +37,7 @@ void test_attach_probe(void)
>         if (CHECK(base_addr < 0, "get_base_addr",
>                   "failed to find base addr: %zd", base_addr))
>                 return;
> -       uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
> +       uprobe_offset = get_uprobe_offset(&method, base_addr);
>
>         ref_ctr_offset = get_rel_offset((uintptr_t)&uprobe_ref_ctr);
>         if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset"))
> @@ -98,7 +102,7 @@ void test_attach_probe(void)
>                 goto cleanup;
>
>         /* trigger & validate uprobe & uretprobe */
> -       get_base_addr();
> +       method();
>
>         if (CHECK(skel->bss->uprobe_res != 3, "check_uprobe_res",
>                   "wrong uprobe res: %d\n", skel->bss->uprobe_res))
> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
> index 19c9f7b53cfa..5ebd8ba988e2 100644
> --- a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
> @@ -8,6 +8,10 @@
>  #include <test_progs.h>
>  #include "test_bpf_cookie.skel.h"
>
> +static int method() {
> +       return get_base_addr();
> +}
> +
>  static void kprobe_subtest(struct test_bpf_cookie *skel)
>  {
>         DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts);
> @@ -66,7 +70,7 @@ static void uprobe_subtest(struct test_bpf_cookie *skel)
>         ssize_t base_addr;
>
>         base_addr = get_base_addr();
> -       uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
> +       uprobe_offset = get_uprobe_offset(&method, base_addr);
>
>         /* attach two uprobes */
>         opts.bpf_cookie = 0x100;
> @@ -99,7 +103,7 @@ static void uprobe_subtest(struct test_bpf_cookie *skel)
>                 goto cleanup;
>
>         /* trigger uprobe && uretprobe */
> -       get_base_addr();
> +       method();
>
>         ASSERT_EQ(skel->bss->uprobe_res, 0x100 | 0x200, "uprobe_res");
>         ASSERT_EQ(skel->bss->uretprobe_res, 0x1000 | 0x2000, "uretprobe_res");
> diff --git a/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c b/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c
> index 37c20b5ffa70..4d2f1435be90 100644
> --- a/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c
> +++ b/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c
> @@ -3,6 +3,10 @@
>  #include <test_progs.h>
>  #include "test_task_pt_regs.skel.h"
>
> +static int method() {
> +       return get_base_addr();
> +}
> +
>  void test_task_pt_regs(void)
>  {
>         struct test_task_pt_regs *skel;
> @@ -14,7 +18,7 @@ void test_task_pt_regs(void)
>         base_addr = get_base_addr();
>         if (!ASSERT_GT(base_addr, 0, "get_base_addr"))
>                 return;
> -       uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
> +       uprobe_offset = get_uprobe_offset(&method, base_addr);
>
>         skel = test_task_pt_regs__open_and_load();
>         if (!ASSERT_OK_PTR(skel, "skel_open"))
> @@ -32,7 +36,7 @@ void test_task_pt_regs(void)
>         skel->links.handle_uprobe = uprobe_link;
>
>         /* trigger & validate uprobe */
> -       get_base_addr();
> +       method();
>
>         if (!ASSERT_EQ(skel->bss->uprobe_res, 1, "check_uprobe_res"))
>                 goto cleanup;
> --
> 2.30.2
>
sunyucong@gmail.com Oct. 8, 2021, 10:46 p.m. UTC | #2
On Fri, Oct 8, 2021 at 3:27 PM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Wed, Oct 6, 2021 at 11:56 AM Yucong Sun <fallentree@fb.com> wrote:
> >
> > From: Yucong Sun <sunyucong@gmail.com>
> >
> > Using same address on different processes of the same binary often fail
> > with EINVAL, this patch make these tests use distinct methods, so they
> > can run in parallel.
> >
> > Signed-off-by: Yucong Sun <sunyucong@gmail.com>
> > ---
> >  tools/testing/selftests/bpf/prog_tests/attach_probe.c | 8 ++++++--
> >  tools/testing/selftests/bpf/prog_tests/bpf_cookie.c   | 8 ++++++--
> >  tools/testing/selftests/bpf/prog_tests/task_pt_regs.c | 8 ++++++--
> >  3 files changed, 18 insertions(+), 6 deletions(-)
> >
> > diff --git a/tools/testing/selftests/bpf/prog_tests/attach_probe.c b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
> > index 6c511dcd1465..eff36ba9c148 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/attach_probe.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
> > @@ -5,6 +5,10 @@
> >  /* this is how USDT semaphore is actually defined, except volatile modifier */
> >  volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes")));
> >
> > +static int method() {
>
> wrong style: { should be on separate line
>
> > +       return get_base_addr();
>
> there is nothing special about get_base_addr(), except that it's a
> global function in a different file and won't be inlined, while this
> method() approach has no such guarantee
>
> I've dropped this patch for now.
>
> But I'm surprised that attaching to the same uprobe few times doesn't
> work. Song, is there anything in kernel that could cause this?


libbpf: uprobe perf_event_open() failed: Invalid argument
libbpf: prog 'handle_uprobe': failed to create uprobe
'/proc/self/exe:0x144d59' perf event: Invalid argument
uprobe_subtest:FAIL:link1 unexpected error: -22

The problem only happens when several different processes of the same
binary are trying to attach uprobe on the same function. I am guessing
it is due to address space randomization ?

I traced through the code and the EINVAL is returned right after this warning

[    1.375901] ref_ctr_offset mismatch. inode: 0x55a0 offset: 0x144d59
ref_ctr_offset(old): 0x554a00 ref_ctr_offset(new): 0x0


This could be easily be reproduced by    ./test_progs -t
attach_probe,bpf_cookie,test_pt_regs -j

>
>
> > +}
> > +
> >  void test_attach_probe(void)
> >  {
> >         DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
> > @@ -33,7 +37,7 @@ void test_attach_probe(void)
> >         if (CHECK(base_addr < 0, "get_base_addr",
> >                   "failed to find base addr: %zd", base_addr))
> >                 return;
> > -       uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
> > +       uprobe_offset = get_uprobe_offset(&method, base_addr);
> >
> >         ref_ctr_offset = get_rel_offset((uintptr_t)&uprobe_ref_ctr);
> >         if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset"))
> > @@ -98,7 +102,7 @@ void test_attach_probe(void)
> >                 goto cleanup;
> >
> >         /* trigger & validate uprobe & uretprobe */
> > -       get_base_addr();
> > +       method();
> >
> >         if (CHECK(skel->bss->uprobe_res != 3, "check_uprobe_res",
> >                   "wrong uprobe res: %d\n", skel->bss->uprobe_res))
> > diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
> > index 19c9f7b53cfa..5ebd8ba988e2 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
> > @@ -8,6 +8,10 @@
> >  #include <test_progs.h>
> >  #include "test_bpf_cookie.skel.h"
> >
> > +static int method() {
> > +       return get_base_addr();
> > +}
> > +
> >  static void kprobe_subtest(struct test_bpf_cookie *skel)
> >  {
> >         DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts);
> > @@ -66,7 +70,7 @@ static void uprobe_subtest(struct test_bpf_cookie *skel)
> >         ssize_t base_addr;
> >
> >         base_addr = get_base_addr();
> > -       uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
> > +       uprobe_offset = get_uprobe_offset(&method, base_addr);
> >
> >         /* attach two uprobes */
> >         opts.bpf_cookie = 0x100;
> > @@ -99,7 +103,7 @@ static void uprobe_subtest(struct test_bpf_cookie *skel)
> >                 goto cleanup;
> >
> >         /* trigger uprobe && uretprobe */
> > -       get_base_addr();
> > +       method();
> >
> >         ASSERT_EQ(skel->bss->uprobe_res, 0x100 | 0x200, "uprobe_res");
> >         ASSERT_EQ(skel->bss->uretprobe_res, 0x1000 | 0x2000, "uretprobe_res");
> > diff --git a/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c b/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c
> > index 37c20b5ffa70..4d2f1435be90 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c
> > @@ -3,6 +3,10 @@
> >  #include <test_progs.h>
> >  #include "test_task_pt_regs.skel.h"
> >
> > +static int method() {
> > +       return get_base_addr();
> > +}
> > +
> >  void test_task_pt_regs(void)
> >  {
> >         struct test_task_pt_regs *skel;
> > @@ -14,7 +18,7 @@ void test_task_pt_regs(void)
> >         base_addr = get_base_addr();
> >         if (!ASSERT_GT(base_addr, 0, "get_base_addr"))
> >                 return;
> > -       uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
> > +       uprobe_offset = get_uprobe_offset(&method, base_addr);
> >
> >         skel = test_task_pt_regs__open_and_load();
> >         if (!ASSERT_OK_PTR(skel, "skel_open"))
> > @@ -32,7 +36,7 @@ void test_task_pt_regs(void)
> >         skel->links.handle_uprobe = uprobe_link;
> >
> >         /* trigger & validate uprobe */
> > -       get_base_addr();
> > +       method();
> >
> >         if (!ASSERT_EQ(skel->bss->uprobe_res, 1, "check_uprobe_res"))
> >                 goto cleanup;
> > --
> > 2.30.2
> >
Andrii Nakryiko Oct. 9, 2021, 3:13 a.m. UTC | #3
On Fri, Oct 8, 2021 at 3:47 PM sunyucong@gmail.com <sunyucong@gmail.com> wrote:
>
> On Fri, Oct 8, 2021 at 3:27 PM Andrii Nakryiko
> <andrii.nakryiko@gmail.com> wrote:
> >
> > On Wed, Oct 6, 2021 at 11:56 AM Yucong Sun <fallentree@fb.com> wrote:
> > >
> > > From: Yucong Sun <sunyucong@gmail.com>
> > >
> > > Using same address on different processes of the same binary often fail
> > > with EINVAL, this patch make these tests use distinct methods, so they
> > > can run in parallel.
> > >
> > > Signed-off-by: Yucong Sun <sunyucong@gmail.com>
> > > ---
> > >  tools/testing/selftests/bpf/prog_tests/attach_probe.c | 8 ++++++--
> > >  tools/testing/selftests/bpf/prog_tests/bpf_cookie.c   | 8 ++++++--
> > >  tools/testing/selftests/bpf/prog_tests/task_pt_regs.c | 8 ++++++--
> > >  3 files changed, 18 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/tools/testing/selftests/bpf/prog_tests/attach_probe.c b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
> > > index 6c511dcd1465..eff36ba9c148 100644
> > > --- a/tools/testing/selftests/bpf/prog_tests/attach_probe.c
> > > +++ b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
> > > @@ -5,6 +5,10 @@
> > >  /* this is how USDT semaphore is actually defined, except volatile modifier */
> > >  volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes")));
> > >
> > > +static int method() {
> >
> > wrong style: { should be on separate line
> >
> > > +       return get_base_addr();
> >
> > there is nothing special about get_base_addr(), except that it's a
> > global function in a different file and won't be inlined, while this
> > method() approach has no such guarantee
> >
> > I've dropped this patch for now.
> >
> > But I'm surprised that attaching to the same uprobe few times doesn't
> > work. Song, is there anything in kernel that could cause this?
>
>
> libbpf: uprobe perf_event_open() failed: Invalid argument
> libbpf: prog 'handle_uprobe': failed to create uprobe
> '/proc/self/exe:0x144d59' perf event: Invalid argument
> uprobe_subtest:FAIL:link1 unexpected error: -22
>
> The problem only happens when several different processes of the same
> binary are trying to attach uprobe on the same function. I am guessing
> it is due to address space randomization ?

nope, we don't use address space randomization, it's the
ref_ctr_offset (normally used for USDT semaphore)

>
> I traced through the code and the EINVAL is returned right after this warning
>
> [    1.375901] ref_ctr_offset mismatch. inode: 0x55a0 offset: 0x144d59
> ref_ctr_offset(old): 0x554a00 ref_ctr_offset(new): 0x0

ah, ref_ctr_offset is probably enforced by the kernel to be the same
across all uprobes. attach_probe is the only one that's testing
ref_ctr_offset, so it should be enough to modify only that one, just
make sure you are using a non-inlined function for this.

>
>
> This could be easily be reproduced by    ./test_progs -t
> attach_probe,bpf_cookie,test_pt_regs -j
>
> >
> >
> > > +}
> > > +

[...]
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/prog_tests/attach_probe.c b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
index 6c511dcd1465..eff36ba9c148 100644
--- a/tools/testing/selftests/bpf/prog_tests/attach_probe.c
+++ b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
@@ -5,6 +5,10 @@ 
 /* this is how USDT semaphore is actually defined, except volatile modifier */
 volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes")));
 
+static int method() {
+	return get_base_addr();
+}
+
 void test_attach_probe(void)
 {
 	DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
@@ -33,7 +37,7 @@  void test_attach_probe(void)
 	if (CHECK(base_addr < 0, "get_base_addr",
 		  "failed to find base addr: %zd", base_addr))
 		return;
-	uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
+	uprobe_offset = get_uprobe_offset(&method, base_addr);
 
 	ref_ctr_offset = get_rel_offset((uintptr_t)&uprobe_ref_ctr);
 	if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset"))
@@ -98,7 +102,7 @@  void test_attach_probe(void)
 		goto cleanup;
 
 	/* trigger & validate uprobe & uretprobe */
-	get_base_addr();
+	method();
 
 	if (CHECK(skel->bss->uprobe_res != 3, "check_uprobe_res",
 		  "wrong uprobe res: %d\n", skel->bss->uprobe_res))
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
index 19c9f7b53cfa..5ebd8ba988e2 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
@@ -8,6 +8,10 @@ 
 #include <test_progs.h>
 #include "test_bpf_cookie.skel.h"
 
+static int method() {
+	return get_base_addr();
+}
+
 static void kprobe_subtest(struct test_bpf_cookie *skel)
 {
 	DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts);
@@ -66,7 +70,7 @@  static void uprobe_subtest(struct test_bpf_cookie *skel)
 	ssize_t base_addr;
 
 	base_addr = get_base_addr();
-	uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
+	uprobe_offset = get_uprobe_offset(&method, base_addr);
 
 	/* attach two uprobes */
 	opts.bpf_cookie = 0x100;
@@ -99,7 +103,7 @@  static void uprobe_subtest(struct test_bpf_cookie *skel)
 		goto cleanup;
 
 	/* trigger uprobe && uretprobe */
-	get_base_addr();
+	method();
 
 	ASSERT_EQ(skel->bss->uprobe_res, 0x100 | 0x200, "uprobe_res");
 	ASSERT_EQ(skel->bss->uretprobe_res, 0x1000 | 0x2000, "uretprobe_res");
diff --git a/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c b/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c
index 37c20b5ffa70..4d2f1435be90 100644
--- a/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c
+++ b/tools/testing/selftests/bpf/prog_tests/task_pt_regs.c
@@ -3,6 +3,10 @@ 
 #include <test_progs.h>
 #include "test_task_pt_regs.skel.h"
 
+static int method() {
+	return get_base_addr();
+}
+
 void test_task_pt_regs(void)
 {
 	struct test_task_pt_regs *skel;
@@ -14,7 +18,7 @@  void test_task_pt_regs(void)
 	base_addr = get_base_addr();
 	if (!ASSERT_GT(base_addr, 0, "get_base_addr"))
 		return;
-	uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
+	uprobe_offset = get_uprobe_offset(&method, base_addr);
 
 	skel = test_task_pt_regs__open_and_load();
 	if (!ASSERT_OK_PTR(skel, "skel_open"))
@@ -32,7 +36,7 @@  void test_task_pt_regs(void)
 	skel->links.handle_uprobe = uprobe_link;
 
 	/* trigger & validate uprobe */
-	get_base_addr();
+	method();
 
 	if (!ASSERT_EQ(skel->bss->uprobe_res, 1, "check_uprobe_res"))
 		goto cleanup;