1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>
#include "missed_kprobe.skel.h"
#include "missed_kprobe_recursion.skel.h"
#include "missed_tp_recursion.skel.h"
/*
* Putting kprobe on bpf_fentry_test1 that calls bpf_kfunc_common_test
* kfunc, which has also kprobe on. The latter won't get triggered due
* to kprobe recursion check and kprobe missed counter is incremented.
*/
static void test_missed_perf_kprobe(void)
{
LIBBPF_OPTS(bpf_test_run_opts, topts);
struct bpf_link_info info = {};
struct missed_kprobe *skel;
__u32 len = sizeof(info);
int err, prog_fd;
skel = missed_kprobe__open_and_load();
if (!ASSERT_OK_PTR(skel, "missed_kprobe__open_and_load"))
goto cleanup;
err = missed_kprobe__attach(skel);
if (!ASSERT_OK(err, "missed_kprobe__attach"))
goto cleanup;
prog_fd = bpf_program__fd(skel->progs.trigger);
err = bpf_prog_test_run_opts(prog_fd, &topts);
ASSERT_OK(err, "test_run");
ASSERT_EQ(topts.retval, 0, "test_run");
err = bpf_link_get_info_by_fd(bpf_link__fd(skel->links.test2), &info, &len);
if (!ASSERT_OK(err, "bpf_link_get_info_by_fd"))
goto cleanup;
ASSERT_EQ(info.type, BPF_LINK_TYPE_PERF_EVENT, "info.type");
ASSERT_EQ(info.perf_event.type, BPF_PERF_EVENT_KPROBE, "info.perf_event.type");
ASSERT_EQ(info.perf_event.kprobe.missed, 1, "info.perf_event.kprobe.missed");
cleanup:
missed_kprobe__destroy(skel);
}
static __u64 get_missed_count(int fd)
{
struct bpf_prog_info info = {};
__u32 len = sizeof(info);
int err;
err = bpf_prog_get_info_by_fd(fd, &info, &len);
if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd"))
return (__u64) -1;
return info.recursion_misses;
}
/*
* Putting kprobe.multi on bpf_fentry_test1 that calls bpf_kfunc_common_test
* kfunc which has 3 perf event kprobes and 1 kprobe.multi attached.
*
* Because fprobe (kprobe.multi attach layear) does not have strict recursion
* check the kprobe's bpf_prog_active check is hit for test2-5.
*/
static void test_missed_kprobe_recursion(void)
{
LIBBPF_OPTS(bpf_test_run_opts, topts);
struct missed_kprobe_recursion *skel;
int err, prog_fd;
skel = missed_kprobe_recursion__open_and_load();
if (!ASSERT_OK_PTR(skel, "missed_kprobe_recursion__open_and_load"))
goto cleanup;
err = missed_kprobe_recursion__attach(skel);
if (!ASSERT_OK(err, "missed_kprobe_recursion__attach"))
goto cleanup;
prog_fd = bpf_program__fd(skel->progs.trigger);
err = bpf_prog_test_run_opts(prog_fd, &topts);
ASSERT_OK(err, "test_run");
ASSERT_EQ(topts.retval, 0, "test_run");
ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test1)), 0, "test1_recursion_misses");
ASSERT_GE(get_missed_count(bpf_program__fd(skel->progs.test2)), 1, "test2_recursion_misses");
ASSERT_GE(get_missed_count(bpf_program__fd(skel->progs.test3)), 1, "test3_recursion_misses");
ASSERT_GE(get_missed_count(bpf_program__fd(skel->progs.test4)), 1, "test4_recursion_misses");
ASSERT_GE(get_missed_count(bpf_program__fd(skel->progs.test5)), 1, "test5_recursion_misses");
cleanup:
missed_kprobe_recursion__destroy(skel);
}
/*
* Putting kprobe on bpf_fentry_test1 that calls bpf_printk and invokes
* bpf_trace_printk tracepoint. The bpf_trace_printk tracepoint has test[234]
* programs attached to it.
*
* Because kprobe execution goes through bpf_prog_active check, programs
* attached to the tracepoint will fail the recursion check and increment
* the recursion_misses stats.
*/
static void test_missed_tp_recursion(void)
{
LIBBPF_OPTS(bpf_test_run_opts, topts);
struct missed_tp_recursion *skel;
int err, prog_fd;
skel = missed_tp_recursion__open_and_load();
if (!ASSERT_OK_PTR(skel, "missed_tp_recursion__open_and_load"))
goto cleanup;
err = missed_tp_recursion__attach(skel);
if (!ASSERT_OK(err, "missed_tp_recursion__attach"))
goto cleanup;
prog_fd = bpf_program__fd(skel->progs.trigger);
err = bpf_prog_test_run_opts(prog_fd, &topts);
ASSERT_OK(err, "test_run");
ASSERT_EQ(topts.retval, 0, "test_run");
ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test1)), 0, "test1_recursion_misses");
ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test2)), 1, "test2_recursion_misses");
ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test3)), 1, "test3_recursion_misses");
ASSERT_EQ(get_missed_count(bpf_program__fd(skel->progs.test4)), 1, "test4_recursion_misses");
cleanup:
missed_tp_recursion__destroy(skel);
}
void test_missed(void)
{
if (test__start_subtest("perf_kprobe"))
test_missed_perf_kprobe();
if (test__start_subtest("kprobe_recursion"))
test_missed_kprobe_recursion();
if (test__start_subtest("tp_recursion"))
test_missed_tp_recursion();
}
|