Skip to content

Commit 552895a

Browse files
committed
Merge branch 'selftests-bpf-add-uprobe-multi-pid-filter-test'
Jiri Olsa says: ==================== selftests/bpf: Add uprobe multi pid filter test hi, sending fix for uprobe multi pid filtering together with tests. The first version included tests for standard uprobes, but as we still do not have fix for that, sending just uprobe multi changes. thanks, jirka v2 changes: - focused on uprobe multi only, removed perf event uprobe specific parts - added fix and test for CLONE_VM process filter --- ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Andrii Nakryiko <[email protected]>
2 parents aa01d13 + d2520bd commit 552895a

File tree

3 files changed

+177
-59
lines changed

3 files changed

+177
-59
lines changed

kernel/trace/bpf_trace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3207,7 +3207,7 @@ static int uprobe_prog_run(struct bpf_uprobe *uprobe,
32073207
struct bpf_run_ctx *old_run_ctx;
32083208
int err = 0;
32093209

3210-
if (link->task && current->mm != link->task->mm)
3210+
if (link->task && !same_thread_group(current, link->task))
32113211
return 0;
32123212

32133213
if (sleepable)

tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c

Lines changed: 136 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "uprobe_multi_bench.skel.h"
88
#include "uprobe_multi_usdt.skel.h"
99
#include "uprobe_multi_consumers.skel.h"
10+
#include "uprobe_multi_pid_filter.skel.h"
1011
#include "bpf/libbpf_internal.h"
1112
#include "testing_helpers.h"
1213
#include "../sdt.h"
@@ -39,6 +40,7 @@ struct child {
3940
int pid;
4041
int tid;
4142
pthread_t thread;
43+
char stack[65536];
4244
};
4345

4446
static void release_child(struct child *child)
@@ -68,41 +70,54 @@ static void kick_child(struct child *child)
6870
fflush(NULL);
6971
}
7072

71-
static struct child *spawn_child(void)
73+
static int child_func(void *arg)
7274
{
73-
static struct child child;
74-
int err;
75-
int c;
75+
struct child *child = arg;
76+
int err, c;
7677

77-
/* pipe to notify child to execute the trigger functions */
78-
if (pipe(child.go))
79-
return NULL;
78+
close(child->go[1]);
8079

81-
child.pid = child.tid = fork();
82-
if (child.pid < 0) {
83-
release_child(&child);
84-
errno = EINVAL;
85-
return NULL;
86-
}
80+
/* wait for parent's kick */
81+
err = read(child->go[0], &c, 1);
82+
if (err != 1)
83+
exit(err);
8784

88-
/* child */
89-
if (child.pid == 0) {
90-
close(child.go[1]);
85+
uprobe_multi_func_1();
86+
uprobe_multi_func_2();
87+
uprobe_multi_func_3();
88+
usdt_trigger();
9189

92-
/* wait for parent's kick */
93-
err = read(child.go[0], &c, 1);
94-
if (err != 1)
95-
exit(err);
90+
exit(errno);
91+
}
9692

97-
uprobe_multi_func_1();
98-
uprobe_multi_func_2();
99-
uprobe_multi_func_3();
100-
usdt_trigger();
93+
static int spawn_child_flag(struct child *child, bool clone_vm)
94+
{
95+
/* pipe to notify child to execute the trigger functions */
96+
if (pipe(child->go))
97+
return -1;
10198

102-
exit(errno);
99+
if (clone_vm) {
100+
child->pid = child->tid = clone(child_func, child->stack + sizeof(child->stack)/2,
101+
CLONE_VM|SIGCHLD, child);
102+
} else {
103+
child->pid = child->tid = fork();
104+
}
105+
if (child->pid < 0) {
106+
release_child(child);
107+
errno = EINVAL;
108+
return -1;
103109
}
104110

105-
return &child;
111+
/* fork-ed child */
112+
if (!clone_vm && child->pid == 0)
113+
child_func(child);
114+
115+
return 0;
116+
}
117+
118+
static int spawn_child(struct child *child)
119+
{
120+
return spawn_child_flag(child, false);
106121
}
107122

108123
static void *child_thread(void *ctx)
@@ -131,39 +146,38 @@ static void *child_thread(void *ctx)
131146
pthread_exit(&err);
132147
}
133148

