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 <string.h> 7 #include <unistd.h> 8 #include <net/if.h> 9 #include <sys/utsname.h> 10 #include <sys/vfs.h> 11 12 #include <linux/filter.h> 13 #include <linux/limits.h> 14 15 #include <bpf.h> 16 #include <libbpf.h> 17 18 #include "main.h" 19 20 #ifndef PROC_SUPER_MAGIC 21 # define PROC_SUPER_MAGIC 0x9fa0 22 #endif 23 24 enum probe_component { 25 COMPONENT_UNSPEC, 26 COMPONENT_KERNEL, 27 COMPONENT_DEVICE, 28 }; 29 30 #define BPF_HELPER_MAKE_ENTRY(name) [BPF_FUNC_ ## name] = "bpf_" # name 31 static const char * const helper_name[] = { 32 __BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY) 33 }; 34 35 #undef BPF_HELPER_MAKE_ENTRY 36 37 /* Miscellaneous utility functions */ 38 39 static bool check_procfs(void) 40 { 41 struct statfs st_fs; 42 43 if (statfs("/proc", &st_fs) < 0) 44 return false; 45 if ((unsigned long)st_fs.f_type != PROC_SUPER_MAGIC) 46 return false; 47 48 return true; 49 } 50 51 static void uppercase(char *str, size_t len) 52 { 53 size_t i; 54 55 for (i = 0; i < len && str[i] != '\0'; i++) 56 str[i] = toupper(str[i]); 57 } 58 59 /* Printing utility functions */ 60 61 static void 62 print_bool_feature(const char *feat_name, const char *plain_name, 63 const char *define_name, bool res, const char *define_prefix) 64 { 65 if (json_output) 66 jsonw_bool_field(json_wtr, feat_name, res); 67 else if (define_prefix) 68 printf("#define %s%sHAVE_%s\n", define_prefix, 69 res ? "" : "NO_", define_name); 70 else 71 printf("%s is %savailable\n", plain_name, res ? "" : "NOT "); 72 } 73 74 static void print_kernel_option(const char *name, const char *value) 75 { 76 char *endptr; 77 int res; 78 79 /* No support for C-style ouptut */ 80 81 if (json_output) { 82 if (!value) { 83 jsonw_null_field(json_wtr, name); 84 return; 85 } 86 errno = 0; 87 res = strtol(value, &endptr, 0); 88 if (!errno && *endptr == '\n') 89 jsonw_int_field(json_wtr, name, res); 90 else 91 jsonw_string_field(json_wtr, name, value); 92 } else { 93 if (value) 94 printf("%s is set to %s\n", name, value); 95 else 96 printf("%s is not set\n", name); 97 } 98 } 99 100 static void 101 print_start_section(const char *json_title, const char *plain_title, 102 const char *define_comment, const char *define_prefix) 103 { 104 if (json_output) { 105 jsonw_name(json_wtr, json_title); 106 jsonw_start_object(json_wtr); 107 } else if (define_prefix) { 108 printf("%s\n", define_comment); 109 } else { 110 printf("%s\n", plain_title); 111 } 112 } 113 114 static void 115 print_end_then_start_section(const char *json_title, const char *plain_title, 116 const char *define_comment, 117 const char *define_prefix) 118 { 119 if (json_output) 120 jsonw_end_object(json_wtr); 121 else 122 printf("\n"); 123 124 print_start_section(json_title, plain_title, define_comment, 125 define_prefix); 126 } 127 128 /* Probing functions */ 129 130 static int read_procfs(const char *path) 131 { 132 char *endptr, *line = NULL; 133 size_t len = 0; 134 FILE *fd; 135 int res; 136 137 fd = fopen(path, "r"); 138 if (!fd) 139 return -1; 140 141 res = getline(&line, &len, fd); 142 fclose(fd); 143 if (res < 0) 144 return -1; 145 146 errno = 0; 147 res = strtol(line, &endptr, 10); 148 if (errno || *line == '\0' || *endptr != '\n') 149 res = -1; 150 free(line); 151 152 return res; 153 } 154 155 static void probe_unprivileged_disabled(void) 156 { 157 int res; 158 159 /* No support for C-style ouptut */ 160 161 res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled"); 162 if (json_output) { 163 jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res); 164 } else { 165 switch (res) { 166 case 0: 167 printf("bpf() syscall for unprivileged users is enabled\n"); 168 break; 169 case 1: 170 printf("bpf() syscall restricted to privileged users\n"); 171 break; 172 case -1: 173 printf("Unable to retrieve required privileges for bpf() syscall\n"); 174 break; 175 default: 176 printf("bpf() syscall restriction has unknown value %d\n", res); 177 } 178 } 179 } 180 181 static void probe_jit_enable(void) 182 { 183 int res; 184 185 /* No support for C-style ouptut */ 186 187 res = read_procfs("/proc/sys/net/core/bpf_jit_enable"); 188 if (json_output) { 189 jsonw_int_field(json_wtr, "bpf_jit_enable", res); 190 } else { 191 switch (res) { 192 case 0: 193 printf("JIT compiler is disabled\n"); 194 break; 195 case 1: 196 printf("JIT compiler is enabled\n"); 197 break; 198 case 2: 199 printf("JIT compiler is enabled with debugging traces in kernel logs\n"); 200 break; 201 case -1: 202 printf("Unable to retrieve JIT-compiler status\n"); 203 break; 204 default: 205 printf("JIT-compiler status has unknown value %d\n", 206 res); 207 } 208 } 209 } 210 211 static void probe_jit_harden(void) 212 { 213 int res; 214 215 /* No support for C-style ouptut */ 216 217 res = read_procfs("/proc/sys/net/core/bpf_jit_harden"); 218 if (json_output) { 219 jsonw_int_field(json_wtr, "bpf_jit_harden", res); 220 } else { 221 switch (res) { 222 case 0: 223 printf("JIT compiler hardening is disabled\n"); 224 break; 225 case 1: 226 printf("JIT compiler hardening is enabled for unprivileged users\n"); 227 break; 228 case 2: 229 printf("JIT compiler hardening is enabled for all users\n"); 230 break; 231 case -1: 232 printf("Unable to retrieve JIT hardening status\n"); 233 break; 234 default: 235 printf("JIT hardening status has unknown value %d\n", 236 res); 237 } 238 } 239 } 240 241 static void probe_jit_kallsyms(void) 242 { 243 int res; 244 245 /* No support for C-style ouptut */ 246 247 res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms"); 248 if (json_output) { 249 jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res); 250 } else { 251 switch (res) { 252 case 0: 253 printf("JIT compiler kallsyms exports are disabled\n"); 254 break; 255 case 1: 256 printf("JIT compiler kallsyms exports are enabled for root\n"); 257 break; 258 case -1: 259 printf("Unable to retrieve JIT kallsyms export status\n"); 260 break; 261 default: 262 printf("JIT kallsyms exports status has unknown value %d\n", res); 263 } 264 } 265 } 266 267 static void probe_jit_limit(void) 268 { 269 int res; 270 271 /* No support for C-style ouptut */ 272 273 res = read_procfs("/proc/sys/net/core/bpf_jit_limit"); 274 if (json_output) { 275 jsonw_int_field(json_wtr, "bpf_jit_limit", res); 276 } else { 277 switch (res) { 278 case -1: 279 printf("Unable to retrieve global memory limit for JIT compiler for unprivileged users\n"); 280 break; 281 default: 282 printf("Global memory limit for JIT compiler for unprivileged users is %d bytes\n", res); 283 } 284 } 285 } 286 287 static char *get_kernel_config_option(FILE *fd, const char *option) 288 { 289 size_t line_n = 0, optlen = strlen(option); 290 char *res, *strval, *line = NULL; 291 ssize_t n; 292 293 rewind(fd); 294 while ((n = getline(&line, &line_n, fd)) > 0) { 295 if (strncmp(line, option, optlen)) 296 continue; 297 /* Check we have at least '=', value, and '\n' */ 298 if (strlen(line) < optlen + 3) 299 continue; 300 if (*(line + optlen) != '=') 301 continue; 302 303 /* Trim ending '\n' */ 304 line[strlen(line) - 1] = '\0'; 305 306 /* Copy and return config option value */ 307 strval = line + optlen + 1; 308 res = strdup(strval); 309 free(line); 310 return res; 311 } 312 free(line); 313 314 return NULL; 315 } 316 317 static void probe_kernel_image_config(void) 318 { 319 static const char * const options[] = { 320 /* Enable BPF */ 321 "CONFIG_BPF", 322 /* Enable bpf() syscall */ 323 "CONFIG_BPF_SYSCALL", 324 /* Does selected architecture support eBPF JIT compiler */ 325 "CONFIG_HAVE_EBPF_JIT", 326 /* Compile eBPF JIT compiler */ 327 "CONFIG_BPF_JIT", 328 /* Avoid compiling eBPF interpreter (use JIT only) */ 329 "CONFIG_BPF_JIT_ALWAYS_ON", 330 331 /* cgroups */ 332 "CONFIG_CGROUPS", 333 /* BPF programs attached to cgroups */ 334 "CONFIG_CGROUP_BPF", 335 /* bpf_get_cgroup_classid() helper */ 336 "CONFIG_CGROUP_NET_CLASSID", 337 /* bpf_skb_{,ancestor_}cgroup_id() helpers */ 338 "CONFIG_SOCK_CGROUP_DATA", 339 340 /* Tracing: attach BPF to kprobes, tracepoints, etc. */ 341 "CONFIG_BPF_EVENTS", 342 /* Kprobes */ 343 "CONFIG_KPROBE_EVENTS", 344 /* Uprobes */ 345 "CONFIG_UPROBE_EVENTS", 346 /* Tracepoints */ 347 "CONFIG_TRACING", 348 /* Syscall tracepoints */ 349 "CONFIG_FTRACE_SYSCALLS", 350 /* bpf_override_return() helper support for selected arch */ 351 "CONFIG_FUNCTION_ERROR_INJECTION", 352 /* bpf_override_return() helper */ 353 "CONFIG_BPF_KPROBE_OVERRIDE", 354 355 /* Network */ 356 "CONFIG_NET", 357 /* AF_XDP sockets */ 358 "CONFIG_XDP_SOCKETS", 359 /* BPF_PROG_TYPE_LWT_* and related helpers */ 360 "CONFIG_LWTUNNEL_BPF", 361 /* BPF_PROG_TYPE_SCHED_ACT, TC (traffic control) actions */ 362 "CONFIG_NET_ACT_BPF", 363 /* BPF_PROG_TYPE_SCHED_CLS, TC filters */ 364 "CONFIG_NET_CLS_BPF", 365 /* TC clsact qdisc */ 366 "CONFIG_NET_CLS_ACT", 367 /* Ingress filtering with TC */ 368 "CONFIG_NET_SCH_INGRESS", 369 /* bpf_skb_get_xfrm_state() helper */ 370 "CONFIG_XFRM", 371 /* bpf_get_route_realm() helper */ 372 "CONFIG_IP_ROUTE_CLASSID", 373 /* BPF_PROG_TYPE_LWT_SEG6_LOCAL and related helpers */ 374 "CONFIG_IPV6_SEG6_BPF", 375 /* BPF_PROG_TYPE_LIRC_MODE2 and related helpers */ 376 "CONFIG_BPF_LIRC_MODE2", 377 /* BPF stream parser and BPF socket maps */ 378 "CONFIG_BPF_STREAM_PARSER", 379 /* xt_bpf module for passing BPF programs to netfilter */ 380 "CONFIG_NETFILTER_XT_MATCH_BPF", 381 /* bpfilter back-end for iptables */ 382 "CONFIG_BPFILTER", 383 /* bpftilter module with "user mode helper" */ 384 "CONFIG_BPFILTER_UMH", 385 386 /* test_bpf module for BPF tests */ 387 "CONFIG_TEST_BPF", 388 }; 389 char *value, *buf = NULL; 390 struct utsname utsn; 391 char path[PATH_MAX]; 392 size_t i, n; 393 ssize_t ret; 394 FILE *fd; 395 396 if (uname(&utsn)) 397 goto no_config; 398 399 snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); 400 401 fd = fopen(path, "r"); 402 if (!fd && errno == ENOENT) { 403 /* Some distributions put the config file at /proc/config, give 404 * it a try. 405 * Sometimes it is also at /proc/config.gz but we do not try 406 * this one for now, it would require linking against libz. 407 */ 408 fd = fopen("/proc/config", "r"); 409 } 410 if (!fd) { 411 p_info("skipping kernel config, can't open file: %s", 412 strerror(errno)); 413 goto no_config; 414 } 415 /* Sanity checks */ 416 ret = getline(&buf, &n, fd); 417 ret = getline(&buf, &n, fd); 418 if (!buf || !ret) { 419 p_info("skipping kernel config, can't read from file: %s", 420 strerror(errno)); 421 free(buf); 422 goto no_config; 423 } 424 if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) { 425 p_info("skipping kernel config, can't find correct file"); 426 free(buf); 427 goto no_config; 428 } 429 free(buf); 430 431 for (i = 0; i < ARRAY_SIZE(options); i++) { 432 value = get_kernel_config_option(fd, options[i]); 433 print_kernel_option(options[i], value); 434 free(value); 435 } 436 fclose(fd); 437 return; 438 439 no_config: 440 for (i = 0; i < ARRAY_SIZE(options); i++) 441 print_kernel_option(options[i], NULL); 442 } 443 444 static bool probe_bpf_syscall(const char *define_prefix) 445 { 446 bool res; 447 448 bpf_load_program(BPF_PROG_TYPE_UNSPEC, NULL, 0, NULL, 0, NULL, 0); 449 res = (errno != ENOSYS); 450 451 print_bool_feature("have_bpf_syscall", 452 "bpf() syscall", 453 "BPF_SYSCALL", 454 res, define_prefix); 455 456 return res; 457 } 458 459 static void 460 probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types, 461 const char *define_prefix, __u32 ifindex) 462 { 463 char feat_name[128], plain_desc[128], define_name[128]; 464 const char *plain_comment = "eBPF program_type "; 465 size_t maxlen; 466 bool res; 467 468 if (ifindex) 469 /* Only test offload-able program types */ 470 switch (prog_type) { 471 case BPF_PROG_TYPE_SCHED_CLS: 472 case BPF_PROG_TYPE_XDP: 473 break; 474 default: 475 return; 476 } 477 478 res = bpf_probe_prog_type(prog_type, ifindex); 479 480 supported_types[prog_type] |= res; 481 482 maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; 483 if (strlen(prog_type_name[prog_type]) > maxlen) { 484 p_info("program type name too long"); 485 return; 486 } 487 488 sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]); 489 sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]); 490 uppercase(define_name, sizeof(define_name)); 491 sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]); 492 print_bool_feature(feat_name, plain_desc, define_name, res, 493 define_prefix); 494 } 495 496 static void 497 probe_map_type(enum bpf_map_type map_type, const char *define_prefix, 498 __u32 ifindex) 499 { 500 char feat_name[128], plain_desc[128], define_name[128]; 501 const char *plain_comment = "eBPF map_type "; 502 size_t maxlen; 503 bool res; 504 505 res = bpf_probe_map_type(map_type, ifindex); 506 507 maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; 508 if (strlen(map_type_name[map_type]) > maxlen) { 509 p_info("map type name too long"); 510 return; 511 } 512 513 sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]); 514 sprintf(define_name, "%s_map_type", map_type_name[map_type]); 515 uppercase(define_name, sizeof(define_name)); 516 sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]); 517 print_bool_feature(feat_name, plain_desc, define_name, res, 518 define_prefix); 519 } 520 521 static void 522 probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type, 523 const char *define_prefix, __u32 ifindex) 524 { 525 const char *ptype_name = prog_type_name[prog_type]; 526 char feat_name[128]; 527 unsigned int id; 528 bool res; 529 530 if (ifindex) 531 /* Only test helpers for offload-able program types */ 532 switch (prog_type) { 533 case BPF_PROG_TYPE_SCHED_CLS: 534 case BPF_PROG_TYPE_XDP: 535 break; 536 default: 537 return; 538 } 539 540 if (json_output) { 541 sprintf(feat_name, "%s_available_helpers", ptype_name); 542 jsonw_name(json_wtr, feat_name); 543 jsonw_start_array(json_wtr); 544 } else if (!define_prefix) { 545 printf("eBPF helpers supported for program type %s:", 546 ptype_name); 547 } 548 549 for (id = 1; id < ARRAY_SIZE(helper_name); id++) { 550 if (!supported_type) 551 res = false; 552 else 553 res = bpf_probe_helper(id, prog_type, ifindex); 554 555 if (json_output) { 556 if (res) 557 jsonw_string(json_wtr, helper_name[id]); 558 } else if (define_prefix) { 559 printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n", 560 define_prefix, ptype_name, helper_name[id], 561 res ? "1" : "0"); 562 } else { 563 if (res) 564 printf("\n\t- %s", helper_name[id]); 565 } 566 } 567 568 if (json_output) 569 jsonw_end_array(json_wtr); 570 else if (!define_prefix) 571 printf("\n"); 572 } 573 574 static int do_probe(int argc, char **argv) 575 { 576 enum probe_component target = COMPONENT_UNSPEC; 577 const char *define_prefix = NULL; 578 bool supported_types[128] = {}; 579 __u32 ifindex = 0; 580 unsigned int i; 581 char *ifname; 582 583 /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN). 584 * Let's approximate, and restrict usage to root user only. 585 */ 586 if (geteuid()) { 587 p_err("please run this command as root user"); 588 return -1; 589 } 590 591 set_max_rlimit(); 592 593 while (argc) { 594 if (is_prefix(*argv, "kernel")) { 595 if (target != COMPONENT_UNSPEC) { 596 p_err("component to probe already specified"); 597 return -1; 598 } 599 target = COMPONENT_KERNEL; 600 NEXT_ARG(); 601 } else if (is_prefix(*argv, "dev")) { 602 NEXT_ARG(); 603 604 if (target != COMPONENT_UNSPEC || ifindex) { 605 p_err("component to probe already specified"); 606 return -1; 607 } 608 if (!REQ_ARGS(1)) 609 return -1; 610 611 target = COMPONENT_DEVICE; 612 ifname = GET_ARG(); 613 ifindex = if_nametoindex(ifname); 614 if (!ifindex) { 615 p_err("unrecognized netdevice '%s': %s", ifname, 616 strerror(errno)); 617 return -1; 618 } 619 } else if (is_prefix(*argv, "macros") && !define_prefix) { 620 define_prefix = ""; 621 NEXT_ARG(); 622 } else if (is_prefix(*argv, "prefix")) { 623 if (!define_prefix) { 624 p_err("'prefix' argument can only be use after 'macros'"); 625 return -1; 626 } 627 if (strcmp(define_prefix, "")) { 628 p_err("'prefix' already defined"); 629 return -1; 630 } 631 NEXT_ARG(); 632 633 if (!REQ_ARGS(1)) 634 return -1; 635 define_prefix = GET_ARG(); 636 } else { 637 p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?", 638 *argv); 639 return -1; 640 } 641 } 642 643 if (json_output) { 644 define_prefix = NULL; 645 jsonw_start_object(json_wtr); 646 } 647 648 switch (target) { 649 case COMPONENT_KERNEL: 650 case COMPONENT_UNSPEC: 651 if (define_prefix) 652 break; 653 654 print_start_section("system_config", 655 "Scanning system configuration...", 656 NULL, /* define_comment never used here */ 657 NULL); /* define_prefix always NULL here */ 658 if (check_procfs()) { 659 probe_unprivileged_disabled(); 660 probe_jit_enable(); 661 probe_jit_harden(); 662 probe_jit_kallsyms(); 663 probe_jit_limit(); 664 } else { 665 p_info("/* procfs not mounted, skipping related probes */"); 666 } 667 probe_kernel_image_config(); 668 if (json_output) 669 jsonw_end_object(json_wtr); 670 else 671 printf("\n"); 672 break; 673 default: 674 break; 675 } 676 677 print_start_section("syscall_config", 678 "Scanning system call availability...", 679 "/*** System call availability ***/", 680 define_prefix); 681 682 if (!probe_bpf_syscall(define_prefix)) 683 /* bpf() syscall unavailable, don't probe other BPF features */ 684 goto exit_close_json; 685 686 print_end_then_start_section("program_types", 687 "Scanning eBPF program types...", 688 "/*** eBPF program types ***/", 689 define_prefix); 690 691 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) 692 probe_prog_type(i, supported_types, define_prefix, ifindex); 693 694 print_end_then_start_section("map_types", 695 "Scanning eBPF map types...", 696 "/*** eBPF map types ***/", 697 define_prefix); 698 699 for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++) 700 probe_map_type(i, define_prefix, ifindex); 701 702 print_end_then_start_section("helpers", 703 "Scanning eBPF helper functions...", 704 "/*** eBPF helper functions ***/", 705 define_prefix); 706 707 if (define_prefix) 708 printf("/*\n" 709 " * Use %sHAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)\n" 710 " * to determine if <helper_name> is available for <prog_type_name>,\n" 711 " * e.g.\n" 712 " * #if %sHAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)\n" 713 " * // do stuff with this helper\n" 714 " * #elif\n" 715 " * // use a workaround\n" 716 " * #endif\n" 717 " */\n" 718 "#define %sHAVE_PROG_TYPE_HELPER(prog_type, helper) \\\n" 719 " %sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n", 720 define_prefix, define_prefix, define_prefix, 721 define_prefix); 722 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) 723 probe_helpers_for_progtype(i, supported_types[i], 724 define_prefix, ifindex); 725 726 exit_close_json: 727 if (json_output) { 728 /* End current "section" of probes */ 729 jsonw_end_object(json_wtr); 730 /* End root object */ 731 jsonw_end_object(json_wtr); 732 } 733 734 return 0; 735 } 736 737 static int do_help(int argc, char **argv) 738 { 739 if (json_output) { 740 jsonw_null(json_wtr); 741 return 0; 742 } 743 744 fprintf(stderr, 745 "Usage: %s %s probe [COMPONENT] [macros [prefix PREFIX]]\n" 746 " %s %s help\n" 747 "\n" 748 " COMPONENT := { kernel | dev NAME }\n" 749 "", 750 bin_name, argv[-2], bin_name, argv[-2]); 751 752 return 0; 753 } 754 755 static const struct cmd cmds[] = { 756 { "probe", do_probe }, 757 { "help", do_help }, 758 { 0 } 759 }; 760 761 int do_feature(int argc, char **argv) 762 { 763 return cmd_select(cmds, argc, argv, do_help); 764 } 765