xref: /linux/tools/bpf/bpftool/feature.c (revision cf9bf714523dbbc97953be6de6ca14d57d4f8a21)
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