134-
static struct child *spawn_thread(void)
149+
static int spawn_thread(struct child *child)
135150
{
136-
static struct child child;
137151
int c, err;
138152

139153
/* pipe to notify child to execute the trigger functions */
140-
if (pipe(child.go))
141-
return NULL;
154+
if (pipe(child->go))
155+
return -1;
142156
/* pipe to notify parent that child thread is ready */
143-
if (pipe(child.c2p)) {
144-
close(child.go[0]);
145-
close(child.go[1]);
146-
return NULL;
157+
if (pipe(child->c2p)) {
158+
close(child->go[0]);
159+
close(child->go[1]);
160+
return -1;
147161
}
148162

149-
child.pid = getpid();
163+
child->pid = getpid();
150164

151-
err = pthread_create(&child.thread, NULL, child_thread, &child);
165+
err = pthread_create(&child->thread, NULL, child_thread, child);
152166
if (err) {
153167
err = -errno;
154-
close(child.go[0]);
155-
close(child.go[1]);
156-
close(child.c2p[0]);
157-
close(child.c2p[1]);
168+
close(child->go[0]);
169+
close(child->go[1]);
170+
close(child->c2p[0]);
171+
close(child->c2p[1]);
158172
errno = -err;
159-
return NULL;
173+
return -1;
160174
}
161175

162-
err = read(child.c2p[0], &c, 1);
176+
err = read(child->c2p[0], &c, 1);
163177
if (!ASSERT_EQ(err, 1, "child_thread_ready"))
164-
return NULL;
178+
return -1;
165179

166-
return &child;
180+
return 0;
167181
}
168182

169183
static void uprobe_multi_test_run(struct uprobe_multi *skel, struct child *child)
@@ -304,24 +318,22 @@ __test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_mul
304318
static void
305319
test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_multi_opts *opts)
306320
{
307-
struct child *child;
321+
static struct child child;
308322

309323
/* no pid filter */
310324
__test_attach_api(binary, pattern, opts, NULL);
311325

312326
/* pid filter */
313-
child = spawn_child();
314-
if (!ASSERT_OK_PTR(child, "spawn_child"))
327+
if (!ASSERT_OK(spawn_child(&child), "spawn_child"))
315328
return;
316329

317-
__test_attach_api(binary, pattern, opts, child);
330+
__test_attach_api(binary, pattern, opts, &child);
318331

319332
/* pid filter (thread) */
320-
child = spawn_thread();
321-
if (!ASSERT_OK_PTR(child, "spawn_thread"))
333+
if (!ASSERT_OK(spawn_thread(&child), "spawn_thread"))
322334
return;
323335

324-
__test_attach_api(binary, pattern, opts, child);
336+
__test_attach_api(binary, pattern, opts, &child);
325337
}
326338

327339
static void test_attach_api_pattern(void)
@@ -712,24 +724,22 @@ static void __test_link_api(struct child *child)
712724

713725
static void test_link_api(void)
714726
{
715-
struct child *child;
727+
static struct child child;
716728

717729
/* no pid filter */
718730
__test_link_api(NULL);
719731

720732
/* pid filter */
721-
child = spawn_child();
722-
if (!ASSERT_OK_PTR(child, "spawn_child"))
733+
if (!ASSERT_OK(spawn_child(&child), "spawn_child"))
723734
return;
724735

725-
__test_link_api(child);
736+
__test_link_api(&child);
726737

727738
/* pid filter (thread) */
728-
child = spawn_thread();
729-
if (!ASSERT_OK_PTR(child, "spawn_thread"))
739+
if (!ASSERT_OK(spawn_thread(&child), "spawn_thread"))
730740
return;
731741

732-
__test_link_api(child);
742+
__test_link_api(&child);
733743
}
734744

735745
static struct bpf_program *
@@ -942,6 +952,70 @@ static void test_consumers(void)
942952
uprobe_multi_consumers__destroy(skel);
943953
}
944954

