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