1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3
4 #define nr_iters 2
5
serial_test_bpf_obj_id(void)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.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, duration = 0;
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 CHECK(err >= 0 || errno != ENOENT,
37 "get-fd-by-notexist-prog-id", "err %d errno %d\n", err, errno);
38
39 err = bpf_map_get_fd_by_id(0);
40 CHECK(err >= 0 || errno != ENOENT,
41 "get-fd-by-notexist-map-id", "err %d errno %d\n", err, errno);
42
43 err = bpf_link_get_fd_by_id(0);
44 CHECK(err >= 0 || errno != ENOENT,
45 "get-fd-by-notexist-link-id", "err %d errno %d\n", err, errno);
46
47 /* Check bpf_obj_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 (CHECK_FAIL(err))
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 (CHECK_FAIL(map_fds[i] < 0))
62 goto done;
63 err = bpf_map_update_elem(map_fds[i], &array_key,
64 &array_magic_value, 0);
65 if (CHECK_FAIL(err))
66 goto done;
67
68 prog = bpf_object__find_program_by_name(objs[i],
69 "test_obj_id");
70 if (CHECK_FAIL(!prog))
71 goto done;
72 links[i] = bpf_program__attach(prog);
73 err = libbpf_get_error(links[i]);
74 if (CHECK(err, "prog_attach", "prog #%d, err %d\n", i, err)) {
75 links[i] = NULL;
76 goto done;
77 }
78
79 /* Check getting map info */
80 info_len = sizeof(struct bpf_map_info) * 2;
81 bzero(&map_infos[i], info_len);
82 err = bpf_obj_get_info_by_fd(map_fds[i], &map_infos[i],
83 &info_len);
84 if (CHECK(err ||
85 map_infos[i].type != BPF_MAP_TYPE_ARRAY ||
86 map_infos[i].key_size != sizeof(__u32) ||
87 map_infos[i].value_size != sizeof(__u64) ||
88 map_infos[i].max_entries != 1 ||
89 map_infos[i].map_flags != 0 ||
90 info_len != sizeof(struct bpf_map_info) ||
91 strcmp((char *)map_infos[i].name, expected_map_name),
92 "get-map-info(fd)",
93 "err %d errno %d type %d(%d) info_len %u(%zu) key_size %u value_size %u max_entries %u map_flags %X name %s(%s)\n",
94 err, errno,
95 map_infos[i].type, BPF_MAP_TYPE_ARRAY,
96 info_len, sizeof(struct bpf_map_info),
97 map_infos[i].key_size,
98 map_infos[i].value_size,
99 map_infos[i].max_entries,
100 map_infos[i].map_flags,
101 map_infos[i].name, expected_map_name))
102 goto done;
103
104 /* Check getting prog info */
105 info_len = sizeof(struct bpf_prog_info) * 2;
106 bzero(&prog_infos[i], info_len);
107 bzero(jited_insns, sizeof(jited_insns));
108 bzero(xlated_insns, sizeof(xlated_insns));
109 prog_infos[i].jited_prog_insns = ptr_to_u64(jited_insns);
110 prog_infos[i].jited_prog_len = sizeof(jited_insns);
111 prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns);
112 prog_infos[i].xlated_prog_len = sizeof(xlated_insns);
113 prog_infos[i].map_ids = ptr_to_u64(map_ids + i);
114 prog_infos[i].nr_map_ids = 2;
115 err = clock_gettime(CLOCK_REALTIME, &real_time_ts);
116 if (CHECK_FAIL(err))
117 goto done;
118 err = clock_gettime(CLOCK_BOOTTIME, &boot_time_ts);
119 if (CHECK_FAIL(err))
120 goto done;
121 err = bpf_obj_get_info_by_fd(prog_fds[i], &prog_infos[i],
122 &info_len);
123 load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec)
124 + (prog_infos[i].load_time / nsec_per_sec);
125 if (CHECK(err ||
126 prog_infos[i].type != BPF_PROG_TYPE_RAW_TRACEPOINT ||
127 info_len != sizeof(struct bpf_prog_info) ||
128 (env.jit_enabled && !prog_infos[i].jited_prog_len) ||
129 (env.jit_enabled &&
130 !memcmp(jited_insns, zeros, sizeof(zeros))) ||
131 !prog_infos[i].xlated_prog_len ||
132 !memcmp(xlated_insns, zeros, sizeof(zeros)) ||
133 load_time < now - 60 || load_time > now + 60 ||
134 prog_infos[i].created_by_uid != my_uid ||
135 prog_infos[i].nr_map_ids != 1 ||
136 *(int *)(long)prog_infos[i].map_ids != map_infos[i].id ||
137 strcmp((char *)prog_infos[i].name, expected_prog_name),
138 "get-prog-info(fd)",
139 "err %d errno %d i %d type %d(%d) info_len %u(%zu) "
140 "jit_enabled %d jited_prog_len %u xlated_prog_len %u "
141 "jited_prog %d xlated_prog %d load_time %lu(%lu) "
142 "uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) "
143 "name %s(%s)\n",
144 err, errno, i,
145 prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER,
146 info_len, sizeof(struct bpf_prog_info),
147 env.jit_enabled,
148 prog_infos[i].jited_prog_len,
149 prog_infos[i].xlated_prog_len,
150 !!memcmp(jited_insns, zeros, sizeof(zeros)),
151 !!memcmp(xlated_insns, zeros, sizeof(zeros)),
152 load_time, now,
153 prog_infos[i].created_by_uid, my_uid,
154 prog_infos[i].nr_map_ids, 1,
155 *(int *)(long)prog_infos[i].map_ids, map_infos[i].id,
156 prog_infos[i].name, expected_prog_name))
157 goto done;
158
159 /* Check getting link info */
160 info_len = sizeof(struct bpf_link_info) * 2;
161 bzero(&link_infos[i], info_len);
162 link_infos[i].raw_tracepoint.tp_name = ptr_to_u64(&tp_name);
163 link_infos[i].raw_tracepoint.tp_name_len = sizeof(tp_name);
164 err = bpf_obj_get_info_by_fd(bpf_link__fd(links[i]),
165 &link_infos[i], &info_len);
166 if (CHECK(err ||
167 link_infos[i].type != BPF_LINK_TYPE_RAW_TRACEPOINT ||
168 link_infos[i].prog_id != prog_infos[i].id ||
169 link_infos[i].raw_tracepoint.tp_name != ptr_to_u64(&tp_name) ||
170 strcmp(u64_to_ptr(link_infos[i].raw_tracepoint.tp_name),
171 "sys_enter") ||
172 info_len != sizeof(struct bpf_link_info),
173 "get-link-info(fd)",
174 "err %d errno %d info_len %u(%zu) type %d(%d) id %d "
175 "prog_id %d (%d) tp_name %s(%s)\n",
176 err, errno,
177 info_len, sizeof(struct bpf_link_info),
178 link_infos[i].type, BPF_LINK_TYPE_RAW_TRACEPOINT,
179 link_infos[i].id,
180 link_infos[i].prog_id, prog_infos[i].id,
181 (const char *)u64_to_ptr(link_infos[i].raw_tracepoint.tp_name),
182 "sys_enter"))
183 goto done;
184
185 }
186
187 /* Check bpf_prog_get_next_id() */
188 nr_id_found = 0;
189 next_id = 0;
190 while (!bpf_prog_get_next_id(next_id, &next_id)) {
191 struct bpf_prog_info prog_info = {};
192 __u32 saved_map_id;
193 int prog_fd;
194
195 info_len = sizeof(prog_info);
196
197 prog_fd = bpf_prog_get_fd_by_id(next_id);
198 if (prog_fd < 0 && errno == ENOENT)
199 /* The bpf_prog is in the dead row */
200 continue;
201 if (CHECK(prog_fd < 0, "get-prog-fd(next_id)",
202 "prog_fd %d next_id %d errno %d\n",
203 prog_fd, next_id, errno))
204 break;
205
206 for (i = 0; i < nr_iters; i++)
207 if (prog_infos[i].id == next_id)
208 break;
209
210 if (i == nr_iters)
211 continue;
212
213 nr_id_found++;
214
215 /* Negative test:
216 * prog_info.nr_map_ids = 1
217 * prog_info.map_ids = NULL
218 */
219 prog_info.nr_map_ids = 1;
220 err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
221 if (CHECK(!err || errno != EFAULT,
222 "get-prog-fd-bad-nr-map-ids", "err %d errno %d(%d)",
223 err, errno, EFAULT))
224 break;
225 bzero(&prog_info, sizeof(prog_info));
226 info_len = sizeof(prog_info);
227
228 saved_map_id = *(int *)((long)prog_infos[i].map_ids);
229 prog_info.map_ids = prog_infos[i].map_ids;
230 prog_info.nr_map_ids = 2;
231 err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
232 prog_infos[i].jited_prog_insns = 0;
233 prog_infos[i].xlated_prog_insns = 0;
234 CHECK(err || info_len != sizeof(struct bpf_prog_info) ||
235 memcmp(&prog_info, &prog_infos[i], info_len) ||
236 *(int *)(long)prog_info.map_ids != saved_map_id,
237 "get-prog-info(next_id->fd)",
238 "err %d errno %d info_len %u(%zu) memcmp %d map_id %u(%u)\n",
239 err, errno, info_len, sizeof(struct bpf_prog_info),
240 memcmp(&prog_info, &prog_infos[i], info_len),
241 *(int *)(long)prog_info.map_ids, saved_map_id);
242 close(prog_fd);
243 }
244 CHECK(nr_id_found != nr_iters,
245 "check total prog id found by get_next_id",
246 "nr_id_found %u(%u)\n",
247 nr_id_found, nr_iters);
248
249 /* Check bpf_map_get_next_id() */
250 nr_id_found = 0;
251 next_id = 0;
252 while (!bpf_map_get_next_id(next_id, &next_id)) {
253 struct bpf_map_info map_info = {};
254 int map_fd;
255
256 info_len = sizeof(map_info);
257
258 map_fd = bpf_map_get_fd_by_id(next_id);
259 if (map_fd < 0 && errno == ENOENT)
260 /* The bpf_map is in the dead row */
261 continue;
262 if (CHECK(map_fd < 0, "get-map-fd(next_id)",
263 "map_fd %d next_id %u errno %d\n",
264 map_fd, next_id, errno))
265 break;
266
267 for (i = 0; i < nr_iters; i++)
268 if (map_infos[i].id == next_id)
269 break;
270
271 if (i == nr_iters)
272 continue;
273
274 nr_id_found++;
275
276 err = bpf_map_lookup_elem(map_fd, &array_key, &array_value);
277 if (CHECK_FAIL(err))
278 goto done;
279
280 err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len);
281 CHECK(err || info_len != sizeof(struct bpf_map_info) ||
282 memcmp(&map_info, &map_infos[i], info_len) ||
283 array_value != array_magic_value,
284 "check get-map-info(next_id->fd)",
285 "err %d errno %d info_len %u(%zu) memcmp %d array_value %llu(%llu)\n",
286 err, errno, info_len, sizeof(struct bpf_map_info),
287 memcmp(&map_info, &map_infos[i], info_len),
288 array_value, array_magic_value);
289
290 close(map_fd);
291 }
292 CHECK(nr_id_found != nr_iters,
293 "check total map id found by get_next_id",
294 "nr_id_found %u(%u)\n",
295 nr_id_found, nr_iters);
296
297 /* Check bpf_link_get_next_id() */
298 nr_id_found = 0;
299 next_id = 0;
300 while (!bpf_link_get_next_id(next_id, &next_id)) {
301 struct bpf_link_info link_info;
302 int link_fd, cmp_res;
303
304 info_len = sizeof(link_info);
305 memset(&link_info, 0, info_len);
306
307 link_fd = bpf_link_get_fd_by_id(next_id);
308 if (link_fd < 0 && errno == ENOENT)
309 /* The bpf_link is in the dead row */
310 continue;
311 if (CHECK(link_fd < 0, "get-link-fd(next_id)",
312 "link_fd %d next_id %u errno %d\n",
313 link_fd, next_id, errno))
314 break;
315
316 for (i = 0; i < nr_iters; i++)
317 if (link_infos[i].id == next_id)
318 break;
319
320 if (i == nr_iters)
321 continue;
322
323 nr_id_found++;
324
325 err = bpf_obj_get_info_by_fd(link_fd, &link_info, &info_len);
326 cmp_res = memcmp(&link_info, &link_infos[i],
327 offsetof(struct bpf_link_info, raw_tracepoint));
328 CHECK(err || info_len != sizeof(link_info) || cmp_res,
329 "check get-link-info(next_id->fd)",
330 "err %d errno %d info_len %u(%zu) memcmp %d\n",
331 err, errno, info_len, sizeof(struct bpf_link_info),
332 cmp_res);
333
334 close(link_fd);
335 }
336 CHECK(nr_id_found != nr_iters,
337 "check total link id found by get_next_id",
338 "nr_id_found %u(%u)\n", nr_id_found, nr_iters);
339
340 done:
341 for (i = 0; i < nr_iters; i++) {
342 bpf_link__destroy(links[i]);
343 bpf_object__close(objs[i]);
344 }
345 }
346