1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 Red Hat, Inc. */ 3 #include <test_progs.h> 4 #include "fentry_recursive.skel.h" 5 #include "fentry_recursive_target.skel.h" 6 #include <bpf/btf.h> 7 #include "bpf/libbpf_internal.h" 8 9 /* Test recursive attachment of tracing progs with more than one nesting level 10 * is not possible. Create a chain of attachment, verify that the last prog 11 * will fail. Depending on the arguments, following cases are tested: 12 * 13 * - Recursive loading of tracing progs, without attaching (attach = false, 14 * detach = false). The chain looks like this: 15 * load target 16 * load fentry1 -> target 17 * load fentry2 -> fentry1 (fail) 18 * 19 * - Recursive attach of tracing progs (attach = true, detach = false). The 20 * chain looks like this: 21 * load target 22 * load fentry1 -> target 23 * attach fentry1 -> target 24 * load fentry2 -> fentry1 (fail) 25 * 26 * - Recursive attach and detach of tracing progs (attach = true, detach = 27 * true). This validates that attach_tracing_prog flag will be set throughout 28 * the whole lifecycle of an fentry prog, independently from whether it's 29 * detached. The chain looks like this: 30 * load target 31 * load fentry1 -> target 32 * attach fentry1 -> target 33 * detach fentry1 34 * load fentry2 -> fentry1 (fail) 35 */ 36 static void test_recursive_fentry_chain(bool attach, bool detach) 37 { 38 struct fentry_recursive_target *target_skel = NULL; 39 struct fentry_recursive *tracing_chain[2] = {}; 40 struct bpf_program *prog; 41 int prev_fd, err; 42 43 target_skel = fentry_recursive_target__open_and_load(); 44 if (!ASSERT_OK_PTR(target_skel, "fentry_recursive_target__open_and_load")) 45 return; 46 47 /* Create an attachment chain with two fentry progs */ 48 for (int i = 0; i < 2; i++) { 49 tracing_chain[i] = fentry_recursive__open(); 50 if (!ASSERT_OK_PTR(tracing_chain[i], "fentry_recursive__open")) 51 goto close_prog; 52 53 /* The first prog in the chain is going to be attached to the target 54 * fentry program, the second one to the previous in the chain. 55 */ 56 prog = tracing_chain[i]->progs.recursive_attach; 57 if (i == 0) { 58 prev_fd = bpf_program__fd(target_skel->progs.test1); 59 err = bpf_program__set_attach_target(prog, prev_fd, "test1"); 60 } else { 61 prev_fd = bpf_program__fd(tracing_chain[i-1]->progs.recursive_attach); 62 err = bpf_program__set_attach_target(prog, prev_fd, "recursive_attach"); 63 } 64 65 if (!ASSERT_OK(err, "bpf_program__set_attach_target")) 66 goto close_prog; 67 68 err = fentry_recursive__load(tracing_chain[i]); 69 /* The first attach should succeed, the second fail */ 70 if (i == 0) { 71 if (!ASSERT_OK(err, "fentry_recursive__load")) 72 goto close_prog; 73 74 if (attach) { 75 err = fentry_recursive__attach(tracing_chain[i]); 76 if (!ASSERT_OK(err, "fentry_recursive__attach")) 77 goto close_prog; 78 } 79 80 if (detach) { 81 /* Flag attach_tracing_prog should still be set, preventing 82 * attachment of the following prog. 83 */ 84 fentry_recursive__detach(tracing_chain[i]); 85 } 86 } else { 87 if (!ASSERT_ERR(err, "fentry_recursive__load")) 88 goto close_prog; 89 } 90 } 91 92 close_prog: 93 fentry_recursive_target__destroy(target_skel); 94 for (int i = 0; i < 2; i++) { 95 fentry_recursive__destroy(tracing_chain[i]); 96 } 97 } 98 99 void test_recursive_fentry(void) 100 { 101 if (test__start_subtest("attach")) 102 test_recursive_fentry_chain(true, false); 103 if (test__start_subtest("load")) 104 test_recursive_fentry_chain(false, false); 105 if (test__start_subtest("detach")) 106 test_recursive_fentry_chain(true, true); 107 } 108 109 /* Test that a tracing prog reattachment (when we land in 110 * "prog->aux->dst_trampoline and tgt_prog is NULL" branch in 111 * bpf_tracing_prog_attach) does not lead to a crash due to missing attach_btf 112 */ 113 void test_fentry_attach_btf_presence(void) 114 { 115 struct fentry_recursive_target *target_skel = NULL; 116 struct fentry_recursive *tracing_skel = NULL; 117 struct bpf_program *prog; 118 int err, link_fd, tgt_prog_fd; 119 120 target_skel = fentry_recursive_target__open_and_load(); 121 if (!ASSERT_OK_PTR(target_skel, "fentry_recursive_target__open_and_load")) 122 goto close_prog; 123 124 tracing_skel = fentry_recursive__open(); 125 if (!ASSERT_OK_PTR(tracing_skel, "fentry_recursive__open")) 126 goto close_prog; 127 128 prog = tracing_skel->progs.recursive_attach; 129 tgt_prog_fd = bpf_program__fd(target_skel->progs.fentry_target); 130 err = bpf_program__set_attach_target(prog, tgt_prog_fd, "fentry_target"); 131 if (!ASSERT_OK(err, "bpf_program__set_attach_target")) 132 goto close_prog; 133 134 err = fentry_recursive__load(tracing_skel); 135 if (!ASSERT_OK(err, "fentry_recursive__load")) 136 goto close_prog; 137 138 tgt_prog_fd = bpf_program__fd(tracing_skel->progs.recursive_attach); 139 link_fd = bpf_link_create(tgt_prog_fd, 0, BPF_TRACE_FENTRY, NULL); 140 if (!ASSERT_GE(link_fd, 0, "link_fd")) 141 goto close_prog; 142 143 fentry_recursive__detach(tracing_skel); 144 145 err = fentry_recursive__attach(tracing_skel); 146 ASSERT_ERR(err, "fentry_recursive__attach"); 147 148 close_prog: 149 fentry_recursive_target__destroy(target_skel); 150 fentry_recursive__destroy(tracing_skel); 151 } 152 153 static void *fentry_target_test_run(void *arg) 154 { 155 for (;;) { 156 int prog_fd = __atomic_load_n((int *)arg, __ATOMIC_SEQ_CST); 157 LIBBPF_OPTS(bpf_test_run_opts, topts); 158 int err; 159 160 if (prog_fd == -1) 161 break; 162 err = bpf_prog_test_run_opts(prog_fd, &topts); 163 if (!ASSERT_OK(err, "fentry_target test_run")) 164 break; 165 } 166 167 return NULL; 168 } 169 170 void test_fentry_attach_stress(void) 171 { 172 struct fentry_recursive_target *target_skel = NULL; 173 struct fentry_recursive *tracing_skel = NULL; 174 struct bpf_program *prog; 175 int err, i, tgt_prog_fd; 176 pthread_t thread; 177 178 target_skel = fentry_recursive_target__open_and_load(); 179 if (!ASSERT_OK_PTR(target_skel, 180 "fentry_recursive_target__open_and_load")) 181 goto close_prog; 182 tgt_prog_fd = bpf_program__fd(target_skel->progs.fentry_target); 183 err = pthread_create(&thread, NULL, 184 fentry_target_test_run, &tgt_prog_fd); 185 if (!ASSERT_OK(err, "bpf_program__set_attach_target")) 186 goto close_prog; 187 188 for (i = 0; i < 1000; i++) { 189 tracing_skel = fentry_recursive__open(); 190 if (!ASSERT_OK_PTR(tracing_skel, "fentry_recursive__open")) 191 goto stop_thread; 192 193 prog = tracing_skel->progs.recursive_attach; 194 err = bpf_program__set_attach_target(prog, tgt_prog_fd, 195 "fentry_target"); 196 if (!ASSERT_OK(err, "bpf_program__set_attach_target")) 197 goto stop_thread; 198 199 err = fentry_recursive__load(tracing_skel); 200 if (!ASSERT_OK(err, "fentry_recursive__load")) 201 goto stop_thread; 202 203 err = fentry_recursive__attach(tracing_skel); 204 if (!ASSERT_OK(err, "fentry_recursive__attach")) 205 goto stop_thread; 206 207 fentry_recursive__destroy(tracing_skel); 208 tracing_skel = NULL; 209 } 210 211 stop_thread: 212 __atomic_store_n(&tgt_prog_fd, -1, __ATOMIC_SEQ_CST); 213 err = pthread_join(thread, NULL); 214 ASSERT_OK(err, "pthread_join"); 215 close_prog: 216 fentry_recursive__destroy(tracing_skel); 217 fentry_recursive_target__destroy(target_skel); 218 } 219