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/capability.h> 10 #include <sys/utsname.h> 11 #include <sys/vfs.h> 12 13 #include <linux/filter.h> 14 #include <linux/limits.h> 15 16 #include <bpf/bpf.h> 17 #include <bpf/libbpf.h> 18 #include <zlib.h> 19 20 #include "main.h" 21 22 #ifndef PROC_SUPER_MAGIC 23 # define PROC_SUPER_MAGIC 0x9fa0 24 #endif 25 26 enum probe_component { 27 COMPONENT_UNSPEC, 28 COMPONENT_KERNEL, 29 COMPONENT_DEVICE, 30 }; 31 32 #define BPF_HELPER_MAKE_ENTRY(name) [BPF_FUNC_ ## name] = "bpf_" # name 33 static const char * const helper_name[] = { 34 __BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY) 35 }; 36 37 #undef BPF_HELPER_MAKE_ENTRY 38 39 static bool full_mode; 40 static bool run_as_unprivileged; 41 42 /* Miscellaneous utility functions */ 43 44 static bool check_procfs(void) 45 { 46 struct statfs st_fs; 47 48 if (statfs("/proc", &st_fs) < 0) 49 return false; 50 if ((unsigned long)st_fs.f_type != PROC_SUPER_MAGIC) 51 return false; 52 53 return true; 54 } 55 56 static void uppercase(char *str, size_t len) 57 { 58 size_t i; 59 60 for (i = 0; i < len && str[i] != '\0'; i++) 61 str[i] = toupper(str[i]); 62 } 63 64 /* Printing utility functions */ 65 66 static void 67 print_bool_feature(const char *feat_name, const char *plain_name, 68 const char *define_name, bool res, const char *define_prefix) 69 { 70 if (json_output) 71 jsonw_bool_field(json_wtr, feat_name, res); 72 else if (define_prefix) 73 printf("#define %s%sHAVE_%s\n", define_prefix, 74 res ? "" : "NO_", define_name); 75 else 76 printf("%s is %savailable\n", plain_name, res ? "" : "NOT "); 77 } 78 79 static void print_kernel_option(const char *name, const char *value) 80 { 81 char *endptr; 82 int res; 83 84 /* No support for C-style ouptut */ 85 86 if (json_output) { 87 if (!value) { 88 jsonw_null_field(json_wtr, name); 89 return; 90 } 91 errno = 0; 92 res = strtol(value, &endptr, 0); 93 if (!errno && *endptr == '\n') 94 jsonw_int_field(json_wtr, name, res); 95 else 96 jsonw_string_field(json_wtr, name, value); 97 } else { 98 if (value) 99 printf("%s is set to %s\n", name, value); 100 else 101 printf("%s is not set\n", name); 102 } 103 } 104 105 static void 106 print_start_section(const char *json_title, const char *plain_title, 107 const char *define_comment, const char *define_prefix) 108 { 109 if (json_output) { 110 jsonw_name(json_wtr, json_title); 111 jsonw_start_object(json_wtr); 112 } else if (define_prefix) { 113 printf("%s\n", define_comment); 114 } else { 115 printf("%s\n", plain_title); 116 } 117 } 118 119 static void print_end_section(void) 120 { 121 if (json_output) 122 jsonw_end_object(json_wtr); 123 else 124 printf("\n"); 125 } 126 127 /* Probing functions */ 128 129 static int read_procfs(const char *path) 130 { 131 char *endptr, *line = NULL; 132 size_t len = 0; 133 FILE *fd; 134 int res; 135 136 fd = fopen(path, "r"); 137 if (!fd) 138 return -1; 139 140 res = getline(&line, &len, fd); 141 fclose(fd); 142 if (res < 0) 143 return -1; 144 145 errno = 0; 146 res = strtol(line, &endptr, 10); 147 if (errno || *line == '\0' || *endptr != '\n') 148 res = -1; 149 free(line); 150 151 return res; 152 } 153 154 static void probe_unprivileged_disabled(void) 155 { 156 int res; 157 158 /* No support for C-style ouptut */ 159 160 res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled"); 161 if (json_output) { 162 jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res); 163 } else { 164 switch (res) { 165 case 0: 166 printf("bpf() syscall for unprivileged users is enabled\n"); 167 break; 168 case 1: 169 printf("bpf() syscall restricted to privileged users\n"); 170 break; 171 case -1: 172 printf("Unable to retrieve required privileges for bpf() syscall\n"); 173 break; 174 default: 175 printf("bpf() syscall restriction has unknown value %d\n", res); 176 } 177 } 178 } 179 180 static void probe_jit_enable(void) 181 { 182 int res; 183 184 /* No support for C-style ouptut */ 185 186 res = read_procfs("/proc/sys/net/core/bpf_jit_enable"); 187 if (json_output) { 188 jsonw_int_field(json_wtr, "bpf_jit_enable", res); 189 } else { 190 switch (res) { 191 case 0: 192 printf("JIT compiler is disabled\n"); 193 break; 194 case 1: 195 printf("JIT compiler is enabled\n"); 196 break; 197 case 2: 198 printf("JIT compiler is enabled with debugging traces in kernel logs\n"); 199 break; 200 case -1: 201 printf("Unable to retrieve JIT-compiler status\n"); 202 break; 203 default: 204 printf("JIT-compiler status has unknown value %d\n", 205 res); 206 } 207 } 208 } 209 210 static void probe_jit_harden(void) 211 { 212 int res; 213 214 /* No support for C-style ouptut */ 215 216 res = read_procfs("/proc/sys/net/core/bpf_jit_harden"); 217 if (json_output) { 218 jsonw_int_field(json_wtr, "bpf_jit_harden", res); 219 } else { 220 switch (res) { 221 case 0: 222 printf("JIT compiler hardening is disabled\n"); 223 break; 224 case 1: 225 printf("JIT compiler hardening is enabled for unprivileged users\n"); 226 break; 227 case 2: 228 printf("JIT compiler hardening is enabled for all users\n"); 229 break; 230 case -1: 231 printf("Unable to retrieve JIT hardening status\n"); 232 break; 233 default: 234 printf("JIT hardening status has unknown value %d\n", 235 res); 236 } 237 } 238 } 239 240 static void probe_jit_kallsyms(void) 241 { 242 int res; 243 244 /* No support for C-style ouptut */ 245 246 res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms"); 247 if (json_output) { 248 jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res); 249 } else { 250 switch (res) { 251 case 0: 252 printf("JIT compiler kallsyms exports are disabled\n"); 253 break; 254 case 1: 255 printf("JIT compiler kallsyms exports are enabled for root\n"); 256 break; 257 case -1: 258 printf("Unable to retrieve JIT kallsyms export status\n"); 259 break; 260 default: 261 printf("JIT kallsyms exports status has unknown value %d\n", res); 262 } 263 } 264 } 265 266 static void probe_jit_limit(void) 267 { 268 int res; 269 270 /* No support for C-style ouptut */ 271 272 res = read_procfs("/proc/sys/net/core/bpf_jit_limit"); 273 if (json_output) { 274 jsonw_int_field(json_wtr, "bpf_jit_limit", res); 275 } else { 276 switch (res) { 277 case -1: 278 printf("Unable to retrieve global memory limit for JIT compiler for unprivileged users\n"); 279 break; 280 default: 281 printf("Global memory limit for JIT compiler for unprivileged users is %d bytes\n", res); 282 } 283 } 284 } 285 286 static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n, 287 char **value) 288 { 289 char *sep; 290 291 while (gzgets(file, buf, n)) { 292 if (strncmp(buf, "CONFIG_", 7)) 293 continue; 294 295 sep = strchr(buf, '='); 296 if (!sep) 297 continue; 298 299 /* Trim ending '\n' */ 300 buf[strlen(buf) - 1] = '\0'; 301 302 /* Split on '=' and ensure that a value is present. */ 303 *sep = '\0'; 304 if (!sep[1]) 305 continue; 306 307 *value = sep + 1; 308 return true; 309 } 310 311 return false; 312 } 313 314 static void probe_kernel_image_config(void) 315 { 316 static const char * const options[] = { 317 /* Enable BPF */ 318 "CONFIG_BPF", 319 /* Enable bpf() syscall */ 320 "CONFIG_BPF_SYSCALL", 321 /* Does selected architecture support eBPF JIT compiler */ 322 "CONFIG_HAVE_EBPF_JIT", 323 /* Compile eBPF JIT compiler */ 324 "CONFIG_BPF_JIT", 325 /* Avoid compiling eBPF interpreter (use JIT only) */ 326 "CONFIG_BPF_JIT_ALWAYS_ON", 327 328 /* cgroups */ 329 "CONFIG_CGROUPS", 330 /* BPF programs attached to cgroups */ 331 "CONFIG_CGROUP_BPF", 332 /* bpf_get_cgroup_classid() helper */ 333 "CONFIG_CGROUP_NET_CLASSID", 334 /* bpf_skb_{,ancestor_}cgroup_id() helpers */ 335 "CONFIG_SOCK_CGROUP_DATA", 336 337 /* Tracing: attach BPF to kprobes, tracepoints, etc. */ 338 "CONFIG_BPF_EVENTS", 339 /* Kprobes */ 340 "CONFIG_KPROBE_EVENTS", 341 /* Uprobes */ 342 "CONFIG_UPROBE_EVENTS", 343 /* Tracepoints */ 344 "CONFIG_TRACING", 345 /* Syscall tracepoints */ 346 "CONFIG_FTRACE_SYSCALLS", 347 /* bpf_override_return() helper support for selected arch */ 348 "CONFIG_FUNCTION_ERROR_INJECTION", 349 /* bpf_override_return() helper */ 350 "CONFIG_BPF_KPROBE_OVERRIDE", 351 352 /* Network */ 353 "CONFIG_NET", 354 /* AF_XDP sockets */ 355 "CONFIG_XDP_SOCKETS", 356 /* BPF_PROG_TYPE_LWT_* and related helpers */ 357 "CONFIG_LWTUNNEL_BPF", 358 /* BPF_PROG_TYPE_SCHED_ACT, TC (traffic control) actions */ 359 "CONFIG_NET_ACT_BPF", 360 /* BPF_PROG_TYPE_SCHED_CLS, TC filters */ 361 "CONFIG_NET_CLS_BPF", 362 /* TC clsact qdisc */ 363 "CONFIG_NET_CLS_ACT", 364 /* Ingress filtering with TC */ 365 "CONFIG_NET_SCH_INGRESS", 366 /* bpf_skb_get_xfrm_state() helper */ 367 "CONFIG_XFRM", 368 /* bpf_get_route_realm() helper */ 369 "CONFIG_IP_ROUTE_CLASSID", 370 /* BPF_PROG_TYPE_LWT_SEG6_LOCAL and related helpers */ 371 "CONFIG_IPV6_SEG6_BPF", 372 /* BPF_PROG_TYPE_LIRC_MODE2 and related helpers */ 373 "CONFIG_BPF_LIRC_MODE2", 374 /* BPF stream parser and BPF socket maps */ 375 "CONFIG_BPF_STREAM_PARSER", 376 /* xt_bpf module for passing BPF programs to netfilter */ 377 "CONFIG_NETFILTER_XT_MATCH_BPF", 378 /* bpfilter back-end for iptables */ 379 "CONFIG_BPFILTER", 380 /* bpftilter module with "user mode helper" */ 381 "CONFIG_BPFILTER_UMH", 382 383 /* test_bpf module for BPF tests */ 384 "CONFIG_TEST_BPF", 385 }; 386 char *values[ARRAY_SIZE(options)] = { }; 387 struct utsname utsn; 388 char path[PATH_MAX]; 389 gzFile file = NULL; 390 char buf[4096]; 391 char *value; 392 size_t i; 393 394 if (!uname(&utsn)) { 395 snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); 396 397 /* gzopen also accepts uncompressed files. */ 398 file = gzopen(path, "r"); 399 } 400 401 if (!file) { 402 /* Some distributions build with CONFIG_IKCONFIG=y and put the 403 * config file at /proc/config.gz. 404 */ 405 file = gzopen("/proc/config.gz", "r"); 406 } 407 if (!file) { 408 p_info("skipping kernel config, can't open file: %s", 409 strerror(errno)); 410 goto end_parse; 411 } 412 /* Sanity checks */ 413 if (!gzgets(file, buf, sizeof(buf)) || 414 !gzgets(file, buf, sizeof(buf))) { 415 p_info("skipping kernel config, can't read from file: %s", 416 strerror(errno)); 417 goto end_parse; 418 } 419 if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) { 420 p_info("skipping kernel config, can't find correct file"); 421 goto end_parse; 422 } 423 424 while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) { 425 for (i = 0; i < ARRAY_SIZE(options); i++) { 426 if (values[i] || strcmp(buf, options[i])) 427 continue; 428 429 values[i] = strdup(value); 430 } 431 } 432 433 end_parse: 434 if (file) 435 gzclose(file); 436 437 for (i = 0; i < ARRAY_SIZE(options); i++) { 438 print_kernel_option(options[i], values[i]); 439 free(values[i]); 440 } 441 } 442 443 static bool probe_bpf_syscall(const char *define_prefix) 444 { 445 bool res; 446 447 bpf_load_program(BPF_PROG_TYPE_UNSPEC, NULL, 0, NULL, 0, NULL, 0); 448 res = (errno != ENOSYS); 449 450 print_bool_feature("have_bpf_syscall", 451 "bpf() syscall", 452 "BPF_SYSCALL", 453 res, define_prefix); 454 455 return res; 456 } 457 458 static void 459 probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types, 460 const char *define_prefix, __u32 ifindex) 461 { 462 char feat_name[128], plain_desc[128], define_name[128]; 463 const char *plain_comment = "eBPF program_type "; 464 size_t maxlen; 465 bool res; 466 467 if (ifindex) 468 /* Only test offload-able program types */ 469 switch (prog_type) { 470 case BPF_PROG_TYPE_SCHED_CLS: 471 case BPF_PROG_TYPE_XDP: 472 break; 473 default: 474 return; 475 } 476 477 res = bpf_probe_prog_type(prog_type, ifindex); 478 /* Probe may succeed even if program load fails, for unprivileged users 479 * check that we did not fail because of insufficient permissions 480 */ 481 if (run_as_unprivileged && errno == EPERM) 482 res = false; 483 484 supported_types[prog_type] |= res; 485 486 maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; 487 if (strlen(prog_type_name[prog_type]) > maxlen) { 488 p_info("program type name too long"); 489 return; 490 } 491 492 sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]); 493 sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]); 494 uppercase(define_name, sizeof(define_name)); 495 sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]); 496 print_bool_feature(feat_name, plain_desc, define_name, res, 497 define_prefix); 498 } 499 500 static void 501 probe_map_type(enum bpf_map_type map_type, const char *define_prefix, 502 __u32 ifindex) 503 { 504 char feat_name[128], plain_desc[128], define_name[128]; 505 const char *plain_comment = "eBPF map_type "; 506 size_t maxlen; 507 bool res; 508 509 res = bpf_probe_map_type(map_type, ifindex); 510 511 /* Probe result depends on the success of map creation, no additional 512 * check required for unprivileged users 513 */ 514 515 maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; 516 if (strlen(map_type_name[map_type]) > maxlen) { 517 p_info("map type name too long"); 518 return; 519 } 520 521 sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]); 522 sprintf(define_name, "%s_map_type", map_type_name[map_type]); 523 uppercase(define_name, sizeof(define_name)); 524 sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]); 525 print_bool_feature(feat_name, plain_desc, define_name, res, 526 define_prefix); 527 } 528 529 static void 530 probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type, 531 const char *define_prefix, unsigned int id, 532 const char *ptype_name, __u32 ifindex) 533 { 534 bool res = false; 535 536 if (supported_type) { 537 res = bpf_probe_helper(id, prog_type, ifindex); 538 /* Probe may succeed even if program load fails, for 539 * unprivileged users check that we did not fail because of 540 * insufficient permissions 541 */ 542 if (run_as_unprivileged && errno == EPERM) 543 res = false; 544 } 545 546 if (json_output) { 547 if (res) 548 jsonw_string(json_wtr, helper_name[id]); 549 } else if (define_prefix) { 550 printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n", 551 define_prefix, ptype_name, helper_name[id], 552 res ? "1" : "0"); 553 } else { 554 if (res) 555 printf("\n\t- %s", helper_name[id]); 556 } 557 } 558 559 static void 560 probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type, 561 const char *define_prefix, __u32 ifindex) 562 { 563 const char *ptype_name = prog_type_name[prog_type]; 564 char feat_name[128]; 565 unsigned int id; 566 567 if (ifindex) 568 /* Only test helpers for offload-able program types */ 569 switch (prog_type) { 570 case BPF_PROG_TYPE_SCHED_CLS: 571 case BPF_PROG_TYPE_XDP: 572 break; 573 default: 574 return; 575 } 576 577 if (json_output) { 578 sprintf(feat_name, "%s_available_helpers", ptype_name); 579 jsonw_name(json_wtr, feat_name); 580 jsonw_start_array(json_wtr); 581 } else if (!define_prefix) { 582 printf("eBPF helpers supported for program type %s:", 583 ptype_name); 584 } 585 586 for (id = 1; id < ARRAY_SIZE(helper_name); id++) { 587 /* Skip helper functions which emit dmesg messages when not in 588 * the full mode. 589 */ 590 switch (id) { 591 case BPF_FUNC_trace_printk: 592 case BPF_FUNC_probe_write_user: 593 if (!full_mode) 594 continue; 595 /* fallthrough */ 596 default: 597 probe_helper_for_progtype(prog_type, supported_type, 598 define_prefix, id, ptype_name, 599 ifindex); 600 } 601 } 602 603 if (json_output) 604 jsonw_end_array(json_wtr); 605 else if (!define_prefix) 606 printf("\n"); 607 } 608 609 static void 610 probe_large_insn_limit(const char *define_prefix, __u32 ifindex) 611 { 612 bool res; 613 614 res = bpf_probe_large_insn_limit(ifindex); 615 print_bool_feature("have_large_insn_limit", 616 "Large program size limit", 617 "LARGE_INSN_LIMIT", 618 res, define_prefix); 619 } 620 621 static void 622 section_system_config(enum probe_component target, const char *define_prefix) 623 { 624 switch (target) { 625 case COMPONENT_KERNEL: 626 case COMPONENT_UNSPEC: 627 if (define_prefix) 628 break; 629 630 print_start_section("system_config", 631 "Scanning system configuration...", 632 NULL, /* define_comment never used here */ 633 NULL); /* define_prefix always NULL here */ 634 if (check_procfs()) { 635 probe_unprivileged_disabled(); 636 probe_jit_enable(); 637 probe_jit_harden(); 638 probe_jit_kallsyms(); 639 probe_jit_limit(); 640 } else { 641 p_info("/* procfs not mounted, skipping related probes */"); 642 } 643 probe_kernel_image_config(); 644 print_end_section(); 645 break; 646 default: 647 break; 648 } 649 } 650 651 static bool section_syscall_config(const char *define_prefix) 652 { 653 bool res; 654 655 print_start_section("syscall_config", 656 "Scanning system call availability...", 657 "/*** System call availability ***/", 658 define_prefix); 659 res = probe_bpf_syscall(define_prefix); 660 print_end_section(); 661 662 return res; 663 } 664 665 static void 666 section_program_types(bool *supported_types, const char *define_prefix, 667 __u32 ifindex) 668 { 669 unsigned int i; 670 671 print_start_section("program_types", 672 "Scanning eBPF program types...", 673 "/*** eBPF program types ***/", 674 define_prefix); 675 676 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) 677 probe_prog_type(i, supported_types, define_prefix, ifindex); 678 679 print_end_section(); 680 } 681 682 static void section_map_types(const char *define_prefix, __u32 ifindex) 683 { 684 unsigned int i; 685 686 print_start_section("map_types", 687 "Scanning eBPF map types...", 688 "/*** eBPF map types ***/", 689 define_prefix); 690 691 for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++) 692 probe_map_type(i, define_prefix, ifindex); 693 694 print_end_section(); 695 } 696 697 static void 698 section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex) 699 { 700 unsigned int i; 701 702 print_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], define_prefix, 724 ifindex); 725 726 print_end_section(); 727 } 728 729 static void section_misc(const char *define_prefix, __u32 ifindex) 730 { 731 print_start_section("misc", 732 "Scanning miscellaneous eBPF features...", 733 "/*** eBPF misc features ***/", 734 define_prefix); 735 probe_large_insn_limit(define_prefix, ifindex); 736 print_end_section(); 737 } 738 739 static int handle_perms(void) 740 { 741 cap_value_t cap_list[1] = { CAP_SYS_ADMIN }; 742 bool has_sys_admin_cap = false; 743 cap_flag_value_t val; 744 int res = -1; 745 cap_t caps; 746 747 caps = cap_get_proc(); 748 if (!caps) { 749 p_err("failed to get capabilities for process: %s", 750 strerror(errno)); 751 return -1; 752 } 753 754 if (cap_get_flag(caps, CAP_SYS_ADMIN, CAP_EFFECTIVE, &val)) { 755 p_err("bug: failed to retrieve CAP_SYS_ADMIN status"); 756 goto exit_free; 757 } 758 if (val == CAP_SET) 759 has_sys_admin_cap = true; 760 761 if (!run_as_unprivileged && !has_sys_admin_cap) { 762 p_err("full feature probing requires CAP_SYS_ADMIN, run as root or use 'unprivileged'"); 763 goto exit_free; 764 } 765 766 if ((run_as_unprivileged && !has_sys_admin_cap) || 767 (!run_as_unprivileged && has_sys_admin_cap)) { 768 /* We are all good, exit now */ 769 res = 0; 770 goto exit_free; 771 } 772 773 /* if (run_as_unprivileged && has_sys_admin_cap), drop CAP_SYS_ADMIN */ 774 775 if (cap_set_flag(caps, CAP_EFFECTIVE, ARRAY_SIZE(cap_list), cap_list, 776 CAP_CLEAR)) { 777 p_err("bug: failed to clear CAP_SYS_ADMIN from capabilities"); 778 goto exit_free; 779 } 780 781 if (cap_set_proc(caps)) { 782 p_err("failed to drop CAP_SYS_ADMIN: %s", strerror(errno)); 783 goto exit_free; 784 } 785 786 res = 0; 787 788 exit_free: 789 if (cap_free(caps) && !res) { 790 p_err("failed to clear storage object for capabilities: %s", 791 strerror(errno)); 792 res = -1; 793 } 794 795 return res; 796 } 797 798 static int do_probe(int argc, char **argv) 799 { 800 enum probe_component target = COMPONENT_UNSPEC; 801 const char *define_prefix = NULL; 802 bool supported_types[128] = {}; 803 __u32 ifindex = 0; 804 char *ifname; 805 806 set_max_rlimit(); 807 808 while (argc) { 809 if (is_prefix(*argv, "kernel")) { 810 if (target != COMPONENT_UNSPEC) { 811 p_err("component to probe already specified"); 812 return -1; 813 } 814 target = COMPONENT_KERNEL; 815 NEXT_ARG(); 816 } else if (is_prefix(*argv, "dev")) { 817 NEXT_ARG(); 818 819 if (target != COMPONENT_UNSPEC || ifindex) { 820 p_err("component to probe already specified"); 821 return -1; 822 } 823 if (!REQ_ARGS(1)) 824 return -1; 825 826 target = COMPONENT_DEVICE; 827 ifname = GET_ARG(); 828 ifindex = if_nametoindex(ifname); 829 if (!ifindex) { 830 p_err("unrecognized netdevice '%s': %s", ifname, 831 strerror(errno)); 832 return -1; 833 } 834 } else if (is_prefix(*argv, "full")) { 835 full_mode = true; 836 NEXT_ARG(); 837 } else if (is_prefix(*argv, "macros") && !define_prefix) { 838 define_prefix = ""; 839 NEXT_ARG(); 840 } else if (is_prefix(*argv, "prefix")) { 841 if (!define_prefix) { 842 p_err("'prefix' argument can only be use after 'macros'"); 843 return -1; 844 } 845 if (strcmp(define_prefix, "")) { 846 p_err("'prefix' already defined"); 847 return -1; 848 } 849 NEXT_ARG(); 850 851 if (!REQ_ARGS(1)) 852 return -1; 853 define_prefix = GET_ARG(); 854 } else if (is_prefix(*argv, "unprivileged")) { 855 run_as_unprivileged = true; 856 NEXT_ARG(); 857 } else { 858 p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?", 859 *argv); 860 return -1; 861 } 862 } 863 864 /* Full feature detection requires CAP_SYS_ADMIN privilege. 865 * Let's approximate, and warn if user is not root. 866 */ 867 if (handle_perms()) 868 return -1; 869 870 if (json_output) { 871 define_prefix = NULL; 872 jsonw_start_object(json_wtr); 873 } 874 875 section_system_config(target, define_prefix); 876 if (!section_syscall_config(define_prefix)) 877 /* bpf() syscall unavailable, don't probe other BPF features */ 878 goto exit_close_json; 879 section_program_types(supported_types, define_prefix, ifindex); 880 section_map_types(define_prefix, ifindex); 881 section_helpers(supported_types, define_prefix, ifindex); 882 section_misc(define_prefix, ifindex); 883 884 exit_close_json: 885 if (json_output) 886 /* End root object */ 887 jsonw_end_object(json_wtr); 888 889 return 0; 890 } 891 892 static int do_help(int argc, char **argv) 893 { 894 if (json_output) { 895 jsonw_null(json_wtr); 896 return 0; 897 } 898 899 fprintf(stderr, 900 "Usage: %s %s probe [COMPONENT] [full] [unprivileged] [macros [prefix PREFIX]]\n" 901 " %s %s help\n" 902 "\n" 903 " COMPONENT := { kernel | dev NAME }\n" 904 "", 905 bin_name, argv[-2], bin_name, argv[-2]); 906 907 return 0; 908 } 909 910 static const struct cmd cmds[] = { 911 { "probe", do_probe }, 912 { "help", do_help }, 913 { 0 } 914 }; 915 916 int do_feature(int argc, char **argv) 917 { 918 return cmd_select(cmds, argc, argv, do_help); 919 } 920