selftests/bpf: Add ref_ctr_offset selftests
authorAndrii Nakryiko <andrii@kernel.org>
Sun, 15 Aug 2021 07:06:09 +0000 (00:06 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Mon, 16 Aug 2021 22:45:08 +0000 (00:45 +0200)
Extend attach_probe selftests to specify ref_ctr_offset for uprobe/uretprobe
and validate that its value is incremented from zero.

Turns out that once uprobe is attached with ref_ctr_offset, uretprobe for the
same location/function *has* to use ref_ctr_offset as well, otherwise
perf_event_open() fails with -EINVAL. So this test uses ref_ctr_offset for
both uprobe and uretprobe, even though for the purpose of test uprobe would be
enough.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20210815070609.987780-17-andrii@kernel.org
tools/testing/selftests/bpf/prog_tests/attach_probe.c
tools/testing/selftests/bpf/trace_helpers.c
tools/testing/selftests/bpf/trace_helpers.h

index e40b41c..bf307bb 100644 (file)
@@ -2,14 +2,18 @@
 #include <test_progs.h>
 #include "test_attach_probe.skel.h"
 
+/* this is how USDT semaphore is actually defined, except volatile modifier */
+volatile unsigned short uprobe_ref_ctr __attribute__((unused)) __attribute((section(".probes")));
+
 void test_attach_probe(void)
 {
+       DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
        int duration = 0;
        struct bpf_link *kprobe_link, *kretprobe_link;
        struct bpf_link *uprobe_link, *uretprobe_link;
        struct test_attach_probe* skel;
        size_t uprobe_offset;
-       ssize_t base_addr;
+       ssize_t base_addr, ref_ctr_offset;
 
        base_addr = get_base_addr();
        if (CHECK(base_addr < 0, "get_base_addr",
@@ -17,6 +21,10 @@ void test_attach_probe(void)
                return;
        uprobe_offset = get_uprobe_offset(&get_base_addr, base_addr);
 
+       ref_ctr_offset = get_rel_offset((uintptr_t)&uprobe_ref_ctr);
+       if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset"))
+               return;
+
        skel = test_attach_probe__open_and_load();
        if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
                return;
@@ -37,20 +45,28 @@ void test_attach_probe(void)
                goto cleanup;
        skel->links.handle_kretprobe = kretprobe_link;
 
-       uprobe_link = bpf_program__attach_uprobe(skel->progs.handle_uprobe,
-                                                false /* retprobe */,
-                                                0 /* self pid */,
-                                                "/proc/self/exe",
-                                                uprobe_offset);
+       ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_before");
+
+       uprobe_opts.retprobe = false;
+       uprobe_opts.ref_ctr_offset = ref_ctr_offset;
+       uprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uprobe,
+                                                     0 /* self pid */,
+                                                     "/proc/self/exe",
+                                                     uprobe_offset,
+                                                     &uprobe_opts);
        if (!ASSERT_OK_PTR(uprobe_link, "attach_uprobe"))
                goto cleanup;
        skel->links.handle_uprobe = uprobe_link;
 
-       uretprobe_link = bpf_program__attach_uprobe(skel->progs.handle_uretprobe,
-                                                   true /* retprobe */,
-                                                   -1 /* any pid */,
-                                                   "/proc/self/exe",
-                                                   uprobe_offset);
+       ASSERT_GT(uprobe_ref_ctr, 0, "uprobe_ref_ctr_after");
+
+       /* if uprobe uses ref_ctr, uretprobe has to use ref_ctr as well */
+       uprobe_opts.retprobe = true;
+       uprobe_opts.ref_ctr_offset = ref_ctr_offset;
+       uretprobe_link = bpf_program__attach_uprobe_opts(skel->progs.handle_uretprobe,
+                                                        -1 /* any pid */,
+                                                        "/proc/self/exe",
+                                                        uprobe_offset, &uprobe_opts);
        if (!ASSERT_OK_PTR(uretprobe_link, "attach_uretprobe"))
                goto cleanup;
        skel->links.handle_uretprobe = uretprobe_link;
@@ -77,4 +93,5 @@ void test_attach_probe(void)
 
 cleanup:
        test_attach_probe__destroy(skel);
+       ASSERT_EQ(uprobe_ref_ctr, 0, "uprobe_ref_ctr_cleanup");
 }
index 381dafc..e7a19b0 100644 (file)
@@ -202,3 +202,24 @@ ssize_t get_base_addr(void)
        fclose(f);
        return -EINVAL;
 }
+
+ssize_t get_rel_offset(uintptr_t addr)
+{
+       size_t start, end, offset;
+       char buf[256];
+       FILE *f;
+
+       f = fopen("/proc/self/maps", "r");
+       if (!f)
+               return -errno;
+
+       while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) {
+               if (addr >= start && addr < end) {
+                       fclose(f);
+                       return (size_t)addr - start + offset;
+               }
+       }
+
+       fclose(f);
+       return -EINVAL;
+}
index 3d9435b..d907b44 100644 (file)
@@ -20,5 +20,6 @@ void read_trace_pipe(void);
 
 ssize_t get_uprobe_offset(const void *addr, ssize_t base);
 ssize_t get_base_addr(void);
+ssize_t get_rel_offset(uintptr_t addr);
 
 #endif