Skip to content

Commit bfebc3b

Browse files
olsajiriKernel Patches Daemon
authored andcommitted
selftests/bpf: Add tests for forked/cloned optimized uprobes
Adding tests for forked/cloned optimized uprobes and make sure the child can properly execute optimized probe for both fork (dups mm) and clone with CLONE_VM. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
1 parent 55a8384 commit bfebc3b

1 file changed

Lines changed: 88 additions & 0 deletions

File tree

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

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#ifdef __x86_64__
66

7+
#define _GNU_SOURCE
8+
#include <sched.h>
79
#include <unistd.h>
810
#include <asm/ptrace.h>
911
#include <linux/compiler.h>
@@ -936,6 +938,88 @@ static void test_uprobe_error(void)
936938
ASSERT_EQ(errno, EPROTO, "errno");
937939
}
938940

941+
__attribute__((aligned(16)))
942+
__nocf_check __weak __naked void uprobe_fork_test(void)
943+
{
944+
asm volatile (
945+
".byte 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00\n" /* nop10 */
946+
"ret\n"
947+
);
948+
}
949+
950+
static int child_func(void *arg)
951+
{
952+
struct uprobe_syscall_executed *skel = arg;
953+
954+
/* Make sure the child's probe is still there and optimized.. */
955+
if (memcmp(uprobe_fork_test, lea_rsp, sizeof(lea_rsp)))
956+
_exit(1);
957+
958+
skel->bss->pid = getpid();
959+
960+
/* .. and it executes properly. */
961+
uprobe_fork_test();
962+
963+
if (skel->bss->executed != 3)
964+
_exit(2);
965+
966+
_exit(0);
967+
}
968+
969+
static void test_uprobe_fork_optimized(bool clone_vm)
970+
{
971+
struct uprobe_syscall_executed *skel = NULL;
972+
struct bpf_link *link = NULL;
973+
unsigned long offset;
974+
int pid, status, err;
975+
char stack[65535];
976+
977+
offset = get_uprobe_offset(&uprobe_fork_test);
978+
if (!ASSERT_GE(offset, 0, "get_uprobe_offset"))
979+
return;
980+
981+
skel = uprobe_syscall_executed__open_and_load();
982+
if (!ASSERT_OK_PTR(skel, "open_and_load"))
983+
goto cleanup;
984+
985+
link = bpf_program__attach_uprobe_opts(skel->progs.test_uprobe,
986+
-1, "/proc/self/exe", offset, NULL);
987+
if (!ASSERT_OK_PTR(link, "attach_uprobe"))
988+
goto cleanup;
989+
990+
skel->bss->pid = getpid();
991+
992+
/* Trigger optimization of uprobe in uprobe_fork_test. */
993+
uprobe_fork_test();
994+
uprobe_fork_test();
995+
996+
/* Make sure it got optimied. */
997+
if (!ASSERT_OK(memcmp(uprobe_fork_test, lea_rsp, sizeof(lea_rsp)), "optimized"))
998+
goto cleanup;
999+
1000+
if (clone_vm) {
1001+
pid = clone(child_func, stack + sizeof(stack), CLONE_VM|SIGCHLD, skel);
1002+
if (!ASSERT_GT(pid, 0, "clone"))
1003+
goto cleanup;
1004+
} else {
1005+
pid = fork();
1006+
if (!ASSERT_GE(pid, 0, "fork"))
1007+
goto cleanup;
1008+
if (pid == 0)
1009+
child_func(skel);
1010+
}
1011+
1012+
/* Wait for the child and verify it exited properly with 0. */
1013+
err = waitpid(pid, &status, 0);
1014+
if (ASSERT_EQ(err, pid, "waitpid")) {
1015+
ASSERT_EQ(WIFEXITED(status), 1, "child_exited");
1016+
ASSERT_EQ(WEXITSTATUS(status), 0, "child_exit_code");
1017+
}
1018+
1019+
cleanup:
1020+
uprobe_syscall_executed__destroy(skel);
1021+
}
1022+
9391023
static void __test_uprobe_syscall(void)
9401024
{
9411025
if (test__start_subtest("uretprobe_regs_equal"))
@@ -956,6 +1040,10 @@ static void __test_uprobe_syscall(void)
9561040
test_uprobe_race();
9571041
if (test__start_subtest("uprobe_red_zone"))
9581042
test_uprobe_red_zone();
1043+
if (test__start_subtest("uprobe_optimized_fork"))
1044+
test_uprobe_fork_optimized(false);
1045+
if (test__start_subtest("uprobe_optimized_clone_vm"))
1046+
test_uprobe_fork_optimized(true);
9591047
if (test__start_subtest("uprobe_error"))
9601048
test_uprobe_error();
9611049
if (test__start_subtest("uprobe_regs_equal"))

0 commit comments

Comments
 (0)