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