Skip to content

Commit 7089f85

Browse files
chenhengqianakryiko
authored andcommitted
selftests/bpf: Add tests for symbol versioning for uprobe
This exercises the newly added dynsym symbol versioning logics. Now we accept symbols in form of func, func@LIB_VERSION or func@@LIB_VERSION. The test rely on liburandom_read.so. For liburandom_read.so, we have: $ nm -D liburandom_read.so w __cxa_finalize@GLIBC_2.17 w __gmon_start__ w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable 0000000000000000 A LIBURANDOM_READ_1.0.0 0000000000000000 A LIBURANDOM_READ_2.0.0 000000000000081c T urandlib_api@@LIBURANDOM_READ_2.0.0 0000000000000814 T urandlib_api@LIBURANDOM_READ_1.0.0 0000000000000824 T urandlib_api_sameoffset@LIBURANDOM_READ_1.0.0 0000000000000824 T urandlib_api_sameoffset@@LIBURANDOM_READ_2.0.0 000000000000082c T urandlib_read_without_sema@@LIBURANDOM_READ_1.0.0 00000000000007c4 T urandlib_read_with_sema@@LIBURANDOM_READ_1.0.0 0000000000011018 D urandlib_read_with_sema_semaphore@@LIBURANDOM_READ_1.0.0 For `urandlib_api`, specifying `urandlib_api` will cause a conflict because there are two symbols named urandlib_api and both are global bind. For `urandlib_api_sameoffset`, there are also two symbols in the .so, but both are at the same offset and essentially they refer to the same function so no conflict. Signed-off-by: Hengqi Chen <hengqi.chen@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Reviewed-by: Alan Maguire <alan.maguire@oracle.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Link: https://lore.kernel.org/bpf/20230918024813.237475-4-hengqi.chen@gmail.com
1 parent bb7fa09 commit 7089f85

6 files changed

Lines changed: 209 additions & 4 deletions

File tree

tools/testing/selftests/bpf/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,12 @@ endif
196196

197197
# Filter out -static for liburandom_read.so and its dependent targets so that static builds
198198
# do not fail. Static builds leave urandom_read relying on system-wide shared libraries.
199-
$(OUTPUT)/liburandom_read.so: urandom_read_lib1.c urandom_read_lib2.c
199+
$(OUTPUT)/liburandom_read.so: urandom_read_lib1.c urandom_read_lib2.c liburandom_read.map
200200
$(call msg,LIB,,$@)
201201
$(Q)$(CLANG) $(filter-out -static,$(CFLAGS) $(LDFLAGS)) \
202-
$^ $(filter-out -static,$(LDLIBS)) \
202+
$(filter %.c,$^) $(filter-out -static,$(LDLIBS)) \
203203
-fuse-ld=$(LLD) -Wl,-znoseparate-code -Wl,--build-id=sha1 \
204+
-Wl,--version-script=liburandom_read.map \
204205
-fPIC -shared -o $@
205206

