1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 4 #define nr_iters 2 5 6 void serial_test_bpf_obj_id(void) 7 { 8 const __u64 array_magic_value = 0xfaceb00c; 9 const __u32 array_key = 0; 10 const char *file = "./test_obj_id.bpf.o"; 11 const char *expected_prog_name = "test_obj_id"; 12 const char *expected_map_name = "test_map_id"; 13 const __u64 nsec_per_sec = 1000000000; 14 15 struct bpf_object *objs[nr_iters] = {}; 16 struct bpf_link *links[nr_iters] = {}; 17 struct bpf_program *prog; 18 int prog_fds[nr_iters], map_fds[nr_iters]; 19 /* +1 to test for the info_len returned by kernel */ 20 struct bpf_prog_info prog_infos[nr_iters + 1]; 21 struct bpf_map_info map_infos[nr_iters + 1]; 22 struct bpf_link_info link_infos[nr_iters + 1]; 23 /* Each prog only uses one map. +1 to test nr_map_ids 24 * returned by kernel. 25 */ 26 __u32 map_ids[nr_iters + 1]; 27 char jited_insns[128], xlated_insns[128], zeros[128], tp_name[128]; 28 __u32 i, next_id, info_len, nr_id_found; 29 struct timespec real_time_ts, boot_time_ts; 30 int err = 0; 31 __u64 array_value; 32 uid_t my_uid = getuid(); 33 time_t now, load_time; 34 35 err = bpf_prog_get_fd_by_id(0); 36 ASSERT_LT(err, 0, "bpf_prog_get_fd_by_id"); 37 ASSERT_EQ(errno, ENOENT, "bpf_prog_get_fd_by_id"); 38 39 err = bpf_map_get_fd_by_id(0); 40 ASSERT_LT(err, 0, "bpf_map_get_fd_by_id"); 41 ASSERT_EQ(errno, ENOENT, "bpf_map_get_fd_by_id"); 42 43 err = bpf_link_get_fd_by_id(0); 44 ASSERT_LT(err, 0, "bpf_map_get_fd_by_id"); 45 ASSERT_EQ(errno, ENOENT, "bpf_map_get_fd_by_id"); 46 47 /* Check bpf_map_get_info_by_fd() */ 48 bzero(zeros, sizeof(zeros)); 49 for (i = 0; i < nr_iters; i++) { 50 now = time(NULL); 51 err = bpf_prog_test_load(file, BPF_PROG_TYPE_RAW_TRACEPOINT, 52 &objs[i], &prog_fds[i]); 53 /* test_obj_id.o is a dumb prog. It should never fail 54 * to load. 55 */ 56 if (!ASSERT_OK(err, "bpf_prog_test_load")) 57 continue; 58 59 /* Insert a magic value to the map */ 60 map_fds[i] = bpf_find_map(__func__, objs[i], "test_map_id"); 61 if (!ASSERT_GE(map_fds[i], 0, "bpf_find_map")) 62 goto done; 63 64 err = bpf_map_update_elem(map_fds[i], &array_key, 65 &array_magic_value, 0); 66 if (!ASSERT_OK(err, "bpf_map_update_elem")) 67 goto done; 68 69 prog = bpf_object__find_program_by_name(objs[i], "test_obj_id"); 70 if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) 71 goto done; 72 73 links[i] = bpf_program__attach(prog); 74 err = libbpf_get_error(links[i]); 75 if (!ASSERT_OK(err, "bpf_program__attach")) { 76 links[i] = NULL; 77 goto done; 78 } 79 80 /* Check getting map info */ 81 info_len = sizeof(struct bpf_map_info) * 2; 82 bzero(&map_infos[i], info_len); 83 err = bpf_map_get_info_by_fd(map_fds[i], &map_infos[i], 84 &info_len); 85 if (!ASSERT_OK(err, "bpf_map_get_info_by_fd") || 86 !ASSERT_EQ(map_infos[i].type, BPF_MAP_TYPE_ARRAY, "map_type") || 87 !ASSERT_EQ(map_infos[i].key_size, sizeof(__u32), "key_size") || 88 !ASSERT_EQ(map_infos[i].value_size, sizeof(__u64), "value_size") || 89 !ASSERT_EQ(map_infos[i].max_entries, 1, "max_entries") || 90 !ASSERT_EQ(map_infos[i].map_flags, 0, "map_flags") || 91 !ASSERT_EQ(info_len, sizeof(struct bpf_map_info), "map_info_len") || 92 !ASSERT_STREQ((char *)map_infos[i].name, expected_map_name, "map_name")) 93 goto done; 94 95 /* Check getting prog info */ 96 info_len = sizeof(struct bpf_prog_info) * 2; 97 bzero(&prog_infos[i], info_len); 98 bzero(jited_insns, sizeof(jited_insns)); 99 bzero(xlated_insns, sizeof(xlated_insns)); 100 prog_infos[i].jited_prog_insns = ptr_to_u64(jited_insns); 101 prog_infos[i].jited_prog_len = sizeof(jited_insns); 102 prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns); 103 prog_infos[i].xlated_prog_len = sizeof(xlated_insns); 104 prog_infos[i].map_ids = ptr_to_u64(map_ids + i); 105 prog_infos[i].nr_map_ids = 2; 106 107 err = clock_gettime(CLOCK_REALTIME, &real_time_ts); 108 if (!ASSERT_OK(err, "clock_gettime")) 109 goto done; 110 111 err = clock_gettime(CLOCK_BOOTTIME, &boot_time_ts); 112 if (!ASSERT_OK(err, "clock_gettime")) 113 goto done; 114 115 err = bpf_prog_get_info_by_fd(prog_fds[i], &prog_infos[i], 116 &info_len); 117 load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec) 118 + (prog_infos[i].load_time / nsec_per_sec); 119 120 if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd") || 121 !ASSERT_EQ(prog_infos[i].type, BPF_PROG_TYPE_RAW_TRACEPOINT, "prog_type") || 122 !ASSERT_EQ(info_len, sizeof(struct bpf_prog_info), "prog_info_len") || 123 !ASSERT_FALSE((env.jit_enabled && !prog_infos[i].jited_prog_len), "jited_prog_len") || 124 !ASSERT_FALSE((env.jit_enabled && !memcmp(jited_insns, zeros, sizeof(zeros))), 125 "jited_insns") || 126 !ASSERT_NEQ(prog_infos[i].xlated_prog_len, 0, "xlated_prog_len") || 127 !ASSERT_NEQ(memcmp(xlated_insns, zeros, sizeof(zeros)), 0, "xlated_insns") || 128 !ASSERT_GE(load_time, (now - 60), "load_time") || 129 !ASSERT_LE(load_time, (now + 60), "load_time") || 130 !ASSERT_EQ(prog_infos[i].created_by_uid, my_uid, "created_by_uid") || 131 !ASSERT_EQ(prog_infos[i].nr_map_ids, 1, "nr_map_ids") || 132 !ASSERT_EQ(*(int *)(long)prog_infos[i].map_ids, map_infos[i].id, "map_ids") || 133 !ASSERT_STREQ((char *)prog_infos[i].name, expected_prog_name, "prog_name")) 134 goto done; 135 136 /* Check getting link info */ 137 info_len = sizeof(struct bpf_link_info) * 2; 138 bzero(&link_infos[i], info_len); 139 link_infos[i].raw_tracepoint.tp_name = ptr_to_u64(&tp_name); 140 link_infos[i].raw_tracepoint.tp_name_len = sizeof(tp_name); 141 err = bpf_link_get_info_by_fd(bpf_link__fd(links[i]), 142 &link_infos[i], &info_len); 143 if (!ASSERT_OK(err, "bpf_link_get_info_by_fd") || 144 !ASSERT_EQ(link_infos[i].type, BPF_LINK_TYPE_RAW_TRACEPOINT, "link_type") || 145 !ASSERT_EQ(link_infos[i].prog_id, prog_infos[i].id, "prog_id") || 146 !ASSERT_EQ(link_infos[i].raw_tracepoint.tp_name, ptr_to_u64(&tp_name), "&tp_name") || 147 !ASSERT_STREQ(u64_to_ptr(link_infos[i].raw_tracepoint.tp_name), "sys_enter", "tp_name")) 148 goto done; 149 } 150 151 /* Check bpf_prog_get_next_id() */ 152 nr_id_found = 0; 153 next_id = 0; 154 while (!bpf_prog_get_next_id(next_id, &next_id)) { 155 struct bpf_prog_info prog_info = {}; 156 __u32 saved_map_id; 157 int prog_fd, cmp_res; 158 159 info_len = sizeof(prog_info); 160 161 prog_fd = bpf_prog_get_fd_by_id(next_id); 162 if (prog_fd < 0 && errno == ENOENT) 163 /* The bpf_prog is in the dead row */ 164 continue; 165 if (!ASSERT_GE(prog_fd, 0, "bpf_prog_get_fd_by_id")) 166 break; 167 168 for (i = 0; i < nr_iters; i++) 169 if (prog_infos[i].id == next_id) 170 break; 171 172 if (i == nr_iters) 173 continue; 174 175 nr_id_found++; 176 177 /* Negative test: 178 * prog_info.nr_map_ids = 1 179 * prog_info.map_ids = NULL 180 */ 181 prog_info.nr_map_ids = 1; 182 err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len); 183 if (!ASSERT_ERR(err, "bpf_prog_get_info_by_fd") || 184 !ASSERT_EQ(errno, EFAULT, "bpf_prog_get_info_by_fd")) 185 break; 186 bzero(&prog_info, sizeof(prog_info)); 187 info_len = sizeof(prog_info); 188 189 saved_map_id = *(int *)((long)prog_infos[i].map_ids); 190 prog_info.map_ids = prog_infos[i].map_ids; 191 prog_info.nr_map_ids = 2; 192 err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len); 193 prog_infos[i].jited_prog_insns = 0; 194 prog_infos[i].xlated_prog_insns = 0; 195 cmp_res = memcmp(&prog_info, &prog_infos[i], info_len); 196 197 ASSERT_OK(err, "bpf_prog_get_info_by_fd"); 198 ASSERT_EQ(info_len, sizeof(struct bpf_prog_info), "prog_info_len"); 199 ASSERT_OK(cmp_res, "memcmp"); 200 ASSERT_EQ(*(int *)(long)prog_info.map_ids, saved_map_id, "map_id"); 201 close(prog_fd); 202 } 203 ASSERT_EQ(nr_id_found, nr_iters, "prog_nr_id_found"); 204 205 /* Check bpf_map_get_next_id() */ 206 nr_id_found = 0; 207 next_id = 0; 208 while (!bpf_map_get_next_id(next_id, &next_id)) { 209 struct bpf_map_info map_info = {}; 210 int map_fd, cmp_res; 211 212 info_len = sizeof(map_info); 213 214 map_fd = bpf_map_get_fd_by_id(next_id); 215 if (map_fd < 0 && errno == ENOENT) 216 /* The bpf_map is in the dead row */ 217 continue; 218 if (!ASSERT_GE(map_fd, 0, "bpf_map_get_fd_by_id")) 219 break; 220 221 for (i = 0; i < nr_iters; i++) 222 if (map_infos[i].id == next_id) 223 break; 224 225 if (i == nr_iters) 226 continue; 227 228 nr_id_found++; 229 230 err = bpf_map_lookup_elem(map_fd, &array_key, &array_value); 231 if (!ASSERT_OK(err, "bpf_map_lookup_elem")) 232 goto done; 233 234 err = bpf_map_get_info_by_fd(map_fd, &map_info, &info_len); 235 cmp_res = memcmp(&map_info, &map_infos[i], info_len); 236 ASSERT_OK(err, "bpf_map_get_info_by_fd"); 237 ASSERT_EQ(info_len, sizeof(struct bpf_map_info), "info_len"); 238 ASSERT_OK(cmp_res, "memcmp"); 239 ASSERT_EQ(array_value, array_magic_value, "array_value"); 240 241 close(map_fd); 242 } 243 ASSERT_EQ(nr_id_found, nr_iters, "map_nr_id_found"); 244 245 /* Check bpf_link_get_next_id() */ 246 nr_id_found = 0; 247 next_id = 0; 248 while (!bpf_link_get_next_id(next_id, &next_id)) { 249 struct bpf_link_info link_info; 250 int link_fd, cmp_res; 251 252 info_len = sizeof(link_info); 253 memset(&link_info, 0, info_len); 254 255 link_fd = bpf_link_get_fd_by_id(next_id); 256 if (link_fd < 0 && errno == ENOENT) 257 /* The bpf_link is in the dead row */ 258 continue; 259 if (!ASSERT_GE(link_fd, 0, "bpf_link_get_fd_by_id")) 260 break; 261 262 for (i = 0; i < nr_iters; i++) 263 if (link_infos[i].id == next_id) 264 break; 265 266 if (i == nr_iters) 267 continue; 268 269 nr_id_found++; 270 271 err = bpf_link_get_info_by_fd(link_fd, &link_info, &info_len); 272 cmp_res = memcmp(&link_info, &link_infos[i], 273 offsetof(struct bpf_link_info, raw_tracepoint)); 274 ASSERT_OK(err, "bpf_link_get_info_by_fd"); 275 ASSERT_EQ(info_len, sizeof(link_info), "info_len"); 276 ASSERT_OK(cmp_res, "memcmp"); 277 278 close(link_fd); 279 } 280 ASSERT_EQ(nr_id_found, nr_iters, "link_nr_id_found"); 281 282 done: 283 for (i = 0; i < nr_iters; i++) { 284 bpf_link__destroy(links[i]); 285 bpf_object__close(objs[i]); 286 } 287 } 288