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