206207
$(OUTPUT)/urandom_read: urandom_read.c urandom_read_aux.c $(OUTPUT)/liburandom_read.so
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
LIBURANDOM_READ_1.0.0 {
2+
global:
3+
urandlib_api;
4+
urandlib_api_sameoffset;
5+
urandlib_read_without_sema;
6+
urandlib_read_with_sema;
7+
urandlib_read_with_sema_semaphore;
8+
local:
9+
*;
10+
};
11+
12+
LIBURANDOM_READ_2.0.0 {
13+
global:
14+
urandlib_api;
15+
} LIBURANDOM_READ_1.0.0;
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2023 Hengqi Chen */
3+
4+
#include <test_progs.h>
5+
#include "test_uprobe.skel.h"
6+
7+
static FILE *urand_spawn(int *pid)
8+
{
9+
FILE *f;
10+
11+
/* urandom_read's stdout is wired into f */
12+
f = popen("./urandom_read 1 report-pid", "r");
13+
if (!f)
14+
return NULL;
15+
16+
if (fscanf(f, "%d", pid) != 1) {
17+
pclose(f);
18+
errno = EINVAL;
19+
return NULL;
20+
}
21+
22+
return f;
23+
}
24+
25+
static int urand_trigger(FILE **urand_pipe)
26+
{
27+
int exit_code;
28+
29+
/* pclose() waits for child process to exit and returns their exit code */
30+
exit_code = pclose(*urand_pipe);
31+
*urand_pipe = NULL;
32+
33+
return exit_code;
34+
}
35+
36+
void test_uprobe(void)
37+
{
38+
LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
39+
struct test_uprobe *skel;
40+
FILE *urand_pipe = NULL;
41+
int urand_pid = 0, err;
42+
43+
skel = test_uprobe__open_and_load();
44+
if (!ASSERT_OK_PTR(skel, "skel_open"))
45+
return;
46+
47+
urand_pipe = urand_spawn(&urand_pid);
48+
if (!ASSERT_OK_PTR(urand_pipe, "urand_spawn"))
49+
goto cleanup;
50+
51+
skel->bss->my_pid = urand_pid;
52+
53+
/* Manual attach uprobe to urandlib_api
54+
* There are two `urandlib_api` symbols in .dynsym section:
55+
* - urandlib_api@LIBURANDOM_READ_1.0.0
56+
* - urandlib_api@@LIBURANDOM_READ_2.0.0
57+
* Both are global bind and would cause a conflict if user
58+
* specify the symbol name without a version suffix
59+
*/
60+
uprobe_opts.func_name = "urandlib_api";
61+
skel->links.test4 = bpf_program__attach_uprobe_opts(skel->progs.test4,
62+
urand_pid,
63+
"./liburandom_read.so",
64+
0 /* offset */,
65+
&uprobe_opts);
66+
if (!ASSERT_ERR_PTR(skel->links.test4, "urandlib_api_attach_conflict"))
67+
goto cleanup;
68+
69+
uprobe_opts.func_name = "urandlib_api@LIBURANDOM_READ_1.0.0";
70+
skel->links.test4 = bpf_program__attach_uprobe_opts(skel->progs.test4,
71+
urand_pid,
72+
"./liburandom_read.so",
73+
0 /* offset */,
74+
&uprobe_opts);
75+
if (!ASSERT_OK_PTR(skel->links.test4, "urandlib_api_attach_ok"))
76+
goto cleanup;
77+
78+
/* Auto attach 3 u[ret]probes to urandlib_api_sameoffset */
79+
err = test_uprobe__attach(skel);
80+
if (!ASSERT_OK(err, "skel_attach"))
81+
goto cleanup;
82+
83+
/* trigger urandom_read */
84+
ASSERT_OK(urand_trigger(&urand_pipe), "urand_exit_code");
85+
86+
ASSERT_EQ(skel->bss->test1_result, 1, "urandlib_api_sameoffset");
87+
ASSERT_EQ(skel->bss->test2_result, 1, "urandlib_api_sameoffset@v1");
88+
ASSERT_EQ(skel->bss->test3_result, 3, "urandlib_api_sameoffset@@v2");
89+
ASSERT_EQ(skel->bss->test4_result, 1, "urandlib_api");
90+
91+
cleanup:
92+
if (urand_pipe)
93+
pclose(urand_pipe);
94+
test_uprobe__destroy(skel);
95+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2023 Hengqi Chen */
3+
4+
#include "vmlinux.h"
5+
#include <bpf/bpf_helpers.h>
6+
#include <bpf/bpf_tracing.h>
7+
8+
pid_t my_pid = 0;
9+
10+
int test1_result = 0;
11+
int test2_result = 0;
12+
int test3_result = 0;
13+
int test4_result = 0;
14+
15+
SEC("uprobe/./liburandom_read.so:urandlib_api_sameoffset")
16+
int BPF_UPROBE(test1)
17+
{
18+
pid_t pid = bpf_get_current_pid_tgid() >> 32;
19+
20+
if (pid != my_pid)
21+
return 0;
22+
23+
test1_result = 1;
24+
return 0;
25+
}
26+
27+
SEC("uprobe/./liburandom_read.so:urandlib_api_sameoffset@LIBURANDOM_READ_1.0.0")
28+
int BPF_UPROBE(test2)
29+
{
30+
pid_t pid = bpf_get_current_pid_tgid() >> 32;
31+
32+
if (pid != my_pid)
33+
return 0;
34+
35+
test2_result = 1;
36+
return 0;
37+
}
38+
39+
SEC("uretprobe/./liburandom_read.so:urandlib_api_sameoffset@@LIBURANDOM_READ_2.0.0")
40+
int BPF_URETPROBE(test3, int ret)
41+
{
42+
pid_t pid = bpf_get_current_pid_tgid() >> 32;
43+
44+
if (pid != my_pid)
45+
return 0;
46+
47+
test3_result = ret;
48+
return 0;
49+
}
50+
51+
SEC("uprobe")
52+
int BPF_UPROBE(test4)
53+
{
54+
pid_t pid = bpf_get_current_pid_tgid() >> 32;
55+
56+
if (pid != my_pid)
57+
return 0;
58+
59+
test4_result = 1;
60+
return 0;
61+
}

tools/testing/selftests/bpf/urandom_read.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#define _SDT_HAS_SEMAPHORES 1
1212
#include "sdt.h"
1313

14+
#define SHARED 1
15+
#include "bpf/libbpf_internal.h"
16+
1417
#define SEC(name) __attribute__((section(name), used))
1518

1619
#define BUF_SIZE 256
@@ -21,10 +24,14 @@ void urand_read_without_sema(int iter_num, int iter_cnt, int read_sz);
2124
void urandlib_read_with_sema(int iter_num, int iter_cnt, int read_sz);
2225
void urandlib_read_without_sema(int iter_num, int iter_cnt, int read_sz);
2326

27+
int urandlib_api(void);
28+
COMPAT_VERSION(urandlib_api_old, urandlib_api, LIBURANDOM_READ_1.0.0)
29+
int urandlib_api_old(void);
30+
int urandlib_api_sameoffset(void);
31+
2432
unsigned short urand_read_with_sema_semaphore SEC(".probes");
2533

26-
static __attribute__((noinline))
27-
void urandom_read(int fd, int count)
34+
static noinline void urandom_read(int fd, int count)
2835
{
2936
char buf[BUF_SIZE];
3037
int i;
@@ -83,6 +90,10 @@ int main(int argc, char *argv[])
8390

8491
urandom_read(fd, count);
8592

93+
urandlib_api();
94+
urandlib_api_old();
95+
urandlib_api_sameoffset();
96+
8697
close(fd);
8798
return 0;
8899
}

tools/testing/selftests/bpf/urandom_read_lib1.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#define _SDT_HAS_SEMAPHORES 1
44
#include "sdt.h"
55

6+
#define SHARED 1
7+
#include "bpf/libbpf_internal.h"
8+
69
#define SEC(name) __attribute__((section(name), used))
710

811
unsigned short urandlib_read_with_sema_semaphore SEC(".probes");
@@ -11,3 +14,22 @@ void urandlib_read_with_sema(int iter_num, int iter_cnt, int read_sz)
1114
{
1215
STAP_PROBE3(urandlib, read_with_sema, iter_num, iter_cnt, read_sz);
1316
}
17+
18+
COMPAT_VERSION(urandlib_api_v1, urandlib_api, LIBURANDOM_READ_1.0.0)
19+
int urandlib_api_v1(void)
20+
{
21+
return 1;
22+
}
23+
24+
DEFAULT_VERSION(urandlib_api_v2, urandlib_api, LIBURANDOM_READ_2.0.0)
25+
int urandlib_api_v2(void)
26+
{
27+
return 2;
28+
}
29+
30+
COMPAT_VERSION(urandlib_api_sameoffset, urandlib_api_sameoffset, LIBURANDOM_READ_1.0.0)
31+
DEFAULT_VERSION(urandlib_api_sameoffset, urandlib_api_sameoffset, LIBURANDOM_READ_2.0.0)
32+
int urandlib_api_sameoffset(void)
33+
{
34+
return 3;
35+
}

0 commit comments

Comments
 (0)