1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (c) 2019 Netronome Systems, Inc. */
3
4 #include <ctype.h>
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <net/if.h>
10 #ifdef USE_LIBCAP
11 #include <sys/capability.h>
12 #endif
13 #include <sys/vfs.h>
14
15 #include <linux/filter.h>
16 #include <linux/limits.h>
17
18 #include <bpf/bpf.h>
19 #include <bpf/libbpf.h>
20
21 #include "main.h"
22
23 #ifndef PROC_SUPER_MAGIC
24 # define PROC_SUPER_MAGIC 0x9fa0
25 #endif
26
27 enum probe_component {
28 COMPONENT_UNSPEC,
29 COMPONENT_KERNEL,
30 COMPONENT_DEVICE,
31 };
32
33 #define BPF_HELPER_MAKE_ENTRY(name) [BPF_FUNC_ ## name] = "bpf_" # name
34 static const char * const helper_name[] = {
35 __BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY)
36 };
37
38 #undef BPF_HELPER_MAKE_ENTRY
39
40 static bool full_mode;
41 #ifdef USE_LIBCAP
42 static bool run_as_unprivileged;
43 #endif
44
45 /* Miscellaneous utility functions */
46
grep(const char * buffer,const char * pattern)47 static bool grep(const char *buffer, const char *pattern)
48 {
49 return !!strstr(buffer, pattern);
50 }
51
check_procfs(void)52 static bool check_procfs(void)
53 {
54 struct statfs st_fs;
55
56 if (statfs("/proc", &st_fs) < 0)
57 return false;
58 if ((unsigned long)st_fs.f_type != PROC_SUPER_MAGIC)
59 return false;
60
61 return true;
62 }
63
uppercase(char * str,size_t len)64 static void uppercase(char *str, size_t len)
65 {
66 size_t i;
67
68 for (i = 0; i < len && str[i] != '\0'; i++)
69 str[i] = toupper(str[i]);
70 }
71
72 /* Printing utility functions */
73
74 static void
print_bool_feature(const char * feat_name,const char * plain_name,const char * define_name,bool res,const char * define_prefix)75 print_bool_feature(const char *feat_name, const char *plain_name,
76 const char *define_name, bool res, const char *define_prefix)
77 {
78 if (json_output)
79 jsonw_bool_field(json_wtr, feat_name, res);
80 else if (define_prefix)
81 printf("#define %s%sHAVE_%s\n", define_prefix,
82 res ? "" : "NO_", define_name);
83 else
84 printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
85 }
86
print_kernel_option(const char * name,const char * value,const char * define_prefix)87 static void print_kernel_option(const char *name, const char *value,
88 const char *define_prefix)
89 {
90 char *endptr;
91 int res;
92
93 if (json_output) {
94 if (!value) {
95 jsonw_null_field(json_wtr, name);
96 return;
97 }
98 errno = 0;
99 res = strtol(value, &endptr, 0);
100 if (!errno && *endptr == '\n')
101 jsonw_int_field(json_wtr, name, res);
102 else
103 jsonw_string_field(json_wtr, name, value);
104 } else if (define_prefix) {
105 if (value)
106 printf("#define %s%s %s\n", define_prefix,
107 name, value);
108 else
109 printf("/* %s%s is not set */\n", define_prefix, name);
110 } else {
111 if (value)
112 printf("%s is set to %s\n", name, value);
113 else
114 printf("%s is not set\n", name);
115 }
116 }
117
118 static void
print_start_section(const char * json_title,const char * plain_title,const char * define_comment,const char * define_prefix)119 print_start_section(const char *json_title, const char *plain_title,
120 const char *define_comment, const char *define_prefix)
121 {
122 if (json_output) {
123 jsonw_name(json_wtr, json_title);
124 jsonw_start_object(json_wtr);
125 } else if (define_prefix) {
126 printf("%s\n", define_comment);
127 } else {
128 printf("%s\n", plain_title);
129 }
130 }
131
print_end_section(void)132 static void print_end_section(void)
133 {
134 if (json_output)
135 jsonw_end_object(json_wtr);
136 else
137 printf("\n");
138 }
139
140 /* Probing functions */
141
get_vendor_id(int ifindex)142 static int get_vendor_id(int ifindex)
143 {
144 char ifname[IF_NAMESIZE], path[64], buf[8];
145 ssize_t len;
146 int fd;
147
148 if (!if_indextoname(ifindex, ifname))
149 return -1;
150
151 snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname);
152
153 fd = open(path, O_RDONLY | O_CLOEXEC);
154 if (fd < 0)
155 return -1;
156
157 len = read(fd, buf, sizeof(buf));
158 close(fd);
159 if (len < 0)
160 return -1;
161 if (len >= (ssize_t)sizeof(buf))
162 return -1;
163 buf[len] = '\0';
164
165 return strtol(buf, NULL, 0);
166 }
167
read_procfs(const char * path)168 static long read_procfs(const char *path)
169 {
170 char *endptr, *line = NULL;
171 size_t len = 0;
172 FILE *fd;
173 long res;
174
175 fd = fopen(path, "r");
176 if (!fd)
177 return -1;
178
179 res = getline(&line, &len, fd);
180 fclose(fd);
181 if (res < 0)
182 return -1;
183
184 errno = 0;
185 res = strtol(line, &endptr, 10);
186 if (errno || *line == '\0' || *endptr != '\n')
187 res = -1;
188 free(line);
189
190 return res;
191 }
192
probe_unprivileged_disabled(void)193 static void probe_unprivileged_disabled(void)
194 {
195 long res;
196
197 /* No support for C-style output */
198
199 res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
200 if (json_output) {
201 jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
202 } else {
203 switch (res) {
204 case 0:
205 printf("bpf() syscall for unprivileged users is enabled\n");
206 break;
207 case 1:
208 printf("bpf() syscall restricted to privileged users (without recovery)\n");
209 break;
210 case 2:
211 printf("bpf() syscall restricted to privileged users (admin can change)\n");
212 break;
213 case -1:
214 printf("Unable to retrieve required privileges for bpf() syscall\n");
215 break;
216 default:
217 printf("bpf() syscall restriction has unknown value %ld\n", res);
218 }
219 }
220 }
221
probe_jit_enable(void)222 static void probe_jit_enable(void)
223 {
224 long res;
225
226 /* No support for C-style output */
227
228 res = read_procfs("/proc/sys/net/core/bpf_jit_enable");
229 if (json_output) {
230 jsonw_int_field(json_wtr, "bpf_jit_enable", res);
231 } else {
232 switch (res) {
233 case 0:
234 printf("JIT compiler is disabled\n");
235 break;
236 case 1:
237 printf("JIT compiler is enabled\n");
238 break;
239 case 2:
240 printf("JIT compiler is enabled with debugging traces in kernel logs\n");
241 break;
242 case -1:
243 printf("Unable to retrieve JIT-compiler status\n");
244 break;
245 default:
246 printf("JIT-compiler status has unknown value %ld\n",
247 res);
248 }
249 }
250 }
251
probe_jit_harden(void)252 static void probe_jit_harden(void)
253 {
254 long res;
255
256 /* No support for C-style output */
257
258 res = read_procfs("/proc/sys/net/core/bpf_jit_harden");
259 if (json_output) {
260 jsonw_int_field(json_wtr, "bpf_jit_harden", res);
261 } else {
262 switch (res) {
263 case 0:
264 printf("JIT compiler hardening is disabled\n");
265 break;
266 case 1:
267 printf("JIT compiler hardening is enabled for unprivileged users\n");
268 break;
269 case 2:
270 printf("JIT compiler hardening is enabled for all users\n");
271 break;
272 case -1:
273 printf("Unable to retrieve JIT hardening status\n");
274 break;
275 default:
276 printf("JIT hardening status has unknown value %ld\n",
277 res);
278 }
279 }
280 }
281
probe_jit_kallsyms(void)282 static void probe_jit_kallsyms(void)
283 {
284 long res;
285
286 /* No support for C-style output */
287
288 res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms");
289 if (json_output) {
290 jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res);
291 } else {
292 switch (res) {
293 case 0:
294 printf("JIT compiler kallsyms exports are disabled\n");
295 break;
296 case 1:
297 printf("JIT compiler kallsyms exports are enabled for root\n");
298 break;
299 case -1:
300 printf("Unable to retrieve JIT kallsyms export status\n");
301 break;
302 default:
303 printf("JIT kallsyms exports status has unknown value %ld\n", res);
304 }
305 }
306 }
307
probe_jit_limit(void)308 static void probe_jit_limit(void)
309 {
310 long res;
311
312 /* No support for C-style output */
313
314 res = read_procfs("/proc/sys/net/core/bpf_jit_limit");
315 if (json_output) {
316 jsonw_int_field(json_wtr, "bpf_jit_limit", res);
317 } else {
318 switch (res) {
319 case -1:
320 printf("Unable to retrieve global memory limit for JIT compiler for unprivileged users\n");
321 break;
322 default:
323 printf("Global memory limit for JIT compiler for unprivileged users is %ld bytes\n", res);
324 }
325 }
326 }
327
probe_kernel_image_config(const char * define_prefix)328 static void probe_kernel_image_config(const char *define_prefix)
329 {
330 struct kernel_config_option options[] = {
331 /* Enable BPF */
332 { "CONFIG_BPF", },
333 /* Enable bpf() syscall */
334 { "CONFIG_BPF_SYSCALL", },
335 /* Does selected architecture support eBPF JIT compiler */
336 { "CONFIG_HAVE_EBPF_JIT", },
337 /* Compile eBPF JIT compiler */
338 { "CONFIG_BPF_JIT", },
339 /* Avoid compiling eBPF interpreter (use JIT only) */
340 { "CONFIG_BPF_JIT_ALWAYS_ON", },
341 /* Kernel BTF debug information available */
342 { "CONFIG_DEBUG_INFO_BTF", },
343 /* Kernel module BTF debug information available */
344 { "CONFIG_DEBUG_INFO_BTF_MODULES", },
345
346 /* cgroups */
347 { "CONFIG_CGROUPS", },
348 /* BPF programs attached to cgroups */
349 { "CONFIG_CGROUP_BPF", },
350 /* bpf_get_cgroup_classid() helper */
351 { "CONFIG_CGROUP_NET_CLASSID", },
352 /* bpf_skb_{,ancestor_}cgroup_id() helpers */
353 { "CONFIG_SOCK_CGROUP_DATA", },
354
355 /* Tracing: attach BPF to kprobes, tracepoints, etc. */
356 { "CONFIG_BPF_EVENTS", },
357 /* Kprobes */
358 { "CONFIG_KPROBE_EVENTS", },
359 /* Uprobes */
360 { "CONFIG_UPROBE_EVENTS", },
361 /* Tracepoints */
362 { "CONFIG_TRACING", },
363 /* Syscall tracepoints */
364 { "CONFIG_FTRACE_SYSCALLS", },
365 /* bpf_override_return() helper support for selected arch */
366 { "CONFIG_FUNCTION_ERROR_INJECTION", },
367 /* bpf_override_return() helper */
368 { "CONFIG_BPF_KPROBE_OVERRIDE", },
369
370 /* Network */
371 { "CONFIG_NET", },
372 /* AF_XDP sockets */
373 { "CONFIG_XDP_SOCKETS", },
374 /* BPF_PROG_TYPE_LWT_* and related helpers */
375 { "CONFIG_LWTUNNEL_BPF", },
376 /* BPF_PROG_TYPE_SCHED_ACT, TC (traffic control) actions */
377 { "CONFIG_NET_ACT_BPF", },
378 /* BPF_PROG_TYPE_SCHED_CLS, TC filters */
379 { "CONFIG_NET_CLS_BPF", },
380 /* TC clsact qdisc */
381 { "CONFIG_NET_CLS_ACT", },
382 /* Ingress filtering with TC */
383 { "CONFIG_NET_SCH_INGRESS", },
384 /* bpf_skb_get_xfrm_state() helper */
385 { "CONFIG_XFRM", },
386 /* bpf_get_route_realm() helper */
387 { "CONFIG_IP_ROUTE_CLASSID", },
388 /* BPF_PROG_TYPE_LWT_SEG6_LOCAL and related helpers */
389 { "CONFIG_IPV6_SEG6_BPF", },
390 /* BPF_PROG_TYPE_LIRC_MODE2 and related helpers */
391 { "CONFIG_BPF_LIRC_MODE2", },
392 /* BPF stream parser and BPF socket maps */
393 { "CONFIG_BPF_STREAM_PARSER", },
394 /* xt_bpf module for passing BPF programs to netfilter */
395 { "CONFIG_NETFILTER_XT_MATCH_BPF", },
396
397 /* test_bpf module for BPF tests */
398 { "CONFIG_TEST_BPF", },
399
400 /* Misc configs useful in BPF C programs */
401 /* jiffies <-> sec conversion for bpf_jiffies64() helper */
402 { "CONFIG_HZ", true, }
403 };
404 char *values[ARRAY_SIZE(options)] = { };
405 size_t i;
406
407 if (read_kernel_config(options, ARRAY_SIZE(options), values,
408 define_prefix))
409 return;
410
411 for (i = 0; i < ARRAY_SIZE(options); i++) {
412 if (define_prefix && !options[i].macro_dump)
413 continue;
414 print_kernel_option(options[i].name, values[i], define_prefix);
415 free(values[i]);
416 }
417 }
418
probe_bpf_syscall(const char * define_prefix)419 static bool probe_bpf_syscall(const char *define_prefix)
420 {
421 bool res;
422
423 bpf_prog_load(BPF_PROG_TYPE_UNSPEC, NULL, NULL, NULL, 0, NULL);
424 res = (errno != ENOSYS);
425
426 print_bool_feature("have_bpf_syscall",
427 "bpf() syscall",
428 "BPF_SYSCALL",
429 res, define_prefix);
430
431 return res;
432 }
433
434 static bool
probe_prog_load_ifindex(enum bpf_prog_type prog_type,const struct bpf_insn * insns,size_t insns_cnt,char * log_buf,size_t log_buf_sz,__u32 ifindex)435 probe_prog_load_ifindex(enum bpf_prog_type prog_type,
436 const struct bpf_insn *insns, size_t insns_cnt,
437 char *log_buf, size_t log_buf_sz,
438 __u32 ifindex)
439 {
440 LIBBPF_OPTS(bpf_prog_load_opts, opts,
441 .log_buf = log_buf,
442 .log_size = log_buf_sz,
443 .log_level = log_buf ? 1 : 0,
444 .prog_ifindex = ifindex,
445 );
446 int fd;
447
448 errno = 0;
449 fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insns_cnt, &opts);
450 if (fd >= 0)
451 close(fd);
452
453 return fd >= 0 && errno != EINVAL && errno != EOPNOTSUPP;
454 }
455
probe_prog_type_ifindex(enum bpf_prog_type prog_type,__u32 ifindex)456 static bool probe_prog_type_ifindex(enum bpf_prog_type prog_type, __u32 ifindex)
457 {
458 /* nfp returns -EINVAL on exit(0) with TC offload */
459 struct bpf_insn insns[2] = {
460 BPF_MOV64_IMM(BPF_REG_0, 2),
461 BPF_EXIT_INSN()
462 };
463
464 return probe_prog_load_ifindex(prog_type, insns, ARRAY_SIZE(insns),
465 NULL, 0, ifindex);
466 }
467
468 static void
probe_prog_type(enum bpf_prog_type prog_type,const char * prog_type_str,bool * supported_types,const char * define_prefix,__u32 ifindex)469 probe_prog_type(enum bpf_prog_type prog_type, const char *prog_type_str,
470 bool *supported_types, const char *define_prefix, __u32 ifindex)
471 {
472 char feat_name[128], plain_desc[128], define_name[128];
473 const char *plain_comment = "eBPF program_type ";
474 size_t maxlen;
475 bool res;
476
477 if (ifindex) {
478 switch (prog_type) {
479 case BPF_PROG_TYPE_SCHED_CLS:
480 case BPF_PROG_TYPE_XDP:
481 break;
482 default:
483 return;
484 }
485
486 res = probe_prog_type_ifindex(prog_type, ifindex);
487 } else {
488 res = libbpf_probe_bpf_prog_type(prog_type, NULL) > 0;
489 }
490
491 #ifdef USE_LIBCAP
492 /* Probe may succeed even if program load fails, for unprivileged users
493 * check that we did not fail because of insufficient permissions
494 */
495 if (run_as_unprivileged && errno == EPERM)
496 res = false;
497 #endif
498
499 supported_types[prog_type] |= res;
500
501 maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
502 if (strlen(prog_type_str) > maxlen) {
503 p_info("program type name too long");
504 return;
505 }
506
507 sprintf(feat_name, "have_%s_prog_type", prog_type_str);
508 sprintf(define_name, "%s_prog_type", prog_type_str);
509 uppercase(define_name, sizeof(define_name));
510 sprintf(plain_desc, "%s%s", plain_comment, prog_type_str);
511 print_bool_feature(feat_name, plain_desc, define_name, res,
512 define_prefix);
513 }
514
probe_map_type_ifindex(enum bpf_map_type map_type,__u32 ifindex)515 static bool probe_map_type_ifindex(enum bpf_map_type map_type, __u32 ifindex)
516 {
517 LIBBPF_OPTS(bpf_map_create_opts, opts);
518 int key_size, value_size, max_entries;
519 int fd;
520
521 opts.map_ifindex = ifindex;
522
523 key_size = sizeof(__u32);
524 value_size = sizeof(__u32);
525 max_entries = 1;
526
527 fd = bpf_map_create(map_type, NULL, key_size, value_size, max_entries,
528 &opts);
529 if (fd >= 0)
530 close(fd);
531
532 return fd >= 0;
533 }
534
535 static void
probe_map_type(enum bpf_map_type map_type,char const * map_type_str,const char * define_prefix,__u32 ifindex)536 probe_map_type(enum bpf_map_type map_type, char const *map_type_str,
537 const char *define_prefix, __u32 ifindex)
538 {
539 char feat_name[128], plain_desc[128], define_name[128];
540 const char *plain_comment = "eBPF map_type ";
541 size_t maxlen;
542 bool res;
543
544 if (ifindex) {
545 switch (map_type) {
546 case BPF_MAP_TYPE_HASH:
547 case BPF_MAP_TYPE_ARRAY:
548 break;
549 default:
550 return;
551 }
552
553 res = probe_map_type_ifindex(map_type, ifindex);
554 } else {
555 res = libbpf_probe_bpf_map_type(map_type, NULL) > 0;
556 }
557
558 /* Probe result depends on the success of map creation, no additional
559 * check required for unprivileged users
560 */
561
562 maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
563 if (strlen(map_type_str) > maxlen) {
564 p_info("map type name too long");
565 return;
566 }
567
568 sprintf(feat_name, "have_%s_map_type", map_type_str);
569 sprintf(define_name, "%s_map_type", map_type_str);
570 uppercase(define_name, sizeof(define_name));
571 sprintf(plain_desc, "%s%s", plain_comment, map_type_str);
572 print_bool_feature(feat_name, plain_desc, define_name, res,
573 define_prefix);
574 }
575
576 static bool
probe_helper_ifindex(enum bpf_func_id id,enum bpf_prog_type prog_type,__u32 ifindex)577 probe_helper_ifindex(enum bpf_func_id id, enum bpf_prog_type prog_type,
578 __u32 ifindex)
579 {
580 struct bpf_insn insns[2] = {
581 BPF_EMIT_CALL(id),
582 BPF_EXIT_INSN()
583 };
584 char buf[4096] = {};
585 bool res;
586
587 probe_prog_load_ifindex(prog_type, insns, ARRAY_SIZE(insns), buf,
588 sizeof(buf), ifindex);
589 res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ") &&
590 !grep(buf, "program of this type cannot use helper ");
591
592 switch (get_vendor_id(ifindex)) {
593 case 0x19ee: /* Netronome specific */
594 res = res && !grep(buf, "not supported by FW") &&
595 !grep(buf, "unsupported function id");
596 break;
597 default:
598 break;
599 }
600
601 return res;
602 }
603
604 static bool
probe_helper_for_progtype(enum bpf_prog_type prog_type,bool supported_type,const char * define_prefix,unsigned int id,const char * ptype_name,__u32 ifindex)605 probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
606 const char *define_prefix, unsigned int id,
607 const char *ptype_name, __u32 ifindex)
608 {
609 bool res = false;
610
611 if (supported_type) {
612 if (ifindex)
613 res = probe_helper_ifindex(id, prog_type, ifindex);
614 else
615 res = libbpf_probe_bpf_helper(prog_type, id, NULL) > 0;
616 #ifdef USE_LIBCAP
617 /* Probe may succeed even if program load fails, for
618 * unprivileged users check that we did not fail because of
619 * insufficient permissions
620 */
621 if (run_as_unprivileged && errno == EPERM)
622 res = false;
623 #endif
624 }
625
626 if (json_output) {
627 if (res)
628 jsonw_string(json_wtr, helper_name[id]);
629 } else if (define_prefix) {
630 printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n",
631 define_prefix, ptype_name, helper_name[id],
632 res ? "1" : "0");
633 } else {
634 if (res)
635 printf("\n\t- %s", helper_name[id]);
636 }
637
638 return res;
639 }
640
641 static void
probe_helpers_for_progtype(enum bpf_prog_type prog_type,const char * prog_type_str,bool supported_type,const char * define_prefix,__u32 ifindex)642 probe_helpers_for_progtype(enum bpf_prog_type prog_type,
643 const char *prog_type_str, bool supported_type,
644 const char *define_prefix, __u32 ifindex)
645 {
646 char feat_name[128];
647 unsigned int id;
648 bool probe_res = false;
649
650 if (ifindex)
651 /* Only test helpers for offload-able program types */
652 switch (prog_type) {
653 case BPF_PROG_TYPE_SCHED_CLS:
654 case BPF_PROG_TYPE_XDP:
655 break;
656 default:
657 return;
658 }
659
660 if (json_output) {
661 sprintf(feat_name, "%s_available_helpers", prog_type_str);
662 jsonw_name(json_wtr, feat_name);
663 jsonw_start_array(json_wtr);
664 } else if (!define_prefix) {
665 printf("eBPF helpers supported for program type %s:",
666 prog_type_str);
667 }
668
669 for (id = 1; id < ARRAY_SIZE(helper_name); id++) {
670 /* Skip helper functions which emit dmesg messages when not in
671 * the full mode.
672 */
673 switch (id) {
674 case BPF_FUNC_trace_printk:
675 case BPF_FUNC_trace_vprintk:
676 case BPF_FUNC_probe_write_user:
677 if (!full_mode)
678 continue;
679 fallthrough;
680 default:
681 probe_res |= probe_helper_for_progtype(prog_type, supported_type,
682 define_prefix, id, prog_type_str,
683 ifindex);
684 }
685 }
686
687 if (json_output)
688 jsonw_end_array(json_wtr);
689 else if (!define_prefix) {
690 printf("\n");
691 if (!probe_res) {
692 if (!supported_type)
693 printf("\tProgram type not supported\n");
694 else
695 printf("\tCould not determine which helpers are available\n");
696 }
697 }
698
699
700 }
701
702 static void
probe_misc_feature(struct bpf_insn * insns,size_t len,const char * define_prefix,__u32 ifindex,const char * feat_name,const char * plain_name,const char * define_name)703 probe_misc_feature(struct bpf_insn *insns, size_t len,
704 const char *define_prefix, __u32 ifindex,
705 const char *feat_name, const char *plain_name,
706 const char *define_name)
707 {
708 LIBBPF_OPTS(bpf_prog_load_opts, opts,
709 .prog_ifindex = ifindex,
710 );
711 bool res;
712 int fd;
713
714 errno = 0;
715 fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL",
716 insns, len, &opts);
717 res = fd >= 0 || !errno;
718
719 if (fd >= 0)
720 close(fd);
721
722 print_bool_feature(feat_name, plain_name, define_name, res,
723 define_prefix);
724 }
725
726 /*
727 * Probe for availability of kernel commit (5.3):
728 *
729 * c04c0d2b968a ("bpf: increase complexity limit and maximum program size")
730 */
probe_large_insn_limit(const char * define_prefix,__u32 ifindex)731 static void probe_large_insn_limit(const char *define_prefix, __u32 ifindex)
732 {
733 struct bpf_insn insns[BPF_MAXINSNS + 1];
734 int i;
735
736 for (i = 0; i < BPF_MAXINSNS; i++)
737 insns[i] = BPF_MOV64_IMM(BPF_REG_0, 1);
738 insns[BPF_MAXINSNS] = BPF_EXIT_INSN();
739
740 probe_misc_feature(insns, ARRAY_SIZE(insns),
741 define_prefix, ifindex,
742 "have_large_insn_limit",
743 "Large program size limit",
744 "LARGE_INSN_LIMIT");
745 }
746
747 /*
748 * Probe for bounded loop support introduced in commit 2589726d12a1
749 * ("bpf: introduce bounded loops").
750 */
751 static void
probe_bounded_loops(const char * define_prefix,__u32 ifindex)752 probe_bounded_loops(const char *define_prefix, __u32 ifindex)
753 {
754 struct bpf_insn insns[4] = {
755 BPF_MOV64_IMM(BPF_REG_0, 10),
756 BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 1),
757 BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, -2),
758 BPF_EXIT_INSN()
759 };
760
761 probe_misc_feature(insns, ARRAY_SIZE(insns),
762 define_prefix, ifindex,
763 "have_bounded_loops",
764 "Bounded loop support",
765 "BOUNDED_LOOPS");
766 }
767
768 /*
769 * Probe for the v2 instruction set extension introduced in commit 92b31a9af73b
770 * ("bpf: add BPF_J{LT,LE,SLT,SLE} instructions").
771 */
772 static void
probe_v2_isa_extension(const char * define_prefix,__u32 ifindex)773 probe_v2_isa_extension(const char *define_prefix, __u32 ifindex)
774 {
775 struct bpf_insn insns[4] = {
776 BPF_MOV64_IMM(BPF_REG_0, 0),
777 BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 0, 1),
778 BPF_MOV64_IMM(BPF_REG_0, 1),
779 BPF_EXIT_INSN()
780 };
781
782 probe_misc_feature(insns, ARRAY_SIZE(insns),
783 define_prefix, ifindex,
784 "have_v2_isa_extension",
785 "ISA extension v2",
786 "V2_ISA_EXTENSION");
787 }
788
789 /*
790 * Probe for the v3 instruction set extension introduced in commit 092ed0968bb6
791 * ("bpf: verifier support JMP32").
792 */
793 static void
probe_v3_isa_extension(const char * define_prefix,__u32 ifindex)794 probe_v3_isa_extension(const char *define_prefix, __u32 ifindex)
795 {
796 struct bpf_insn insns[4] = {
797 BPF_MOV64_IMM(BPF_REG_0, 0),
798 BPF_JMP32_IMM(BPF_JLT, BPF_REG_0, 0, 1),
799 BPF_MOV64_IMM(BPF_REG_0, 1),
800 BPF_EXIT_INSN()
801 };
802
803 probe_misc_feature(insns, ARRAY_SIZE(insns),
804 define_prefix, ifindex,
805 "have_v3_isa_extension",
806 "ISA extension v3",
807 "V3_ISA_EXTENSION");
808 }
809
810 /*
811 * Probe for the v4 instruction set extension introduced in commit 1f9a1ea821ff
812 * ("bpf: Support new sign-extension load insns").
813 */
814 static void
probe_v4_isa_extension(const char * define_prefix,__u32 ifindex)815 probe_v4_isa_extension(const char *define_prefix, __u32 ifindex)
816 {
817 struct bpf_insn insns[5] = {
818 BPF_MOV64_IMM(BPF_REG_0, 0),
819 BPF_JMP32_IMM(BPF_JEQ, BPF_REG_0, 1, 1),
820 BPF_JMP32_A(1),
821 BPF_MOV64_IMM(BPF_REG_0, 1),
822 BPF_EXIT_INSN()
823 };
824
825 probe_misc_feature(insns, ARRAY_SIZE(insns),
826 define_prefix, ifindex,
827 "have_v4_isa_extension",
828 "ISA extension v4",
829 "V4_ISA_EXTENSION");
830 }
831
832 static void
section_system_config(enum probe_component target,const char * define_prefix)833 section_system_config(enum probe_component target, const char *define_prefix)
834 {
835 switch (target) {
836 case COMPONENT_KERNEL:
837 case COMPONENT_UNSPEC:
838 print_start_section("system_config",
839 "Scanning system configuration...",
840 "/*** Misc kernel config items ***/",
841 define_prefix);
842 if (!define_prefix) {
843 if (check_procfs()) {
844 probe_unprivileged_disabled();
845 probe_jit_enable();
846 probe_jit_harden();
847 probe_jit_kallsyms();
848 probe_jit_limit();
849 } else {
850 p_info("/* procfs not mounted, skipping related probes */");
851 }
852 }
853 probe_kernel_image_config(define_prefix);
854 print_end_section();
855 break;
856 default:
857 break;
858 }
859 }
860
section_syscall_config(const char * define_prefix)861 static bool section_syscall_config(const char *define_prefix)
862 {
863 bool res;
864
865 print_start_section("syscall_config",
866 "Scanning system call availability...",
867 "/*** System call availability ***/",
868 define_prefix);
869 res = probe_bpf_syscall(define_prefix);
870 print_end_section();
871
872 return res;
873 }
874
875 static void
section_program_types(bool * supported_types,const char * define_prefix,__u32 ifindex)876 section_program_types(bool *supported_types, const char *define_prefix,
877 __u32 ifindex)
878 {
879 unsigned int prog_type = BPF_PROG_TYPE_UNSPEC;
880 const char *prog_type_str;
881
882 print_start_section("program_types",
883 "Scanning eBPF program types...",
884 "/*** eBPF program types ***/",
885 define_prefix);
886
887 while (true) {
888 prog_type++;
889 prog_type_str = libbpf_bpf_prog_type_str(prog_type);
890 /* libbpf will return NULL for variants unknown to it. */
891 if (!prog_type_str)
892 break;
893
894 probe_prog_type(prog_type, prog_type_str, supported_types, define_prefix,
895 ifindex);
896 }
897
898 print_end_section();
899 }
900
section_map_types(const char * define_prefix,__u32 ifindex)901 static void section_map_types(const char *define_prefix, __u32 ifindex)
902 {
903 unsigned int map_type = BPF_MAP_TYPE_UNSPEC;
904 const char *map_type_str;
905
906 print_start_section("map_types",
907 "Scanning eBPF map types...",
908 "/*** eBPF map types ***/",
909 define_prefix);
910
911 while (true) {
912 map_type++;
913 map_type_str = libbpf_bpf_map_type_str(map_type);
914 /* libbpf will return NULL for variants unknown to it. */
915 if (!map_type_str)
916 break;
917
918 probe_map_type(map_type, map_type_str, define_prefix, ifindex);
919 }
920
921 print_end_section();
922 }
923
924 static void
section_helpers(bool * supported_types,const char * define_prefix,__u32 ifindex)925 section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex)
926 {
927 unsigned int prog_type = BPF_PROG_TYPE_UNSPEC;
928 const char *prog_type_str;
929
930 print_start_section("helpers",
931 "Scanning eBPF helper functions...",
932 "/*** eBPF helper functions ***/",
933 define_prefix);
934
935 if (define_prefix)
936 printf("/*\n"
937 " * Use %sHAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)\n"
938 " * to determine if <helper_name> is available for <prog_type_name>,\n"
939 " * e.g.\n"
940 " * #if %sHAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)\n"
941 " * // do stuff with this helper\n"
942 " * #elif\n"
943 " * // use a workaround\n"
944 " * #endif\n"
945 " */\n"
946 "#define %sHAVE_PROG_TYPE_HELPER(prog_type, helper) \\\n"
947 " %sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n",
948 define_prefix, define_prefix, define_prefix,
949 define_prefix);
950 while (true) {
951 prog_type++;
952 prog_type_str = libbpf_bpf_prog_type_str(prog_type);
953 /* libbpf will return NULL for variants unknown to it. */
954 if (!prog_type_str)
955 break;
956
957 probe_helpers_for_progtype(prog_type, prog_type_str,
958 supported_types[prog_type],
959 define_prefix,
960 ifindex);
961 }
962
963 print_end_section();
964 }
965
section_misc(const char * define_prefix,__u32 ifindex)966 static void section_misc(const char *define_prefix, __u32 ifindex)
967 {
968 print_start_section("misc",
969 "Scanning miscellaneous eBPF features...",
970 "/*** eBPF misc features ***/",
971 define_prefix);
972 probe_large_insn_limit(define_prefix, ifindex);
973 probe_bounded_loops(define_prefix, ifindex);
974 probe_v2_isa_extension(define_prefix, ifindex);
975 probe_v3_isa_extension(define_prefix, ifindex);
976 probe_v4_isa_extension(define_prefix, ifindex);
977 print_end_section();
978 }
979
980 #ifdef USE_LIBCAP
981 #define capability(c) { c, false, #c }
982 #define capability_msg(a, i) a[i].set ? "" : a[i].name, a[i].set ? "" : ", "
983 #endif
984
handle_perms(void)985 static int handle_perms(void)
986 {
987 #ifdef USE_LIBCAP
988 struct {
989 cap_value_t cap;
990 bool set;
991 char name[14]; /* strlen("CAP_SYS_ADMIN") */
992 } bpf_caps[] = {
993 capability(CAP_SYS_ADMIN),
994 #ifdef CAP_BPF
995 capability(CAP_BPF),
996 capability(CAP_NET_ADMIN),
997 capability(CAP_PERFMON),
998 #endif
999 };
1000 cap_value_t cap_list[ARRAY_SIZE(bpf_caps)];
1001 unsigned int i, nb_bpf_caps = 0;
1002 bool cap_sys_admin_only = true;
1003 cap_flag_value_t val;
1004 int res = -1;
1005 cap_t caps;
1006
1007 caps = cap_get_proc();
1008 if (!caps) {
1009 p_err("failed to get capabilities for process: %s",
1010 strerror(errno));
1011 return -1;
1012 }
1013
1014 #ifdef CAP_BPF
1015 if (CAP_IS_SUPPORTED(CAP_BPF))
1016 cap_sys_admin_only = false;
1017 #endif
1018
1019 for (i = 0; i < ARRAY_SIZE(bpf_caps); i++) {
1020 const char *cap_name = bpf_caps[i].name;
1021 cap_value_t cap = bpf_caps[i].cap;
1022
1023 if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val)) {
1024 p_err("bug: failed to retrieve %s status: %s", cap_name,
1025 strerror(errno));
1026 goto exit_free;
1027 }
1028
1029 if (val == CAP_SET) {
1030 bpf_caps[i].set = true;
1031 cap_list[nb_bpf_caps++] = cap;
1032 }
1033
1034 if (cap_sys_admin_only)
1035 /* System does not know about CAP_BPF, meaning that
1036 * CAP_SYS_ADMIN is the only capability required. We
1037 * just checked it, break.
1038 */
1039 break;
1040 }
1041
1042 if ((run_as_unprivileged && !nb_bpf_caps) ||
1043 (!run_as_unprivileged && nb_bpf_caps == ARRAY_SIZE(bpf_caps)) ||
1044 (!run_as_unprivileged && cap_sys_admin_only && nb_bpf_caps)) {
1045 /* We are all good, exit now */
1046 res = 0;
1047 goto exit_free;
1048 }
1049
1050 if (!run_as_unprivileged) {
1051 if (cap_sys_admin_only)
1052 p_err("missing %s, required for full feature probing; run as root or use 'unprivileged'",
1053 bpf_caps[0].name);
1054 else
1055 p_err("missing %s%s%s%s%s%s%s%srequired for full feature probing; run as root or use 'unprivileged'",
1056 capability_msg(bpf_caps, 0),
1057 #ifdef CAP_BPF
1058 capability_msg(bpf_caps, 1),
1059 capability_msg(bpf_caps, 2),
1060 capability_msg(bpf_caps, 3)
1061 #else
1062 "", "", "", "", "", ""
1063 #endif /* CAP_BPF */
1064 );
1065 goto exit_free;
1066 }
1067
1068 /* if (run_as_unprivileged && nb_bpf_caps > 0), drop capabilities. */
1069 if (cap_set_flag(caps, CAP_EFFECTIVE, nb_bpf_caps, cap_list,
1070 CAP_CLEAR)) {
1071 p_err("bug: failed to clear capabilities: %s", strerror(errno));
1072 goto exit_free;
1073 }
1074
1075 if (cap_set_proc(caps)) {
1076 p_err("failed to drop capabilities: %s", strerror(errno));
1077 goto exit_free;
1078 }
1079
1080 res = 0;
1081
1082 exit_free:
1083 if (cap_free(caps) && !res) {
1084 p_err("failed to clear storage object for capabilities: %s",
1085 strerror(errno));
1086 res = -1;
1087 }
1088
1089 return res;
1090 #else
1091 /* Detection assumes user has specific privileges.
1092 * We do not use libcap so let's approximate, and restrict usage to
1093 * root user only.
1094 */
1095 if (geteuid()) {
1096 p_err("full feature probing requires root privileges");
1097 return -1;
1098 }
1099
1100 return 0;
1101 #endif /* USE_LIBCAP */
1102 }
1103
do_probe(int argc,char ** argv)1104 static int do_probe(int argc, char **argv)
1105 {
1106 enum probe_component target = COMPONENT_UNSPEC;
1107 const char *define_prefix = NULL;
1108 bool supported_types[128] = {};
1109 __u32 ifindex = 0;
1110 char *ifname;
1111
1112 set_max_rlimit();
1113
1114 while (argc) {
1115 if (is_prefix(*argv, "kernel")) {
1116 if (target != COMPONENT_UNSPEC) {
1117 p_err("component to probe already specified");
1118 return -1;
1119 }
1120 target = COMPONENT_KERNEL;
1121 NEXT_ARG();
1122 } else if (is_prefix(*argv, "dev")) {
1123 NEXT_ARG();
1124
1125 if (target != COMPONENT_UNSPEC || ifindex) {
1126 p_err("component to probe already specified");
1127 return -1;
1128 }
1129 if (!REQ_ARGS(1))
1130 return -1;
1131
1132 target = COMPONENT_DEVICE;
1133 ifname = GET_ARG();
1134 ifindex = if_nametoindex(ifname);
1135 if (!ifindex) {
1136 p_err("unrecognized netdevice '%s': %s", ifname,
1137 strerror(errno));
1138 return -1;
1139 }
1140 } else if (is_prefix(*argv, "full")) {
1141 full_mode = true;
1142 NEXT_ARG();
1143 } else if (is_prefix(*argv, "macros") && !define_prefix) {
1144 define_prefix = "";
1145 NEXT_ARG();
1146 } else if (is_prefix(*argv, "prefix")) {
1147 if (!define_prefix) {
1148 p_err("'prefix' argument can only be use after 'macros'");
1149 return -1;
1150 }
1151 if (strcmp(define_prefix, "")) {
1152 p_err("'prefix' already defined");
1153 return -1;
1154 }
1155 NEXT_ARG();
1156
1157 if (!REQ_ARGS(1))
1158 return -1;
1159 define_prefix = GET_ARG();
1160 } else if (is_prefix(*argv, "unprivileged")) {
1161 #ifdef USE_LIBCAP
1162 run_as_unprivileged = true;
1163 NEXT_ARG();
1164 #else
1165 p_err("unprivileged run not supported, recompile bpftool with libcap");
1166 return -1;
1167 #endif
1168 } else {
1169 p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?",
1170 *argv);
1171 return -1;
1172 }
1173 }
1174
1175 /* Full feature detection requires specific privileges.
1176 * Let's approximate, and warn if user is not root.
1177 */
1178 if (handle_perms())
1179 return -1;
1180
1181 if (json_output) {
1182 define_prefix = NULL;
1183 jsonw_start_object(json_wtr);
1184 }
1185
1186 section_system_config(target, define_prefix);
1187 if (!section_syscall_config(define_prefix))
1188 /* bpf() syscall unavailable, don't probe other BPF features */
1189 goto exit_close_json;
1190 section_program_types(supported_types, define_prefix, ifindex);
1191 section_map_types(define_prefix, ifindex);
1192 section_helpers(supported_types, define_prefix, ifindex);
1193 section_misc(define_prefix, ifindex);
1194
1195 exit_close_json:
1196 if (json_output)
1197 /* End root object */
1198 jsonw_end_object(json_wtr);
1199
1200 return 0;
1201 }
1202
get_helper_name(unsigned int id)1203 static const char *get_helper_name(unsigned int id)
1204 {
1205 if (id >= ARRAY_SIZE(helper_name))
1206 return NULL;
1207
1208 return helper_name[id];
1209 }
1210
do_list_builtins(int argc,char ** argv)1211 static int do_list_builtins(int argc, char **argv)
1212 {
1213 const char *(*get_name)(unsigned int id);
1214 unsigned int id = 0;
1215
1216 if (argc < 1)
1217 usage();
1218
1219 if (is_prefix(*argv, "prog_types")) {
1220 get_name = (const char *(*)(unsigned int))libbpf_bpf_prog_type_str;
1221 } else if (is_prefix(*argv, "map_types")) {
1222 get_name = (const char *(*)(unsigned int))libbpf_bpf_map_type_str;
1223 } else if (is_prefix(*argv, "attach_types")) {
1224 get_name = (const char *(*)(unsigned int))libbpf_bpf_attach_type_str;
1225 } else if (is_prefix(*argv, "link_types")) {
1226 get_name = (const char *(*)(unsigned int))libbpf_bpf_link_type_str;
1227 } else if (is_prefix(*argv, "helpers")) {
1228 get_name = get_helper_name;
1229 } else {
1230 p_err("expected 'prog_types', 'map_types', 'attach_types', 'link_types' or 'helpers', got: %s", *argv);
1231 return -1;
1232 }
1233
1234 if (json_output)
1235 jsonw_start_array(json_wtr); /* root array */
1236
1237 while (true) {
1238 const char *name;
1239
1240 name = get_name(id++);
1241 if (!name)
1242 break;
1243 if (json_output)
1244 jsonw_string(json_wtr, name);
1245 else
1246 printf("%s\n", name);
1247 }
1248
1249 if (json_output)
1250 jsonw_end_array(json_wtr); /* root array */
1251
1252 return 0;
1253 }
1254
do_help(int argc,char ** argv)1255 static int do_help(int argc, char **argv)
1256 {
1257 if (json_output) {
1258 jsonw_null(json_wtr);
1259 return 0;
1260 }
1261
1262 fprintf(stderr,
1263 "Usage: %1$s %2$s probe [COMPONENT] [full] [unprivileged] [macros [prefix PREFIX]]\n"
1264 " %1$s %2$s list_builtins GROUP\n"
1265 " %1$s %2$s help\n"
1266 "\n"
1267 " COMPONENT := { kernel | dev NAME }\n"
1268 " GROUP := { prog_types | map_types | attach_types | link_types | helpers }\n"
1269 " " HELP_SPEC_OPTIONS " }\n"
1270 "",
1271 bin_name, argv[-2]);
1272
1273 return 0;
1274 }
1275
1276 static const struct cmd cmds[] = {
1277 { "probe", do_probe },
1278 { "list_builtins", do_list_builtins },
1279 { "help", do_help },
1280 { 0 }
1281 };
1282
do_feature(int argc,char ** argv)1283 int do_feature(int argc, char **argv)
1284 {
1285 return cmd_select(cmds, argc, argv, do_help);
1286 }
1287