Skip to content

Commit f5ee7d5

Browse files
olsajirianakryiko
authored andcommitted
selftests/bpf: Add uprobe fail tests for uprobe multi
Adding tests for checking on recovery after failing to attach uprobe. Signed-off-by: Jiri Olsa <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent c67b2a6 commit f5ee7d5

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

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

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,122 @@ static void test_attach_api_fails(void)
516516
uprobe_multi__destroy(skel);
517517
}
518518

519+
#ifdef __x86_64__
520+
noinline void uprobe_multi_error_func(void)
521+
{
522+
/*
523+
* If --fcf-protection=branch is enabled the gcc generates endbr as
524+
* first instruction, so marking the exact address of int3 with the
525+
* symbol to be used in the attach_uprobe_fail_trap test below.
526+
*/
527+
asm volatile (
528+
".globl uprobe_multi_error_func_int3; \n"
529+
"uprobe_multi_error_func_int3: \n"
530+
"int3 \n"
531+
);
532+
}
533+
534+
/*
535+
* Attaching uprobe on uprobe_multi_error_func results in error
536+
* because it already starts with int3 instruction.
537+
*/
538+
static void attach_uprobe_fail_trap(struct uprobe_multi *skel)
539+
{
540+
LIBBPF_OPTS(bpf_uprobe_multi_opts, opts);
541+
const char *syms[4] = {
542+
"uprobe_multi_func_1",
543+
"uprobe_multi_func_2",
544+
"uprobe_multi_func_3",
545+
"uprobe_multi_error_func_int3",
546+
};
547+
548+
opts.syms = syms;
549+
opts.cnt = ARRAY_SIZE(syms);
550+
551+
skel->links.uprobe = bpf_program__attach_uprobe_multi(skel->progs.uprobe, -1,
552+
"/proc/self/exe", NULL, &opts);
553+
if (!ASSERT_ERR_PTR(skel->links.uprobe, "bpf_program__attach_uprobe_multi")) {
554+
bpf_link__destroy(skel->links.uprobe);
555+
skel->links.uprobe = NULL;
556+
}
557+
}
558+
#else
559+
static void attach_uprobe_fail_trap(struct uprobe_multi *skel) { }
560+
#endif
561+
562+
short sema_1 __used, sema_2 __used;
563+
564+
static void attach_uprobe_fail_refctr(struct uprobe_multi *skel)
565+
{
566+
unsigned long *tmp_offsets = NULL, *tmp_ref_ctr_offsets = NULL;
567+
unsigned long offsets[3], ref_ctr_offsets[3];
568+
LIBBPF_OPTS(bpf_link_create_opts, opts);
569+
const char *path = "/proc/self/exe";
570+
const char *syms[3] = {
571+
"uprobe_multi_func_1",
572+
"uprobe_multi_func_2",
573+
};
574+
const char *sema[3] = {
575+
"sema_1",
576+
"sema_2",
577+
};
578+
int prog_fd, link_fd, err;
579+
580+
prog_fd = bpf_program__fd(skel->progs.uprobe_extra);
581+
582+
err = elf_resolve_syms_offsets("/proc/self/exe", 2, (const char **) &syms,
583+
&tmp_offsets, STT_FUNC);
584+
if (!ASSERT_OK(err, "elf_resolve_syms_offsets_func"))
585+
return;
586+
587+
err = elf_resolve_syms_offsets("/proc/self/exe", 2, (const char **) &sema,
588+
&tmp_ref_ctr_offsets, STT_OBJECT);
589+
if (!ASSERT_OK(err, "elf_resolve_syms_offsets_sema"))
590+
goto cleanup;
591+
592+
/*
593+
* We attach to 3 uprobes on 2 functions, so 2 uprobes share single function,
594+
* but with different ref_ctr_offset which is not allowed and results in fail.
595+
*/
596+
offsets[0] = tmp_offsets[0]; /* uprobe_multi_func_1 */
597+
offsets[1] = tmp_offsets[1]; /* uprobe_multi_func_2 */
598+
offsets[2] = tmp_offsets[1]; /* uprobe_multi_func_2 */
599+
600+
ref_ctr_offsets[0] = tmp_ref_ctr_offsets[0]; /* sema_1 */
601+
ref_ctr_offsets[1] = tmp_ref_ctr_offsets[1]; /* sema_2 */
602+
ref_ctr_offsets[2] = tmp_ref_ctr_offsets[0]; /* sema_1, error */
603+
604+
opts.uprobe_multi.path = path;
605+
opts.uprobe_multi.offsets = (const unsigned long *) &offsets;
606+
opts.uprobe_multi.ref_ctr_offsets = (const unsigned long *) &ref_ctr_offsets;
607+
opts.uprobe_multi.cnt = 3;
608+
609+
link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
610+
if (!ASSERT_ERR(link_fd, "link_fd"))
611+
close(link_fd);
612+
613+
cleanup:
614+
free(tmp_ref_ctr_offsets);
615+
free(tmp_offsets);
616+
}
617+
618+
static void test_attach_uprobe_fails(void)
619+
{
620+
struct uprobe_multi *skel = NULL;
621+
622+
skel = uprobe_multi__open_and_load();
623+
if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
624+
return;
625+
626+
/* attach fails due to adding uprobe on trap instruction, x86_64 only */
627+
attach_uprobe_fail_trap(skel);
628+
629+
/* attach fail due to wrong ref_ctr_offs on one of the uprobes */
630+
attach_uprobe_fail_refctr(skel);
631+
632+
uprobe_multi__destroy(skel);
633+
}
634+
519635
static void __test_link_api(struct child *child)
520636
{
521637
int prog_fd, link1_fd = -1, link2_fd = -1, link3_fd = -1, link4_fd = -1;
@@ -703,4 +819,6 @@ void test_uprobe_multi_test(void)
703819
test_bench_attach_usdt();
704820
if (test__start_subtest("attach_api_fails"))
705821
test_attach_api_fails();
822+
if (test__start_subtest("attach_uprobe_fails"))
823+
test_attach_uprobe_fails();
706824
}

0 commit comments

Comments
 (0)