1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2019 Facebook */ 3 #include <test_progs.h> 4 #include <network_helpers.h> 5 6 static void test_fexit_bpf2bpf_common(const char *obj_file, 7 const char *target_obj_file, 8 int prog_cnt, 9 const char **prog_name, 10 bool run_prog) 11 { 12 struct bpf_object *obj = NULL, *pkt_obj; 13 int err, pkt_fd, i; 14 struct bpf_link **link = NULL; 15 struct bpf_program **prog = NULL; 16 __u32 duration = 0, retval; 17 struct bpf_map *data_map; 18 const int zero = 0; 19 __u64 *result = NULL; 20 21 err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC, 22 &pkt_obj, &pkt_fd); 23 if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n", 24 target_obj_file, err, errno)) 25 return; 26 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, 27 .attach_prog_fd = pkt_fd, 28 ); 29 30 link = calloc(sizeof(struct bpf_link *), prog_cnt); 31 prog = calloc(sizeof(struct bpf_program *), prog_cnt); 32 result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64)); 33 if (CHECK(!link || !prog || !result, "alloc_memory", 34 "failed to alloc memory")) 35 goto close_prog; 36 37 obj = bpf_object__open_file(obj_file, &opts); 38 if (CHECK(IS_ERR_OR_NULL(obj), "obj_open", 39 "failed to open %s: %ld\n", obj_file, 40 PTR_ERR(obj))) 41 goto close_prog; 42 43 err = bpf_object__load(obj); 44 if (CHECK(err, "obj_load", "err %d\n", err)) 45 goto close_prog; 46 47 for (i = 0; i < prog_cnt; i++) { 48 prog[i] = bpf_object__find_program_by_title(obj, prog_name[i]); 49 if (CHECK(!prog[i], "find_prog", "prog %s not found\n", prog_name[i])) 50 goto close_prog; 51 link[i] = bpf_program__attach_trace(prog[i]); 52 if (CHECK(IS_ERR(link[i]), "attach_trace", "failed to link\n")) 53 goto close_prog; 54 } 55 56 if (!run_prog) 57 goto close_prog; 58 59 data_map = bpf_object__find_map_by_name(obj, "fexit_bp.bss"); 60 if (CHECK(!data_map, "find_data_map", "data map not found\n")) 61 goto close_prog; 62 63 err = bpf_prog_test_run(pkt_fd, 1, &pkt_v6, sizeof(pkt_v6), 64 NULL, NULL, &retval, &duration); 65 CHECK(err || retval, "ipv6", 66 "err %d errno %d retval %d duration %d\n", 67 err, errno, retval, duration); 68 69 err = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result); 70 if (CHECK(err, "get_result", 71 "failed to get output data: %d\n", err)) 72 goto close_prog; 73 74 for (i = 0; i < prog_cnt; i++) 75 if (CHECK(result[i] != 1, "result", "fexit_bpf2bpf failed err %llu\n", 76 result[i])) 77 goto close_prog; 78 79 close_prog: 80 for (i = 0; i < prog_cnt; i++) 81 if (!IS_ERR_OR_NULL(link[i])) 82 bpf_link__destroy(link[i]); 83 if (!IS_ERR_OR_NULL(obj)) 84 bpf_object__close(obj); 85 bpf_object__close(pkt_obj); 86 free(link); 87 free(prog); 88 free(result); 89 } 90 91 static void test_target_no_callees(void) 92 { 93 const char *prog_name[] = { 94 "fexit/test_pkt_md_access", 95 }; 96 test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o", 97 "./test_pkt_md_access.o", 98 ARRAY_SIZE(prog_name), 99 prog_name, true); 100 } 101 102 static void test_target_yes_callees(void) 103 { 104 const char *prog_name[] = { 105 "fexit/test_pkt_access", 106 "fexit/test_pkt_access_subprog1", 107 "fexit/test_pkt_access_subprog2", 108 "fexit/test_pkt_access_subprog3", 109 }; 110 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", 111 "./test_pkt_access.o", 112 ARRAY_SIZE(prog_name), 113 prog_name, true); 114 } 115 116 static void test_func_replace(void) 117 { 118 const char *prog_name[] = { 119 "fexit/test_pkt_access", 120 "fexit/test_pkt_access_subprog1", 121 "fexit/test_pkt_access_subprog2", 122 "fexit/test_pkt_access_subprog3", 123 "freplace/get_skb_len", 124 "freplace/get_skb_ifindex", 125 "freplace/get_constant", 126 "freplace/test_pkt_write_access_subprog", 127 }; 128 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o", 129 "./test_pkt_access.o", 130 ARRAY_SIZE(prog_name), 131 prog_name, true); 132 } 133 134 static void test_func_replace_verify(void) 135 { 136 const char *prog_name[] = { 137 "freplace/do_bind", 138 }; 139 test_fexit_bpf2bpf_common("./freplace_connect4.o", 140 "./connect4_prog.o", 141 ARRAY_SIZE(prog_name), 142 prog_name, false); 143 } 144 145 static void test_func_sockmap_update(void) 146 { 147 const char *prog_name[] = { 148 "freplace/cls_redirect", 149 }; 150 test_fexit_bpf2bpf_common("./freplace_cls_redirect.o", 151 "./test_cls_redirect.o", 152 ARRAY_SIZE(prog_name), 153 prog_name, false); 154 } 155 156 static void test_obj_load_failure_common(const char *obj_file, 157 const char *target_obj_file) 158 159 { 160 /* 161 * standalone test that asserts failure to load freplace prog 162 * because of invalid return code. 163 */ 164 struct bpf_object *obj = NULL, *pkt_obj; 165 int err, pkt_fd; 166 __u32 duration = 0; 167 168 err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC, 169 &pkt_obj, &pkt_fd); 170 /* the target prog should load fine */ 171 if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n", 172 target_obj_file, err, errno)) 173 return; 174 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, 175 .attach_prog_fd = pkt_fd, 176 ); 177 178 obj = bpf_object__open_file(obj_file, &opts); 179 if (CHECK(IS_ERR_OR_NULL(obj), "obj_open", 180 "failed to open %s: %ld\n", obj_file, 181 PTR_ERR(obj))) 182 goto close_prog; 183 184 /* It should fail to load the program */ 185 err = bpf_object__load(obj); 186 if (CHECK(!err, "bpf_obj_load should fail", "err %d\n", err)) 187 goto close_prog; 188 189 close_prog: 190 if (!IS_ERR_OR_NULL(obj)) 191 bpf_object__close(obj); 192 bpf_object__close(pkt_obj); 193 } 194 195 static void test_func_replace_return_code(void) 196 { 197 /* test invalid return code in the replaced program */ 198 test_obj_load_failure_common("./freplace_connect_v4_prog.o", 199 "./connect4_prog.o"); 200 } 201 202 static void test_func_map_prog_compatibility(void) 203 { 204 /* test with spin lock map value in the replaced program */ 205 test_obj_load_failure_common("./freplace_attach_probe.o", 206 "./test_attach_probe.o"); 207 } 208 209 void test_fexit_bpf2bpf(void) 210 { 211 if (test__start_subtest("target_no_callees")) 212 test_target_no_callees(); 213 if (test__start_subtest("target_yes_callees")) 214 test_target_yes_callees(); 215 if (test__start_subtest("func_replace")) 216 test_func_replace(); 217 if (test__start_subtest("func_replace_verify")) 218 test_func_replace_verify(); 219 if (test__start_subtest("func_sockmap_update")) 220 test_func_sockmap_update(); 221 if (test__start_subtest("func_replace_return_code")) 222 test_func_replace_return_code(); 223 if (test__start_subtest("func_map_prog_compatibility")) 224 test_func_map_prog_compatibility(); 225 } 226