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