955+
static struct bpf_program *uprobe_multi_program(struct uprobe_multi_pid_filter *skel, int idx)
956+
{
957+
switch (idx) {
958+
case 0: return skel->progs.uprobe_multi_0;
959+
case 1: return skel->progs.uprobe_multi_1;
960+
case 2: return skel->progs.uprobe_multi_2;
961+
}
962+
return NULL;
963+
}
964+
965+
#define TASKS 3
966+
967+
static void run_pid_filter(struct uprobe_multi_pid_filter *skel, bool clone_vm, bool retprobe)
968+
{
969+
LIBBPF_OPTS(bpf_uprobe_multi_opts, opts, .retprobe = retprobe);
970+
struct bpf_link *link[TASKS] = {};
971+
struct child child[TASKS] = {};
972+
int i;
973+
974+
memset(skel->bss->test, 0, sizeof(skel->bss->test));
975+
976+
for (i = 0; i < TASKS; i++) {
977+
if (!ASSERT_OK(spawn_child_flag(&child[i], clone_vm), "spawn_child"))
978+
goto cleanup;
979+
skel->bss->pids[i] = child[i].pid;
980+
}
981+
982+
for (i = 0; i < TASKS; i++) {
983+
link[i] = bpf_program__attach_uprobe_multi(uprobe_multi_program(skel, i),
984+
child[i].pid, "/proc/self/exe",
985+
"uprobe_multi_func_1", &opts);
986+
if (!ASSERT_OK_PTR(link[i], "bpf_program__attach_uprobe_multi"))
987+
goto cleanup;
988+
}
989+
990+
for (i = 0; i < TASKS; i++)
991+
kick_child(&child[i]);
992+
993+
for (i = 0; i < TASKS; i++) {
994+
ASSERT_EQ(skel->bss->test[i][0], 1, "pid");
995+
ASSERT_EQ(skel->bss->test[i][1], 0, "unknown");
996+
}
997+
998+
cleanup:
999+
for (i = 0; i < TASKS; i++)
1000+
bpf_link__destroy(link[i]);
1001+
for (i = 0; i < TASKS; i++)
1002+
release_child(&child[i]);
1003+
}
1004+
1005+
static void test_pid_filter_process(bool clone_vm)
1006+
{
1007+
struct uprobe_multi_pid_filter *skel;
1008+
1009+
skel = uprobe_multi_pid_filter__open_and_load();
1010+
if (!ASSERT_OK_PTR(skel, "uprobe_multi_pid_filter__open_and_load"))
1011+
return;
1012+
1013+
run_pid_filter(skel, clone_vm, false);
1014+
run_pid_filter(skel, clone_vm, true);
1015+
1016+
uprobe_multi_pid_filter__destroy(skel);
1017+
}
1018+
9451019
static void test_bench_attach_uprobe(void)
9461020
{
9471021
long attach_start_ns = 0, attach_end_ns = 0;
@@ -1034,4 +1108,8 @@ void test_uprobe_multi_test(void)
10341108
test_attach_uprobe_fails();
10351109
if (test__start_subtest("consumers"))
10361110
test_consumers();
1111+
if (test__start_subtest("filter_fork"))
1112+
test_pid_filter_process(false);
1113+
if (test__start_subtest("filter_clone_vm"))
1114+
test_pid_filter_process(true);
10371115
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include "vmlinux.h"
3+
#include <bpf/bpf_helpers.h>
4+
#include <bpf/bpf_tracing.h>
5+
6+
char _license[] SEC("license") = "GPL";
7+
8+
__u32 pids[3];
9+
__u32 test[3][2];
10+
11+
static void update_pid(int idx)
12+
{
13+
__u32 pid = bpf_get_current_pid_tgid() >> 32;
14+
15+
if (pid == pids[idx])
16+
test[idx][0]++;
17+
else
18+
test[idx][1]++;
19+
}
20+
21+
SEC("uprobe.multi")
22+
int uprobe_multi_0(struct pt_regs *ctx)
23+
{
24+
update_pid(0);
25+
return 0;
26+
}
27+
28+
SEC("uprobe.multi")
29+
int uprobe_multi_1(struct pt_regs *ctx)
30+
{
31+
update_pid(1);
32+
return 0;
33+
}
34+
35+
SEC("uprobe.multi")
36+
int uprobe_multi_2(struct pt_regs *ctx)
37+
{
38+
update_pid(2);
39+
return 0;
40+
}

0 commit comments

Comments
 (0)