xref: /aosp_15_r20/external/bpftool/src/feature.c (revision 858ea5e570667251cdc31d3fe7b846b591105938)
1*858ea5e5SAndroid Build Coastguard Worker // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*858ea5e5SAndroid Build Coastguard Worker /* Copyright (c) 2019 Netronome Systems, Inc. */
3*858ea5e5SAndroid Build Coastguard Worker 
4*858ea5e5SAndroid Build Coastguard Worker #include <ctype.h>
5*858ea5e5SAndroid Build Coastguard Worker #include <errno.h>
6*858ea5e5SAndroid Build Coastguard Worker #include <fcntl.h>
7*858ea5e5SAndroid Build Coastguard Worker #include <string.h>
8*858ea5e5SAndroid Build Coastguard Worker #include <unistd.h>
9*858ea5e5SAndroid Build Coastguard Worker #include <net/if.h>
10*858ea5e5SAndroid Build Coastguard Worker #ifdef USE_LIBCAP
11*858ea5e5SAndroid Build Coastguard Worker #include <sys/capability.h>
12*858ea5e5SAndroid Build Coastguard Worker #endif
13*858ea5e5SAndroid Build Coastguard Worker #include <sys/utsname.h>
14*858ea5e5SAndroid Build Coastguard Worker #include <sys/vfs.h>
15*858ea5e5SAndroid Build Coastguard Worker 
16*858ea5e5SAndroid Build Coastguard Worker #include <linux/filter.h>
17*858ea5e5SAndroid Build Coastguard Worker #include <linux/limits.h>
18*858ea5e5SAndroid Build Coastguard Worker 
19*858ea5e5SAndroid Build Coastguard Worker #include <bpf/bpf.h>
20*858ea5e5SAndroid Build Coastguard Worker #include <bpf/libbpf.h>
21*858ea5e5SAndroid Build Coastguard Worker #include <zlib.h>
22*858ea5e5SAndroid Build Coastguard Worker 
23*858ea5e5SAndroid Build Coastguard Worker #include "main.h"
24*858ea5e5SAndroid Build Coastguard Worker 
25*858ea5e5SAndroid Build Coastguard Worker #ifndef PROC_SUPER_MAGIC
26*858ea5e5SAndroid Build Coastguard Worker # define PROC_SUPER_MAGIC	0x9fa0
27*858ea5e5SAndroid Build Coastguard Worker #endif
28*858ea5e5SAndroid Build Coastguard Worker 
29*858ea5e5SAndroid Build Coastguard Worker enum probe_component {
30*858ea5e5SAndroid Build Coastguard Worker 	COMPONENT_UNSPEC,
31*858ea5e5SAndroid Build Coastguard Worker 	COMPONENT_KERNEL,
32*858ea5e5SAndroid Build Coastguard Worker 	COMPONENT_DEVICE,
33*858ea5e5SAndroid Build Coastguard Worker };
34*858ea5e5SAndroid Build Coastguard Worker 
35*858ea5e5SAndroid Build Coastguard Worker #define BPF_HELPER_MAKE_ENTRY(name)	[BPF_FUNC_ ## name] = "bpf_" # name
36*858ea5e5SAndroid Build Coastguard Worker static const char * const helper_name[] = {
37*858ea5e5SAndroid Build Coastguard Worker 	__BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY)
38*858ea5e5SAndroid Build Coastguard Worker };
39*858ea5e5SAndroid Build Coastguard Worker 
40*858ea5e5SAndroid Build Coastguard Worker #undef BPF_HELPER_MAKE_ENTRY
41*858ea5e5SAndroid Build Coastguard Worker 
42*858ea5e5SAndroid Build Coastguard Worker static bool full_mode;
43*858ea5e5SAndroid Build Coastguard Worker #ifdef USE_LIBCAP
44*858ea5e5SAndroid Build Coastguard Worker static bool run_as_unprivileged;
45*858ea5e5SAndroid Build Coastguard Worker #endif
46*858ea5e5SAndroid Build Coastguard Worker 
47*858ea5e5SAndroid Build Coastguard Worker /* Miscellaneous utility functions */
48*858ea5e5SAndroid Build Coastguard Worker 
grep(const char * buffer,const char * pattern)49*858ea5e5SAndroid Build Coastguard Worker static bool grep(const char *buffer, const char *pattern)
50*858ea5e5SAndroid Build Coastguard Worker {
51*858ea5e5SAndroid Build Coastguard Worker 	return !!strstr(buffer, pattern);
52*858ea5e5SAndroid Build Coastguard Worker }
53*858ea5e5SAndroid Build Coastguard Worker 
check_procfs(void)54*858ea5e5SAndroid Build Coastguard Worker static bool check_procfs(void)
55*858ea5e5SAndroid Build Coastguard Worker {
56*858ea5e5SAndroid Build Coastguard Worker 	struct statfs st_fs;
57*858ea5e5SAndroid Build Coastguard Worker 
58*858ea5e5SAndroid Build Coastguard Worker 	if (statfs("/proc", &st_fs) < 0)
59*858ea5e5SAndroid Build Coastguard Worker 		return false;
60*858ea5e5SAndroid Build Coastguard Worker 	if ((unsigned long)st_fs.f_type != PROC_SUPER_MAGIC)
61*858ea5e5SAndroid Build Coastguard Worker 		return false;
62*858ea5e5SAndroid Build Coastguard Worker 
63*858ea5e5SAndroid Build Coastguard Worker 	return true;
64*858ea5e5SAndroid Build Coastguard Worker }
65*858ea5e5SAndroid Build Coastguard Worker 
uppercase(char * str,size_t len)66*858ea5e5SAndroid Build Coastguard Worker static void uppercase(char *str, size_t len)
67*858ea5e5SAndroid Build Coastguard Worker {
68*858ea5e5SAndroid Build Coastguard Worker 	size_t i;
69*858ea5e5SAndroid Build Coastguard Worker 
70*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < len && str[i] != '\0'; i++)
71*858ea5e5SAndroid Build Coastguard Worker 		str[i] = toupper(str[i]);
72*858ea5e5SAndroid Build Coastguard Worker }
73*858ea5e5SAndroid Build Coastguard Worker 
74*858ea5e5SAndroid Build Coastguard Worker /* Printing utility functions */
75*858ea5e5SAndroid Build Coastguard Worker 
76*858ea5e5SAndroid Build Coastguard Worker static void
print_bool_feature(const char * feat_name,const char * plain_name,const char * define_name,bool res,const char * define_prefix)77*858ea5e5SAndroid Build Coastguard Worker print_bool_feature(const char *feat_name, const char *plain_name,
78*858ea5e5SAndroid Build Coastguard Worker 		   const char *define_name, bool res, const char *define_prefix)
79*858ea5e5SAndroid Build Coastguard Worker {
80*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
81*858ea5e5SAndroid Build Coastguard Worker 		jsonw_bool_field(json_wtr, feat_name, res);
82*858ea5e5SAndroid Build Coastguard Worker 	else if (define_prefix)
83*858ea5e5SAndroid Build Coastguard Worker 		printf("#define %s%sHAVE_%s\n", define_prefix,
84*858ea5e5SAndroid Build Coastguard Worker 		       res ? "" : "NO_", define_name);
85*858ea5e5SAndroid Build Coastguard Worker 	else
86*858ea5e5SAndroid Build Coastguard Worker 		printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
87*858ea5e5SAndroid Build Coastguard Worker }
88*858ea5e5SAndroid Build Coastguard Worker 
print_kernel_option(const char * name,const char * value,const char * define_prefix)89*858ea5e5SAndroid Build Coastguard Worker static void print_kernel_option(const char *name, const char *value,
90*858ea5e5SAndroid Build Coastguard Worker 				const char *define_prefix)
91*858ea5e5SAndroid Build Coastguard Worker {
92*858ea5e5SAndroid Build Coastguard Worker 	char *endptr;
93*858ea5e5SAndroid Build Coastguard Worker 	int res;
94*858ea5e5SAndroid Build Coastguard Worker 
95*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
96*858ea5e5SAndroid Build Coastguard Worker 		if (!value) {
97*858ea5e5SAndroid Build Coastguard Worker 			jsonw_null_field(json_wtr, name);
98*858ea5e5SAndroid Build Coastguard Worker 			return;
99*858ea5e5SAndroid Build Coastguard Worker 		}
100*858ea5e5SAndroid Build Coastguard Worker 		errno = 0;
101*858ea5e5SAndroid Build Coastguard Worker 		res = strtol(value, &endptr, 0);
102*858ea5e5SAndroid Build Coastguard Worker 		if (!errno && *endptr == '\n')
103*858ea5e5SAndroid Build Coastguard Worker 			jsonw_int_field(json_wtr, name, res);
104*858ea5e5SAndroid Build Coastguard Worker 		else
105*858ea5e5SAndroid Build Coastguard Worker 			jsonw_string_field(json_wtr, name, value);
106*858ea5e5SAndroid Build Coastguard Worker 	} else if (define_prefix) {
107*858ea5e5SAndroid Build Coastguard Worker 		if (value)
108*858ea5e5SAndroid Build Coastguard Worker 			printf("#define %s%s %s\n", define_prefix,
109*858ea5e5SAndroid Build Coastguard Worker 			       name, value);
110*858ea5e5SAndroid Build Coastguard Worker 		else
111*858ea5e5SAndroid Build Coastguard Worker 			printf("/* %s%s is not set */\n", define_prefix, name);
112*858ea5e5SAndroid Build Coastguard Worker 	} else {
113*858ea5e5SAndroid Build Coastguard Worker 		if (value)
114*858ea5e5SAndroid Build Coastguard Worker 			printf("%s is set to %s\n", name, value);
115*858ea5e5SAndroid Build Coastguard Worker 		else
116*858ea5e5SAndroid Build Coastguard Worker 			printf("%s is not set\n", name);
117*858ea5e5SAndroid Build Coastguard Worker 	}
118*858ea5e5SAndroid Build Coastguard Worker }
119*858ea5e5SAndroid Build Coastguard Worker 
120*858ea5e5SAndroid Build Coastguard Worker static void
print_start_section(const char * json_title,const char * plain_title,const char * define_comment,const char * define_prefix)121*858ea5e5SAndroid Build Coastguard Worker print_start_section(const char *json_title, const char *plain_title,
122*858ea5e5SAndroid Build Coastguard Worker 		    const char *define_comment, const char *define_prefix)
123*858ea5e5SAndroid Build Coastguard Worker {
124*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
125*858ea5e5SAndroid Build Coastguard Worker 		jsonw_name(json_wtr, json_title);
126*858ea5e5SAndroid Build Coastguard Worker 		jsonw_start_object(json_wtr);
127*858ea5e5SAndroid Build Coastguard Worker 	} else if (define_prefix) {
128*858ea5e5SAndroid Build Coastguard Worker 		printf("%s\n", define_comment);
129*858ea5e5SAndroid Build Coastguard Worker 	} else {
130*858ea5e5SAndroid Build Coastguard Worker 		printf("%s\n", plain_title);
131*858ea5e5SAndroid Build Coastguard Worker 	}
132*858ea5e5SAndroid Build Coastguard Worker }
133*858ea5e5SAndroid Build Coastguard Worker 
print_end_section(void)134*858ea5e5SAndroid Build Coastguard Worker static void print_end_section(void)
135*858ea5e5SAndroid Build Coastguard Worker {
136*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
137*858ea5e5SAndroid Build Coastguard Worker 		jsonw_end_object(json_wtr);
138*858ea5e5SAndroid Build Coastguard Worker 	else
139*858ea5e5SAndroid Build Coastguard Worker 		printf("\n");
140*858ea5e5SAndroid Build Coastguard Worker }
141*858ea5e5SAndroid Build Coastguard Worker 
142*858ea5e5SAndroid Build Coastguard Worker /* Probing functions */
143*858ea5e5SAndroid Build Coastguard Worker 
get_vendor_id(int ifindex)144*858ea5e5SAndroid Build Coastguard Worker static int get_vendor_id(int ifindex)
145*858ea5e5SAndroid Build Coastguard Worker {
146*858ea5e5SAndroid Build Coastguard Worker 	char ifname[IF_NAMESIZE], path[64], buf[8];
147*858ea5e5SAndroid Build Coastguard Worker 	ssize_t len;
148*858ea5e5SAndroid Build Coastguard Worker 	int fd;
149*858ea5e5SAndroid Build Coastguard Worker 
150*858ea5e5SAndroid Build Coastguard Worker 	if (!if_indextoname(ifindex, ifname))
151*858ea5e5SAndroid Build Coastguard Worker 		return -1;
152*858ea5e5SAndroid Build Coastguard Worker 
153*858ea5e5SAndroid Build Coastguard Worker 	snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname);
154*858ea5e5SAndroid Build Coastguard Worker 
155*858ea5e5SAndroid Build Coastguard Worker 	fd = open(path, O_RDONLY | O_CLOEXEC);
156*858ea5e5SAndroid Build Coastguard Worker 	if (fd < 0)
157*858ea5e5SAndroid Build Coastguard Worker 		return -1;
158*858ea5e5SAndroid Build Coastguard Worker 
159*858ea5e5SAndroid Build Coastguard Worker 	len = read(fd, buf, sizeof(buf));
160*858ea5e5SAndroid Build Coastguard Worker 	close(fd);
161*858ea5e5SAndroid Build Coastguard Worker 	if (len < 0)
162*858ea5e5SAndroid Build Coastguard Worker 		return -1;
163*858ea5e5SAndroid Build Coastguard Worker 	if (len >= (ssize_t)sizeof(buf))
164*858ea5e5SAndroid Build Coastguard Worker 		return -1;
165*858ea5e5SAndroid Build Coastguard Worker 	buf[len] = '\0';
166*858ea5e5SAndroid Build Coastguard Worker 
167*858ea5e5SAndroid Build Coastguard Worker 	return strtol(buf, NULL, 0);
168*858ea5e5SAndroid Build Coastguard Worker }
169*858ea5e5SAndroid Build Coastguard Worker 
read_procfs(const char * path)170*858ea5e5SAndroid Build Coastguard Worker static long read_procfs(const char *path)
171*858ea5e5SAndroid Build Coastguard Worker {
172*858ea5e5SAndroid Build Coastguard Worker 	char *endptr, *line = NULL;
173*858ea5e5SAndroid Build Coastguard Worker 	size_t len = 0;
174*858ea5e5SAndroid Build Coastguard Worker 	FILE *fd;
175*858ea5e5SAndroid Build Coastguard Worker 	long res;
176*858ea5e5SAndroid Build Coastguard Worker 
177*858ea5e5SAndroid Build Coastguard Worker 	fd = fopen(path, "r");
178*858ea5e5SAndroid Build Coastguard Worker 	if (!fd)
179*858ea5e5SAndroid Build Coastguard Worker 		return -1;
180*858ea5e5SAndroid Build Coastguard Worker 
181*858ea5e5SAndroid Build Coastguard Worker 	res = getline(&line, &len, fd);
182*858ea5e5SAndroid Build Coastguard Worker 	fclose(fd);
183*858ea5e5SAndroid Build Coastguard Worker 	if (res < 0)
184*858ea5e5SAndroid Build Coastguard Worker 		return -1;
185*858ea5e5SAndroid Build Coastguard Worker 
186*858ea5e5SAndroid Build Coastguard Worker 	errno = 0;
187*858ea5e5SAndroid Build Coastguard Worker 	res = strtol(line, &endptr, 10);
188*858ea5e5SAndroid Build Coastguard Worker 	if (errno || *line == '\0' || *endptr != '\n')
189*858ea5e5SAndroid Build Coastguard Worker 		res = -1;
190*858ea5e5SAndroid Build Coastguard Worker 	free(line);
191*858ea5e5SAndroid Build Coastguard Worker 
192*858ea5e5SAndroid Build Coastguard Worker 	return res;
193*858ea5e5SAndroid Build Coastguard Worker }
194*858ea5e5SAndroid Build Coastguard Worker 
probe_unprivileged_disabled(void)195*858ea5e5SAndroid Build Coastguard Worker static void probe_unprivileged_disabled(void)
196*858ea5e5SAndroid Build Coastguard Worker {
197*858ea5e5SAndroid Build Coastguard Worker 	long res;
198*858ea5e5SAndroid Build Coastguard Worker 
199*858ea5e5SAndroid Build Coastguard Worker 	/* No support for C-style ouptut */
200*858ea5e5SAndroid Build Coastguard Worker 
201*858ea5e5SAndroid Build Coastguard Worker 	res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
202*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
203*858ea5e5SAndroid Build Coastguard Worker 		jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
204*858ea5e5SAndroid Build Coastguard Worker 	} else {
205*858ea5e5SAndroid Build Coastguard Worker 		switch (res) {
206*858ea5e5SAndroid Build Coastguard Worker 		case 0:
207*858ea5e5SAndroid Build Coastguard Worker 			printf("bpf() syscall for unprivileged users is enabled\n");
208*858ea5e5SAndroid Build Coastguard Worker 			break;
209*858ea5e5SAndroid Build Coastguard Worker 		case 1:
210*858ea5e5SAndroid Build Coastguard Worker 			printf("bpf() syscall restricted to privileged users (without recovery)\n");
211*858ea5e5SAndroid Build Coastguard Worker 			break;
212*858ea5e5SAndroid Build Coastguard Worker 		case 2:
213*858ea5e5SAndroid Build Coastguard Worker 			printf("bpf() syscall restricted to privileged users (admin can change)\n");
214*858ea5e5SAndroid Build Coastguard Worker 			break;
215*858ea5e5SAndroid Build Coastguard Worker 		case -1:
216*858ea5e5SAndroid Build Coastguard Worker 			printf("Unable to retrieve required privileges for bpf() syscall\n");
217*858ea5e5SAndroid Build Coastguard Worker 			break;
218*858ea5e5SAndroid Build Coastguard Worker 		default:
219*858ea5e5SAndroid Build Coastguard Worker 			printf("bpf() syscall restriction has unknown value %ld\n", res);
220*858ea5e5SAndroid Build Coastguard Worker 		}
221*858ea5e5SAndroid Build Coastguard Worker 	}
222*858ea5e5SAndroid Build Coastguard Worker }
223*858ea5e5SAndroid Build Coastguard Worker 
probe_jit_enable(void)224*858ea5e5SAndroid Build Coastguard Worker static void probe_jit_enable(void)
225*858ea5e5SAndroid Build Coastguard Worker {
226*858ea5e5SAndroid Build Coastguard Worker 	long res;
227*858ea5e5SAndroid Build Coastguard Worker 
228*858ea5e5SAndroid Build Coastguard Worker 	/* No support for C-style ouptut */
229*858ea5e5SAndroid Build Coastguard Worker 
230*858ea5e5SAndroid Build Coastguard Worker 	res = read_procfs("/proc/sys/net/core/bpf_jit_enable");
231*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
232*858ea5e5SAndroid Build Coastguard Worker 		jsonw_int_field(json_wtr, "bpf_jit_enable", res);
233*858ea5e5SAndroid Build Coastguard Worker 	} else {
234*858ea5e5SAndroid Build Coastguard Worker 		switch (res) {
235*858ea5e5SAndroid Build Coastguard Worker 		case 0:
236*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT compiler is disabled\n");
237*858ea5e5SAndroid Build Coastguard Worker 			break;
238*858ea5e5SAndroid Build Coastguard Worker 		case 1:
239*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT compiler is enabled\n");
240*858ea5e5SAndroid Build Coastguard Worker 			break;
241*858ea5e5SAndroid Build Coastguard Worker 		case 2:
242*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT compiler is enabled with debugging traces in kernel logs\n");
243*858ea5e5SAndroid Build Coastguard Worker 			break;
244*858ea5e5SAndroid Build Coastguard Worker 		case -1:
245*858ea5e5SAndroid Build Coastguard Worker 			printf("Unable to retrieve JIT-compiler status\n");
246*858ea5e5SAndroid Build Coastguard Worker 			break;
247*858ea5e5SAndroid Build Coastguard Worker 		default:
248*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT-compiler status has unknown value %ld\n",
249*858ea5e5SAndroid Build Coastguard Worker 			       res);
250*858ea5e5SAndroid Build Coastguard Worker 		}
251*858ea5e5SAndroid Build Coastguard Worker 	}
252*858ea5e5SAndroid Build Coastguard Worker }
253*858ea5e5SAndroid Build Coastguard Worker 
probe_jit_harden(void)254*858ea5e5SAndroid Build Coastguard Worker static void probe_jit_harden(void)
255*858ea5e5SAndroid Build Coastguard Worker {
256*858ea5e5SAndroid Build Coastguard Worker 	long res;
257*858ea5e5SAndroid Build Coastguard Worker 
258*858ea5e5SAndroid Build Coastguard Worker 	/* No support for C-style ouptut */
259*858ea5e5SAndroid Build Coastguard Worker 
260*858ea5e5SAndroid Build Coastguard Worker 	res = read_procfs("/proc/sys/net/core/bpf_jit_harden");
261*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
262*858ea5e5SAndroid Build Coastguard Worker 		jsonw_int_field(json_wtr, "bpf_jit_harden", res);
263*858ea5e5SAndroid Build Coastguard Worker 	} else {
264*858ea5e5SAndroid Build Coastguard Worker 		switch (res) {
265*858ea5e5SAndroid Build Coastguard Worker 		case 0:
266*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT compiler hardening is disabled\n");
267*858ea5e5SAndroid Build Coastguard Worker 			break;
268*858ea5e5SAndroid Build Coastguard Worker 		case 1:
269*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT compiler hardening is enabled for unprivileged users\n");
270*858ea5e5SAndroid Build Coastguard Worker 			break;
271*858ea5e5SAndroid Build Coastguard Worker 		case 2:
272*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT compiler hardening is enabled for all users\n");
273*858ea5e5SAndroid Build Coastguard Worker 			break;
274*858ea5e5SAndroid Build Coastguard Worker 		case -1:
275*858ea5e5SAndroid Build Coastguard Worker 			printf("Unable to retrieve JIT hardening status\n");
276*858ea5e5SAndroid Build Coastguard Worker 			break;
277*858ea5e5SAndroid Build Coastguard Worker 		default:
278*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT hardening status has unknown value %ld\n",
279*858ea5e5SAndroid Build Coastguard Worker 			       res);
280*858ea5e5SAndroid Build Coastguard Worker 		}
281*858ea5e5SAndroid Build Coastguard Worker 	}
282*858ea5e5SAndroid Build Coastguard Worker }
283*858ea5e5SAndroid Build Coastguard Worker 
probe_jit_kallsyms(void)284*858ea5e5SAndroid Build Coastguard Worker static void probe_jit_kallsyms(void)
285*858ea5e5SAndroid Build Coastguard Worker {
286*858ea5e5SAndroid Build Coastguard Worker 	long res;
287*858ea5e5SAndroid Build Coastguard Worker 
288*858ea5e5SAndroid Build Coastguard Worker 	/* No support for C-style ouptut */
289*858ea5e5SAndroid Build Coastguard Worker 
290*858ea5e5SAndroid Build Coastguard Worker 	res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms");
291*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
292*858ea5e5SAndroid Build Coastguard Worker 		jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res);
293*858ea5e5SAndroid Build Coastguard Worker 	} else {
294*858ea5e5SAndroid Build Coastguard Worker 		switch (res) {
295*858ea5e5SAndroid Build Coastguard Worker 		case 0:
296*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT compiler kallsyms exports are disabled\n");
297*858ea5e5SAndroid Build Coastguard Worker 			break;
298*858ea5e5SAndroid Build Coastguard Worker 		case 1:
299*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT compiler kallsyms exports are enabled for root\n");
300*858ea5e5SAndroid Build Coastguard Worker 			break;
301*858ea5e5SAndroid Build Coastguard Worker 		case -1:
302*858ea5e5SAndroid Build Coastguard Worker 			printf("Unable to retrieve JIT kallsyms export status\n");
303*858ea5e5SAndroid Build Coastguard Worker 			break;
304*858ea5e5SAndroid Build Coastguard Worker 		default:
305*858ea5e5SAndroid Build Coastguard Worker 			printf("JIT kallsyms exports status has unknown value %ld\n", res);
306*858ea5e5SAndroid Build Coastguard Worker 		}
307*858ea5e5SAndroid Build Coastguard Worker 	}
308*858ea5e5SAndroid Build Coastguard Worker }
309*858ea5e5SAndroid Build Coastguard Worker 
probe_jit_limit(void)310*858ea5e5SAndroid Build Coastguard Worker static void probe_jit_limit(void)
311*858ea5e5SAndroid Build Coastguard Worker {
312*858ea5e5SAndroid Build Coastguard Worker 	long res;
313*858ea5e5SAndroid Build Coastguard Worker 
314*858ea5e5SAndroid Build Coastguard Worker 	/* No support for C-style ouptut */
315*858ea5e5SAndroid Build Coastguard Worker 
316*858ea5e5SAndroid Build Coastguard Worker 	res = read_procfs("/proc/sys/net/core/bpf_jit_limit");
317*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
318*858ea5e5SAndroid Build Coastguard Worker 		jsonw_int_field(json_wtr, "bpf_jit_limit", res);
319*858ea5e5SAndroid Build Coastguard Worker 	} else {
320*858ea5e5SAndroid Build Coastguard Worker 		switch (res) {
321*858ea5e5SAndroid Build Coastguard Worker 		case -1:
322*858ea5e5SAndroid Build Coastguard Worker 			printf("Unable to retrieve global memory limit for JIT compiler for unprivileged users\n");
323*858ea5e5SAndroid Build Coastguard Worker 			break;
324*858ea5e5SAndroid Build Coastguard Worker 		default:
325*858ea5e5SAndroid Build Coastguard Worker 			printf("Global memory limit for JIT compiler for unprivileged users is %ld bytes\n", res);
326*858ea5e5SAndroid Build Coastguard Worker 		}
327*858ea5e5SAndroid Build Coastguard Worker 	}
328*858ea5e5SAndroid Build Coastguard Worker }
329*858ea5e5SAndroid Build Coastguard Worker 
read_next_kernel_config_option(gzFile file,char * buf,size_t n,char ** value)330*858ea5e5SAndroid Build Coastguard Worker static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n,
331*858ea5e5SAndroid Build Coastguard Worker 					   char **value)
332*858ea5e5SAndroid Build Coastguard Worker {
333*858ea5e5SAndroid Build Coastguard Worker 	char *sep;
334*858ea5e5SAndroid Build Coastguard Worker 
335*858ea5e5SAndroid Build Coastguard Worker 	while (gzgets(file, buf, n)) {
336*858ea5e5SAndroid Build Coastguard Worker 		if (strncmp(buf, "CONFIG_", 7))
337*858ea5e5SAndroid Build Coastguard Worker 			continue;
338*858ea5e5SAndroid Build Coastguard Worker 
339*858ea5e5SAndroid Build Coastguard Worker 		sep = strchr(buf, '=');
340*858ea5e5SAndroid Build Coastguard Worker 		if (!sep)
341*858ea5e5SAndroid Build Coastguard Worker 			continue;
342*858ea5e5SAndroid Build Coastguard Worker 
343*858ea5e5SAndroid Build Coastguard Worker 		/* Trim ending '\n' */
344*858ea5e5SAndroid Build Coastguard Worker 		buf[strlen(buf) - 1] = '\0';
345*858ea5e5SAndroid Build Coastguard Worker 
346*858ea5e5SAndroid Build Coastguard Worker 		/* Split on '=' and ensure that a value is present. */
347*858ea5e5SAndroid Build Coastguard Worker 		*sep = '\0';
348*858ea5e5SAndroid Build Coastguard Worker 		if (!sep[1])
349*858ea5e5SAndroid Build Coastguard Worker 			continue;
350*858ea5e5SAndroid Build Coastguard Worker 
351*858ea5e5SAndroid Build Coastguard Worker 		*value = sep + 1;
352*858ea5e5SAndroid Build Coastguard Worker 		return true;
353*858ea5e5SAndroid Build Coastguard Worker 	}
354*858ea5e5SAndroid Build Coastguard Worker 
355*858ea5e5SAndroid Build Coastguard Worker 	return false;
356*858ea5e5SAndroid Build Coastguard Worker }
357*858ea5e5SAndroid Build Coastguard Worker 
probe_kernel_image_config(const char * define_prefix)358*858ea5e5SAndroid Build Coastguard Worker static void probe_kernel_image_config(const char *define_prefix)
359*858ea5e5SAndroid Build Coastguard Worker {
360*858ea5e5SAndroid Build Coastguard Worker 	static const struct {
361*858ea5e5SAndroid Build Coastguard Worker 		const char * const name;
362*858ea5e5SAndroid Build Coastguard Worker 		bool macro_dump;
363*858ea5e5SAndroid Build Coastguard Worker 	} options[] = {
364*858ea5e5SAndroid Build Coastguard Worker 		/* Enable BPF */
365*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_BPF", },
366*858ea5e5SAndroid Build Coastguard Worker 		/* Enable bpf() syscall */
367*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_BPF_SYSCALL", },
368*858ea5e5SAndroid Build Coastguard Worker 		/* Does selected architecture support eBPF JIT compiler */
369*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_HAVE_EBPF_JIT", },
370*858ea5e5SAndroid Build Coastguard Worker 		/* Compile eBPF JIT compiler */
371*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_BPF_JIT", },
372*858ea5e5SAndroid Build Coastguard Worker 		/* Avoid compiling eBPF interpreter (use JIT only) */
373*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_BPF_JIT_ALWAYS_ON", },
374*858ea5e5SAndroid Build Coastguard Worker 		/* Kernel BTF debug information available */
375*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_DEBUG_INFO_BTF", },
376*858ea5e5SAndroid Build Coastguard Worker 		/* Kernel module BTF debug information available */
377*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_DEBUG_INFO_BTF_MODULES", },
378*858ea5e5SAndroid Build Coastguard Worker 
379*858ea5e5SAndroid Build Coastguard Worker 		/* cgroups */
380*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_CGROUPS", },
381*858ea5e5SAndroid Build Coastguard Worker 		/* BPF programs attached to cgroups */
382*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_CGROUP_BPF", },
383*858ea5e5SAndroid Build Coastguard Worker 		/* bpf_get_cgroup_classid() helper */
384*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_CGROUP_NET_CLASSID", },
385*858ea5e5SAndroid Build Coastguard Worker 		/* bpf_skb_{,ancestor_}cgroup_id() helpers */
386*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_SOCK_CGROUP_DATA", },
387*858ea5e5SAndroid Build Coastguard Worker 
388*858ea5e5SAndroid Build Coastguard Worker 		/* Tracing: attach BPF to kprobes, tracepoints, etc. */
389*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_BPF_EVENTS", },
390*858ea5e5SAndroid Build Coastguard Worker 		/* Kprobes */
391*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_KPROBE_EVENTS", },
392*858ea5e5SAndroid Build Coastguard Worker 		/* Uprobes */
393*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_UPROBE_EVENTS", },
394*858ea5e5SAndroid Build Coastguard Worker 		/* Tracepoints */
395*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_TRACING", },
396*858ea5e5SAndroid Build Coastguard Worker 		/* Syscall tracepoints */
397*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_FTRACE_SYSCALLS", },
398*858ea5e5SAndroid Build Coastguard Worker 		/* bpf_override_return() helper support for selected arch */
399*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_FUNCTION_ERROR_INJECTION", },
400*858ea5e5SAndroid Build Coastguard Worker 		/* bpf_override_return() helper */
401*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_BPF_KPROBE_OVERRIDE", },
402*858ea5e5SAndroid Build Coastguard Worker 
403*858ea5e5SAndroid Build Coastguard Worker 		/* Network */
404*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_NET", },
405*858ea5e5SAndroid Build Coastguard Worker 		/* AF_XDP sockets */
406*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_XDP_SOCKETS", },
407*858ea5e5SAndroid Build Coastguard Worker 		/* BPF_PROG_TYPE_LWT_* and related helpers */
408*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_LWTUNNEL_BPF", },
409*858ea5e5SAndroid Build Coastguard Worker 		/* BPF_PROG_TYPE_SCHED_ACT, TC (traffic control) actions */
410*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_NET_ACT_BPF", },
411*858ea5e5SAndroid Build Coastguard Worker 		/* BPF_PROG_TYPE_SCHED_CLS, TC filters */
412*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_NET_CLS_BPF", },
413*858ea5e5SAndroid Build Coastguard Worker 		/* TC clsact qdisc */
414*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_NET_CLS_ACT", },
415*858ea5e5SAndroid Build Coastguard Worker 		/* Ingress filtering with TC */
416*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_NET_SCH_INGRESS", },
417*858ea5e5SAndroid Build Coastguard Worker 		/* bpf_skb_get_xfrm_state() helper */
418*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_XFRM", },
419*858ea5e5SAndroid Build Coastguard Worker 		/* bpf_get_route_realm() helper */
420*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_IP_ROUTE_CLASSID", },
421*858ea5e5SAndroid Build Coastguard Worker 		/* BPF_PROG_TYPE_LWT_SEG6_LOCAL and related helpers */
422*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_IPV6_SEG6_BPF", },
423*858ea5e5SAndroid Build Coastguard Worker 		/* BPF_PROG_TYPE_LIRC_MODE2 and related helpers */
424*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_BPF_LIRC_MODE2", },
425*858ea5e5SAndroid Build Coastguard Worker 		/* BPF stream parser and BPF socket maps */
426*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_BPF_STREAM_PARSER", },
427*858ea5e5SAndroid Build Coastguard Worker 		/* xt_bpf module for passing BPF programs to netfilter  */
428*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_NETFILTER_XT_MATCH_BPF", },
429*858ea5e5SAndroid Build Coastguard Worker 
430*858ea5e5SAndroid Build Coastguard Worker 		/* test_bpf module for BPF tests */
431*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_TEST_BPF", },
432*858ea5e5SAndroid Build Coastguard Worker 
433*858ea5e5SAndroid Build Coastguard Worker 		/* Misc configs useful in BPF C programs */
434*858ea5e5SAndroid Build Coastguard Worker 		/* jiffies <-> sec conversion for bpf_jiffies64() helper */
435*858ea5e5SAndroid Build Coastguard Worker 		{ "CONFIG_HZ", true, }
436*858ea5e5SAndroid Build Coastguard Worker 	};
437*858ea5e5SAndroid Build Coastguard Worker 	char *values[ARRAY_SIZE(options)] = { };
438*858ea5e5SAndroid Build Coastguard Worker 	struct utsname utsn;
439*858ea5e5SAndroid Build Coastguard Worker 	char path[PATH_MAX];
440*858ea5e5SAndroid Build Coastguard Worker 	gzFile file = NULL;
441*858ea5e5SAndroid Build Coastguard Worker 	char buf[4096];
442*858ea5e5SAndroid Build Coastguard Worker 	char *value;
443*858ea5e5SAndroid Build Coastguard Worker 	size_t i;
444*858ea5e5SAndroid Build Coastguard Worker 
445*858ea5e5SAndroid Build Coastguard Worker 	if (!uname(&utsn)) {
446*858ea5e5SAndroid Build Coastguard Worker 		snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);
447*858ea5e5SAndroid Build Coastguard Worker 
448*858ea5e5SAndroid Build Coastguard Worker 		/* gzopen also accepts uncompressed files. */
449*858ea5e5SAndroid Build Coastguard Worker 		file = gzopen(path, "r");
450*858ea5e5SAndroid Build Coastguard Worker 	}
451*858ea5e5SAndroid Build Coastguard Worker 
452*858ea5e5SAndroid Build Coastguard Worker 	if (!file) {
453*858ea5e5SAndroid Build Coastguard Worker 		/* Some distributions build with CONFIG_IKCONFIG=y and put the
454*858ea5e5SAndroid Build Coastguard Worker 		 * config file at /proc/config.gz.
455*858ea5e5SAndroid Build Coastguard Worker 		 */
456*858ea5e5SAndroid Build Coastguard Worker 		file = gzopen("/proc/config.gz", "r");
457*858ea5e5SAndroid Build Coastguard Worker 	}
458*858ea5e5SAndroid Build Coastguard Worker 	if (!file) {
459*858ea5e5SAndroid Build Coastguard Worker 		p_info("skipping kernel config, can't open file: %s",
460*858ea5e5SAndroid Build Coastguard Worker 		       strerror(errno));
461*858ea5e5SAndroid Build Coastguard Worker 		goto end_parse;
462*858ea5e5SAndroid Build Coastguard Worker 	}
463*858ea5e5SAndroid Build Coastguard Worker 	/* Sanity checks */
464*858ea5e5SAndroid Build Coastguard Worker 	if (!gzgets(file, buf, sizeof(buf)) ||
465*858ea5e5SAndroid Build Coastguard Worker 	    !gzgets(file, buf, sizeof(buf))) {
466*858ea5e5SAndroid Build Coastguard Worker 		p_info("skipping kernel config, can't read from file: %s",
467*858ea5e5SAndroid Build Coastguard Worker 		       strerror(errno));
468*858ea5e5SAndroid Build Coastguard Worker 		goto end_parse;
469*858ea5e5SAndroid Build Coastguard Worker 	}
470*858ea5e5SAndroid Build Coastguard Worker 	if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
471*858ea5e5SAndroid Build Coastguard Worker 		p_info("skipping kernel config, can't find correct file");
472*858ea5e5SAndroid Build Coastguard Worker 		goto end_parse;
473*858ea5e5SAndroid Build Coastguard Worker 	}
474*858ea5e5SAndroid Build Coastguard Worker 
475*858ea5e5SAndroid Build Coastguard Worker 	while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) {
476*858ea5e5SAndroid Build Coastguard Worker 		for (i = 0; i < ARRAY_SIZE(options); i++) {
477*858ea5e5SAndroid Build Coastguard Worker 			if ((define_prefix && !options[i].macro_dump) ||
478*858ea5e5SAndroid Build Coastguard Worker 			    values[i] || strcmp(buf, options[i].name))
479*858ea5e5SAndroid Build Coastguard Worker 				continue;
480*858ea5e5SAndroid Build Coastguard Worker 
481*858ea5e5SAndroid Build Coastguard Worker 			values[i] = strdup(value);
482*858ea5e5SAndroid Build Coastguard Worker 		}
483*858ea5e5SAndroid Build Coastguard Worker 	}
484*858ea5e5SAndroid Build Coastguard Worker 
485*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(options); i++) {
486*858ea5e5SAndroid Build Coastguard Worker 		if (define_prefix && !options[i].macro_dump)
487*858ea5e5SAndroid Build Coastguard Worker 			continue;
488*858ea5e5SAndroid Build Coastguard Worker 		print_kernel_option(options[i].name, values[i], define_prefix);
489*858ea5e5SAndroid Build Coastguard Worker 		free(values[i]);
490*858ea5e5SAndroid Build Coastguard Worker 	}
491*858ea5e5SAndroid Build Coastguard Worker 
492*858ea5e5SAndroid Build Coastguard Worker end_parse:
493*858ea5e5SAndroid Build Coastguard Worker 	if (file)
494*858ea5e5SAndroid Build Coastguard Worker 		gzclose(file);
495*858ea5e5SAndroid Build Coastguard Worker }
496*858ea5e5SAndroid Build Coastguard Worker 
probe_bpf_syscall(const char * define_prefix)497*858ea5e5SAndroid Build Coastguard Worker static bool probe_bpf_syscall(const char *define_prefix)
498*858ea5e5SAndroid Build Coastguard Worker {
499*858ea5e5SAndroid Build Coastguard Worker 	bool res;
500*858ea5e5SAndroid Build Coastguard Worker 
501*858ea5e5SAndroid Build Coastguard Worker 	bpf_prog_load(BPF_PROG_TYPE_UNSPEC, NULL, NULL, NULL, 0, NULL);
502*858ea5e5SAndroid Build Coastguard Worker 	res = (errno != ENOSYS);
503*858ea5e5SAndroid Build Coastguard Worker 
504*858ea5e5SAndroid Build Coastguard Worker 	print_bool_feature("have_bpf_syscall",
505*858ea5e5SAndroid Build Coastguard Worker 			   "bpf() syscall",
506*858ea5e5SAndroid Build Coastguard Worker 			   "BPF_SYSCALL",
507*858ea5e5SAndroid Build Coastguard Worker 			   res, define_prefix);
508*858ea5e5SAndroid Build Coastguard Worker 
509*858ea5e5SAndroid Build Coastguard Worker 	return res;
510*858ea5e5SAndroid Build Coastguard Worker }
511*858ea5e5SAndroid Build Coastguard Worker 
512*858ea5e5SAndroid Build Coastguard Worker static bool
probe_prog_load_ifindex(enum bpf_prog_type prog_type,const struct bpf_insn * insns,size_t insns_cnt,char * log_buf,size_t log_buf_sz,__u32 ifindex)513*858ea5e5SAndroid Build Coastguard Worker probe_prog_load_ifindex(enum bpf_prog_type prog_type,
514*858ea5e5SAndroid Build Coastguard Worker 			const struct bpf_insn *insns, size_t insns_cnt,
515*858ea5e5SAndroid Build Coastguard Worker 			char *log_buf, size_t log_buf_sz,
516*858ea5e5SAndroid Build Coastguard Worker 			__u32 ifindex)
517*858ea5e5SAndroid Build Coastguard Worker {
518*858ea5e5SAndroid Build Coastguard Worker 	LIBBPF_OPTS(bpf_prog_load_opts, opts,
519*858ea5e5SAndroid Build Coastguard Worker 		    .log_buf = log_buf,
520*858ea5e5SAndroid Build Coastguard Worker 		    .log_size = log_buf_sz,
521*858ea5e5SAndroid Build Coastguard Worker 		    .log_level = log_buf ? 1 : 0,
522*858ea5e5SAndroid Build Coastguard Worker 		    .prog_ifindex = ifindex,
523*858ea5e5SAndroid Build Coastguard Worker 		   );
524*858ea5e5SAndroid Build Coastguard Worker 	int fd;
525*858ea5e5SAndroid Build Coastguard Worker 
526*858ea5e5SAndroid Build Coastguard Worker 	errno = 0;
527*858ea5e5SAndroid Build Coastguard Worker 	fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insns_cnt, &opts);
528*858ea5e5SAndroid Build Coastguard Worker 	if (fd >= 0)
529*858ea5e5SAndroid Build Coastguard Worker 		close(fd);
530*858ea5e5SAndroid Build Coastguard Worker 
531*858ea5e5SAndroid Build Coastguard Worker 	return fd >= 0 && errno != EINVAL && errno != EOPNOTSUPP;
532*858ea5e5SAndroid Build Coastguard Worker }
533*858ea5e5SAndroid Build Coastguard Worker 
probe_prog_type_ifindex(enum bpf_prog_type prog_type,__u32 ifindex)534*858ea5e5SAndroid Build Coastguard Worker static bool probe_prog_type_ifindex(enum bpf_prog_type prog_type, __u32 ifindex)
535*858ea5e5SAndroid Build Coastguard Worker {
536*858ea5e5SAndroid Build Coastguard Worker 	/* nfp returns -EINVAL on exit(0) with TC offload */
537*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_insn insns[2] = {
538*858ea5e5SAndroid Build Coastguard Worker 		BPF_MOV64_IMM(BPF_REG_0, 2),
539*858ea5e5SAndroid Build Coastguard Worker 		BPF_EXIT_INSN()
540*858ea5e5SAndroid Build Coastguard Worker 	};
541*858ea5e5SAndroid Build Coastguard Worker 
542*858ea5e5SAndroid Build Coastguard Worker 	return probe_prog_load_ifindex(prog_type, insns, ARRAY_SIZE(insns),
543*858ea5e5SAndroid Build Coastguard Worker 				       NULL, 0, ifindex);
544*858ea5e5SAndroid Build Coastguard Worker }
545*858ea5e5SAndroid Build Coastguard Worker 
546*858ea5e5SAndroid Build Coastguard Worker static void
probe_prog_type(enum bpf_prog_type prog_type,const char * prog_type_str,bool * supported_types,const char * define_prefix,__u32 ifindex)547*858ea5e5SAndroid Build Coastguard Worker probe_prog_type(enum bpf_prog_type prog_type, const char *prog_type_str,
548*858ea5e5SAndroid Build Coastguard Worker 		bool *supported_types, const char *define_prefix, __u32 ifindex)
549*858ea5e5SAndroid Build Coastguard Worker {
550*858ea5e5SAndroid Build Coastguard Worker 	char feat_name[128], plain_desc[128], define_name[128];
551*858ea5e5SAndroid Build Coastguard Worker 	const char *plain_comment = "eBPF program_type ";
552*858ea5e5SAndroid Build Coastguard Worker 	size_t maxlen;
553*858ea5e5SAndroid Build Coastguard Worker 	bool res;
554*858ea5e5SAndroid Build Coastguard Worker 
555*858ea5e5SAndroid Build Coastguard Worker 	if (ifindex) {
556*858ea5e5SAndroid Build Coastguard Worker 		switch (prog_type) {
557*858ea5e5SAndroid Build Coastguard Worker 		case BPF_PROG_TYPE_SCHED_CLS:
558*858ea5e5SAndroid Build Coastguard Worker 		case BPF_PROG_TYPE_XDP:
559*858ea5e5SAndroid Build Coastguard Worker 			break;
560*858ea5e5SAndroid Build Coastguard Worker 		default:
561*858ea5e5SAndroid Build Coastguard Worker 			return;
562*858ea5e5SAndroid Build Coastguard Worker 		}
563*858ea5e5SAndroid Build Coastguard Worker 
564*858ea5e5SAndroid Build Coastguard Worker 		res = probe_prog_type_ifindex(prog_type, ifindex);
565*858ea5e5SAndroid Build Coastguard Worker 	} else {
566*858ea5e5SAndroid Build Coastguard Worker 		res = libbpf_probe_bpf_prog_type(prog_type, NULL) > 0;
567*858ea5e5SAndroid Build Coastguard Worker 	}
568*858ea5e5SAndroid Build Coastguard Worker 
569*858ea5e5SAndroid Build Coastguard Worker #ifdef USE_LIBCAP
570*858ea5e5SAndroid Build Coastguard Worker 	/* Probe may succeed even if program load fails, for unprivileged users
571*858ea5e5SAndroid Build Coastguard Worker 	 * check that we did not fail because of insufficient permissions
572*858ea5e5SAndroid Build Coastguard Worker 	 */
573*858ea5e5SAndroid Build Coastguard Worker 	if (run_as_unprivileged && errno == EPERM)
574*858ea5e5SAndroid Build Coastguard Worker 		res = false;
575*858ea5e5SAndroid Build Coastguard Worker #endif
576*858ea5e5SAndroid Build Coastguard Worker 
577*858ea5e5SAndroid Build Coastguard Worker 	supported_types[prog_type] |= res;
578*858ea5e5SAndroid Build Coastguard Worker 
579*858ea5e5SAndroid Build Coastguard Worker 	maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
580*858ea5e5SAndroid Build Coastguard Worker 	if (strlen(prog_type_str) > maxlen) {
581*858ea5e5SAndroid Build Coastguard Worker 		p_info("program type name too long");
582*858ea5e5SAndroid Build Coastguard Worker 		return;
583*858ea5e5SAndroid Build Coastguard Worker 	}
584*858ea5e5SAndroid Build Coastguard Worker 
585*858ea5e5SAndroid Build Coastguard Worker 	sprintf(feat_name, "have_%s_prog_type", prog_type_str);
586*858ea5e5SAndroid Build Coastguard Worker 	sprintf(define_name, "%s_prog_type", prog_type_str);
587*858ea5e5SAndroid Build Coastguard Worker 	uppercase(define_name, sizeof(define_name));
588*858ea5e5SAndroid Build Coastguard Worker 	sprintf(plain_desc, "%s%s", plain_comment, prog_type_str);
589*858ea5e5SAndroid Build Coastguard Worker 	print_bool_feature(feat_name, plain_desc, define_name, res,
590*858ea5e5SAndroid Build Coastguard Worker 			   define_prefix);
591*858ea5e5SAndroid Build Coastguard Worker }
592*858ea5e5SAndroid Build Coastguard Worker 
probe_map_type_ifindex(enum bpf_map_type map_type,__u32 ifindex)593*858ea5e5SAndroid Build Coastguard Worker static bool probe_map_type_ifindex(enum bpf_map_type map_type, __u32 ifindex)
594*858ea5e5SAndroid Build Coastguard Worker {
595*858ea5e5SAndroid Build Coastguard Worker 	LIBBPF_OPTS(bpf_map_create_opts, opts);
596*858ea5e5SAndroid Build Coastguard Worker 	int key_size, value_size, max_entries;
597*858ea5e5SAndroid Build Coastguard Worker 	int fd;
598*858ea5e5SAndroid Build Coastguard Worker 
599*858ea5e5SAndroid Build Coastguard Worker 	opts.map_ifindex = ifindex;
600*858ea5e5SAndroid Build Coastguard Worker 
601*858ea5e5SAndroid Build Coastguard Worker 	key_size = sizeof(__u32);
602*858ea5e5SAndroid Build Coastguard Worker 	value_size = sizeof(__u32);
603*858ea5e5SAndroid Build Coastguard Worker 	max_entries = 1;
604*858ea5e5SAndroid Build Coastguard Worker 
605*858ea5e5SAndroid Build Coastguard Worker 	fd = bpf_map_create(map_type, NULL, key_size, value_size, max_entries,
606*858ea5e5SAndroid Build Coastguard Worker 			    &opts);
607*858ea5e5SAndroid Build Coastguard Worker 	if (fd >= 0)
608*858ea5e5SAndroid Build Coastguard Worker 		close(fd);
609*858ea5e5SAndroid Build Coastguard Worker 
610*858ea5e5SAndroid Build Coastguard Worker 	return fd >= 0;
611*858ea5e5SAndroid Build Coastguard Worker }
612*858ea5e5SAndroid Build Coastguard Worker 
613*858ea5e5SAndroid Build Coastguard Worker static void
probe_map_type(enum bpf_map_type map_type,char const * map_type_str,const char * define_prefix,__u32 ifindex)614*858ea5e5SAndroid Build Coastguard Worker probe_map_type(enum bpf_map_type map_type, char const *map_type_str,
615*858ea5e5SAndroid Build Coastguard Worker 	       const char *define_prefix, __u32 ifindex)
616*858ea5e5SAndroid Build Coastguard Worker {
617*858ea5e5SAndroid Build Coastguard Worker 	char feat_name[128], plain_desc[128], define_name[128];
618*858ea5e5SAndroid Build Coastguard Worker 	const char *plain_comment = "eBPF map_type ";
619*858ea5e5SAndroid Build Coastguard Worker 	size_t maxlen;
620*858ea5e5SAndroid Build Coastguard Worker 	bool res;
621*858ea5e5SAndroid Build Coastguard Worker 
622*858ea5e5SAndroid Build Coastguard Worker 	if (ifindex) {
623*858ea5e5SAndroid Build Coastguard Worker 		switch (map_type) {
624*858ea5e5SAndroid Build Coastguard Worker 		case BPF_MAP_TYPE_HASH:
625*858ea5e5SAndroid Build Coastguard Worker 		case BPF_MAP_TYPE_ARRAY:
626*858ea5e5SAndroid Build Coastguard Worker 			break;
627*858ea5e5SAndroid Build Coastguard Worker 		default:
628*858ea5e5SAndroid Build Coastguard Worker 			return;
629*858ea5e5SAndroid Build Coastguard Worker 		}
630*858ea5e5SAndroid Build Coastguard Worker 
631*858ea5e5SAndroid Build Coastguard Worker 		res = probe_map_type_ifindex(map_type, ifindex);
632*858ea5e5SAndroid Build Coastguard Worker 	} else {
633*858ea5e5SAndroid Build Coastguard Worker 		res = libbpf_probe_bpf_map_type(map_type, NULL) > 0;
634*858ea5e5SAndroid Build Coastguard Worker 	}
635*858ea5e5SAndroid Build Coastguard Worker 
636*858ea5e5SAndroid Build Coastguard Worker 	/* Probe result depends on the success of map creation, no additional
637*858ea5e5SAndroid Build Coastguard Worker 	 * check required for unprivileged users
638*858ea5e5SAndroid Build Coastguard Worker 	 */
639*858ea5e5SAndroid Build Coastguard Worker 
640*858ea5e5SAndroid Build Coastguard Worker 	maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
641*858ea5e5SAndroid Build Coastguard Worker 	if (strlen(map_type_str) > maxlen) {
642*858ea5e5SAndroid Build Coastguard Worker 		p_info("map type name too long");
643*858ea5e5SAndroid Build Coastguard Worker 		return;
644*858ea5e5SAndroid Build Coastguard Worker 	}
645*858ea5e5SAndroid Build Coastguard Worker 
646*858ea5e5SAndroid Build Coastguard Worker 	sprintf(feat_name, "have_%s_map_type", map_type_str);
647*858ea5e5SAndroid Build Coastguard Worker 	sprintf(define_name, "%s_map_type", map_type_str);
648*858ea5e5SAndroid Build Coastguard Worker 	uppercase(define_name, sizeof(define_name));
649*858ea5e5SAndroid Build Coastguard Worker 	sprintf(plain_desc, "%s%s", plain_comment, map_type_str);
650*858ea5e5SAndroid Build Coastguard Worker 	print_bool_feature(feat_name, plain_desc, define_name, res,
651*858ea5e5SAndroid Build Coastguard Worker 			   define_prefix);
652*858ea5e5SAndroid Build Coastguard Worker }
653*858ea5e5SAndroid Build Coastguard Worker 
654*858ea5e5SAndroid Build Coastguard Worker static bool
probe_helper_ifindex(enum bpf_func_id id,enum bpf_prog_type prog_type,__u32 ifindex)655*858ea5e5SAndroid Build Coastguard Worker probe_helper_ifindex(enum bpf_func_id id, enum bpf_prog_type prog_type,
656*858ea5e5SAndroid Build Coastguard Worker 		     __u32 ifindex)
657*858ea5e5SAndroid Build Coastguard Worker {
658*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_insn insns[2] = {
659*858ea5e5SAndroid Build Coastguard Worker 		BPF_EMIT_CALL(id),
660*858ea5e5SAndroid Build Coastguard Worker 		BPF_EXIT_INSN()
661*858ea5e5SAndroid Build Coastguard Worker 	};
662*858ea5e5SAndroid Build Coastguard Worker 	char buf[4096] = {};
663*858ea5e5SAndroid Build Coastguard Worker 	bool res;
664*858ea5e5SAndroid Build Coastguard Worker 
665*858ea5e5SAndroid Build Coastguard Worker 	probe_prog_load_ifindex(prog_type, insns, ARRAY_SIZE(insns), buf,
666*858ea5e5SAndroid Build Coastguard Worker 				sizeof(buf), ifindex);
667*858ea5e5SAndroid Build Coastguard Worker 	res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
668*858ea5e5SAndroid Build Coastguard Worker 
669*858ea5e5SAndroid Build Coastguard Worker 	switch (get_vendor_id(ifindex)) {
670*858ea5e5SAndroid Build Coastguard Worker 	case 0x19ee: /* Netronome specific */
671*858ea5e5SAndroid Build Coastguard Worker 		res = res && !grep(buf, "not supported by FW") &&
672*858ea5e5SAndroid Build Coastguard Worker 			!grep(buf, "unsupported function id");
673*858ea5e5SAndroid Build Coastguard Worker 		break;
674*858ea5e5SAndroid Build Coastguard Worker 	default:
675*858ea5e5SAndroid Build Coastguard Worker 		break;
676*858ea5e5SAndroid Build Coastguard Worker 	}
677*858ea5e5SAndroid Build Coastguard Worker 
678*858ea5e5SAndroid Build Coastguard Worker 	return res;
679*858ea5e5SAndroid Build Coastguard Worker }
680*858ea5e5SAndroid Build Coastguard Worker 
681*858ea5e5SAndroid Build Coastguard Worker static bool
probe_helper_for_progtype(enum bpf_prog_type prog_type,bool supported_type,const char * define_prefix,unsigned int id,const char * ptype_name,__u32 ifindex)682*858ea5e5SAndroid Build Coastguard Worker probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
683*858ea5e5SAndroid Build Coastguard Worker 			  const char *define_prefix, unsigned int id,
684*858ea5e5SAndroid Build Coastguard Worker 			  const char *ptype_name, __u32 ifindex)
685*858ea5e5SAndroid Build Coastguard Worker {
686*858ea5e5SAndroid Build Coastguard Worker 	bool res = false;
687*858ea5e5SAndroid Build Coastguard Worker 
688*858ea5e5SAndroid Build Coastguard Worker 	if (supported_type) {
689*858ea5e5SAndroid Build Coastguard Worker 		if (ifindex)
690*858ea5e5SAndroid Build Coastguard Worker 			res = probe_helper_ifindex(id, prog_type, ifindex);
691*858ea5e5SAndroid Build Coastguard Worker 		else
692*858ea5e5SAndroid Build Coastguard Worker 			res = libbpf_probe_bpf_helper(prog_type, id, NULL) > 0;
693*858ea5e5SAndroid Build Coastguard Worker #ifdef USE_LIBCAP
694*858ea5e5SAndroid Build Coastguard Worker 		/* Probe may succeed even if program load fails, for
695*858ea5e5SAndroid Build Coastguard Worker 		 * unprivileged users check that we did not fail because of
696*858ea5e5SAndroid Build Coastguard Worker 		 * insufficient permissions
697*858ea5e5SAndroid Build Coastguard Worker 		 */
698*858ea5e5SAndroid Build Coastguard Worker 		if (run_as_unprivileged && errno == EPERM)
699*858ea5e5SAndroid Build Coastguard Worker 			res = false;
700*858ea5e5SAndroid Build Coastguard Worker #endif
701*858ea5e5SAndroid Build Coastguard Worker 	}
702*858ea5e5SAndroid Build Coastguard Worker 
703*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
704*858ea5e5SAndroid Build Coastguard Worker 		if (res)
705*858ea5e5SAndroid Build Coastguard Worker 			jsonw_string(json_wtr, helper_name[id]);
706*858ea5e5SAndroid Build Coastguard Worker 	} else if (define_prefix) {
707*858ea5e5SAndroid Build Coastguard Worker 		printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n",
708*858ea5e5SAndroid Build Coastguard Worker 		       define_prefix, ptype_name, helper_name[id],
709*858ea5e5SAndroid Build Coastguard Worker 		       res ? "1" : "0");
710*858ea5e5SAndroid Build Coastguard Worker 	} else {
711*858ea5e5SAndroid Build Coastguard Worker 		if (res)
712*858ea5e5SAndroid Build Coastguard Worker 			printf("\n\t- %s", helper_name[id]);
713*858ea5e5SAndroid Build Coastguard Worker 	}
714*858ea5e5SAndroid Build Coastguard Worker 
715*858ea5e5SAndroid Build Coastguard Worker 	return res;
716*858ea5e5SAndroid Build Coastguard Worker }
717*858ea5e5SAndroid Build Coastguard Worker 
718*858ea5e5SAndroid Build Coastguard Worker static void
probe_helpers_for_progtype(enum bpf_prog_type prog_type,const char * prog_type_str,bool supported_type,const char * define_prefix,__u32 ifindex)719*858ea5e5SAndroid Build Coastguard Worker probe_helpers_for_progtype(enum bpf_prog_type prog_type,
720*858ea5e5SAndroid Build Coastguard Worker 			   const char *prog_type_str, bool supported_type,
721*858ea5e5SAndroid Build Coastguard Worker 			   const char *define_prefix, __u32 ifindex)
722*858ea5e5SAndroid Build Coastguard Worker {
723*858ea5e5SAndroid Build Coastguard Worker 	char feat_name[128];
724*858ea5e5SAndroid Build Coastguard Worker 	unsigned int id;
725*858ea5e5SAndroid Build Coastguard Worker 	bool probe_res = false;
726*858ea5e5SAndroid Build Coastguard Worker 
727*858ea5e5SAndroid Build Coastguard Worker 	if (ifindex)
728*858ea5e5SAndroid Build Coastguard Worker 		/* Only test helpers for offload-able program types */
729*858ea5e5SAndroid Build Coastguard Worker 		switch (prog_type) {
730*858ea5e5SAndroid Build Coastguard Worker 		case BPF_PROG_TYPE_SCHED_CLS:
731*858ea5e5SAndroid Build Coastguard Worker 		case BPF_PROG_TYPE_XDP:
732*858ea5e5SAndroid Build Coastguard Worker 			break;
733*858ea5e5SAndroid Build Coastguard Worker 		default:
734*858ea5e5SAndroid Build Coastguard Worker 			return;
735*858ea5e5SAndroid Build Coastguard Worker 		}
736*858ea5e5SAndroid Build Coastguard Worker 
737*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
738*858ea5e5SAndroid Build Coastguard Worker 		sprintf(feat_name, "%s_available_helpers", prog_type_str);
739*858ea5e5SAndroid Build Coastguard Worker 		jsonw_name(json_wtr, feat_name);
740*858ea5e5SAndroid Build Coastguard Worker 		jsonw_start_array(json_wtr);
741*858ea5e5SAndroid Build Coastguard Worker 	} else if (!define_prefix) {
742*858ea5e5SAndroid Build Coastguard Worker 		printf("eBPF helpers supported for program type %s:",
743*858ea5e5SAndroid Build Coastguard Worker 		       prog_type_str);
744*858ea5e5SAndroid Build Coastguard Worker 	}
745*858ea5e5SAndroid Build Coastguard Worker 
746*858ea5e5SAndroid Build Coastguard Worker 	for (id = 1; id < ARRAY_SIZE(helper_name); id++) {
747*858ea5e5SAndroid Build Coastguard Worker 		/* Skip helper functions which emit dmesg messages when not in
748*858ea5e5SAndroid Build Coastguard Worker 		 * the full mode.
749*858ea5e5SAndroid Build Coastguard Worker 		 */
750*858ea5e5SAndroid Build Coastguard Worker 		switch (id) {
751*858ea5e5SAndroid Build Coastguard Worker 		case BPF_FUNC_trace_printk:
752*858ea5e5SAndroid Build Coastguard Worker 		case BPF_FUNC_trace_vprintk:
753*858ea5e5SAndroid Build Coastguard Worker 		case BPF_FUNC_probe_write_user:
754*858ea5e5SAndroid Build Coastguard Worker 			if (!full_mode)
755*858ea5e5SAndroid Build Coastguard Worker 				continue;
756*858ea5e5SAndroid Build Coastguard Worker 			fallthrough;
757*858ea5e5SAndroid Build Coastguard Worker 		default:
758*858ea5e5SAndroid Build Coastguard Worker 			probe_res |= probe_helper_for_progtype(prog_type, supported_type,
759*858ea5e5SAndroid Build Coastguard Worker 						  define_prefix, id, prog_type_str,
760*858ea5e5SAndroid Build Coastguard Worker 						  ifindex);
761*858ea5e5SAndroid Build Coastguard Worker 		}
762*858ea5e5SAndroid Build Coastguard Worker 	}
763*858ea5e5SAndroid Build Coastguard Worker 
764*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
765*858ea5e5SAndroid Build Coastguard Worker 		jsonw_end_array(json_wtr);
766*858ea5e5SAndroid Build Coastguard Worker 	else if (!define_prefix) {
767*858ea5e5SAndroid Build Coastguard Worker 		printf("\n");
768*858ea5e5SAndroid Build Coastguard Worker 		if (!probe_res) {
769*858ea5e5SAndroid Build Coastguard Worker 			if (!supported_type)
770*858ea5e5SAndroid Build Coastguard Worker 				printf("\tProgram type not supported\n");
771*858ea5e5SAndroid Build Coastguard Worker 			else
772*858ea5e5SAndroid Build Coastguard Worker 				printf("\tCould not determine which helpers are available\n");
773*858ea5e5SAndroid Build Coastguard Worker 		}
774*858ea5e5SAndroid Build Coastguard Worker 	}
775*858ea5e5SAndroid Build Coastguard Worker 
776*858ea5e5SAndroid Build Coastguard Worker 
777*858ea5e5SAndroid Build Coastguard Worker }
778*858ea5e5SAndroid Build Coastguard Worker 
779*858ea5e5SAndroid Build Coastguard Worker static void
probe_misc_feature(struct bpf_insn * insns,size_t len,const char * define_prefix,__u32 ifindex,const char * feat_name,const char * plain_name,const char * define_name)780*858ea5e5SAndroid Build Coastguard Worker probe_misc_feature(struct bpf_insn *insns, size_t len,
781*858ea5e5SAndroid Build Coastguard Worker 		   const char *define_prefix, __u32 ifindex,
782*858ea5e5SAndroid Build Coastguard Worker 		   const char *feat_name, const char *plain_name,
783*858ea5e5SAndroid Build Coastguard Worker 		   const char *define_name)
784*858ea5e5SAndroid Build Coastguard Worker {
785*858ea5e5SAndroid Build Coastguard Worker 	LIBBPF_OPTS(bpf_prog_load_opts, opts,
786*858ea5e5SAndroid Build Coastguard Worker 		.prog_ifindex = ifindex,
787*858ea5e5SAndroid Build Coastguard Worker 	);
788*858ea5e5SAndroid Build Coastguard Worker 	bool res;
789*858ea5e5SAndroid Build Coastguard Worker 	int fd;
790*858ea5e5SAndroid Build Coastguard Worker 
791*858ea5e5SAndroid Build Coastguard Worker 	errno = 0;
792*858ea5e5SAndroid Build Coastguard Worker 	fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL",
793*858ea5e5SAndroid Build Coastguard Worker 			   insns, len, &opts);
794*858ea5e5SAndroid Build Coastguard Worker 	res = fd >= 0 || !errno;
795*858ea5e5SAndroid Build Coastguard Worker 
796*858ea5e5SAndroid Build Coastguard Worker 	if (fd >= 0)
797*858ea5e5SAndroid Build Coastguard Worker 		close(fd);
798*858ea5e5SAndroid Build Coastguard Worker 
799*858ea5e5SAndroid Build Coastguard Worker 	print_bool_feature(feat_name, plain_name, define_name, res,
800*858ea5e5SAndroid Build Coastguard Worker 			   define_prefix);
801*858ea5e5SAndroid Build Coastguard Worker }
802*858ea5e5SAndroid Build Coastguard Worker 
803*858ea5e5SAndroid Build Coastguard Worker /*
804*858ea5e5SAndroid Build Coastguard Worker  * Probe for availability of kernel commit (5.3):
805*858ea5e5SAndroid Build Coastguard Worker  *
806*858ea5e5SAndroid Build Coastguard Worker  * c04c0d2b968a ("bpf: increase complexity limit and maximum program size")
807*858ea5e5SAndroid Build Coastguard Worker  */
probe_large_insn_limit(const char * define_prefix,__u32 ifindex)808*858ea5e5SAndroid Build Coastguard Worker static void probe_large_insn_limit(const char *define_prefix, __u32 ifindex)
809*858ea5e5SAndroid Build Coastguard Worker {
810*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_insn insns[BPF_MAXINSNS + 1];
811*858ea5e5SAndroid Build Coastguard Worker 	int i;
812*858ea5e5SAndroid Build Coastguard Worker 
813*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < BPF_MAXINSNS; i++)
814*858ea5e5SAndroid Build Coastguard Worker 		insns[i] = BPF_MOV64_IMM(BPF_REG_0, 1);
815*858ea5e5SAndroid Build Coastguard Worker 	insns[BPF_MAXINSNS] = BPF_EXIT_INSN();
816*858ea5e5SAndroid Build Coastguard Worker 
817*858ea5e5SAndroid Build Coastguard Worker 	probe_misc_feature(insns, ARRAY_SIZE(insns),
818*858ea5e5SAndroid Build Coastguard Worker 			   define_prefix, ifindex,
819*858ea5e5SAndroid Build Coastguard Worker 			   "have_large_insn_limit",
820*858ea5e5SAndroid Build Coastguard Worker 			   "Large program size limit",
821*858ea5e5SAndroid Build Coastguard Worker 			   "LARGE_INSN_LIMIT");
822*858ea5e5SAndroid Build Coastguard Worker }
823*858ea5e5SAndroid Build Coastguard Worker 
824*858ea5e5SAndroid Build Coastguard Worker /*
825*858ea5e5SAndroid Build Coastguard Worker  * Probe for bounded loop support introduced in commit 2589726d12a1
826*858ea5e5SAndroid Build Coastguard Worker  * ("bpf: introduce bounded loops").
827*858ea5e5SAndroid Build Coastguard Worker  */
828*858ea5e5SAndroid Build Coastguard Worker static void
probe_bounded_loops(const char * define_prefix,__u32 ifindex)829*858ea5e5SAndroid Build Coastguard Worker probe_bounded_loops(const char *define_prefix, __u32 ifindex)
830*858ea5e5SAndroid Build Coastguard Worker {
831*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_insn insns[4] = {
832*858ea5e5SAndroid Build Coastguard Worker 		BPF_MOV64_IMM(BPF_REG_0, 10),
833*858ea5e5SAndroid Build Coastguard Worker 		BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 1),
834*858ea5e5SAndroid Build Coastguard Worker 		BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, -2),
835*858ea5e5SAndroid Build Coastguard Worker 		BPF_EXIT_INSN()
836*858ea5e5SAndroid Build Coastguard Worker 	};
837*858ea5e5SAndroid Build Coastguard Worker 
838*858ea5e5SAndroid Build Coastguard Worker 	probe_misc_feature(insns, ARRAY_SIZE(insns),
839*858ea5e5SAndroid Build Coastguard Worker 			   define_prefix, ifindex,
840*858ea5e5SAndroid Build Coastguard Worker 			   "have_bounded_loops",
841*858ea5e5SAndroid Build Coastguard Worker 			   "Bounded loop support",
842*858ea5e5SAndroid Build Coastguard Worker 			   "BOUNDED_LOOPS");
843*858ea5e5SAndroid Build Coastguard Worker }
844*858ea5e5SAndroid Build Coastguard Worker 
845*858ea5e5SAndroid Build Coastguard Worker /*
846*858ea5e5SAndroid Build Coastguard Worker  * Probe for the v2 instruction set extension introduced in commit 92b31a9af73b
847*858ea5e5SAndroid Build Coastguard Worker  * ("bpf: add BPF_J{LT,LE,SLT,SLE} instructions").
848*858ea5e5SAndroid Build Coastguard Worker  */
849*858ea5e5SAndroid Build Coastguard Worker static void
probe_v2_isa_extension(const char * define_prefix,__u32 ifindex)850*858ea5e5SAndroid Build Coastguard Worker probe_v2_isa_extension(const char *define_prefix, __u32 ifindex)
851*858ea5e5SAndroid Build Coastguard Worker {
852*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_insn insns[4] = {
853*858ea5e5SAndroid Build Coastguard Worker 		BPF_MOV64_IMM(BPF_REG_0, 0),
854*858ea5e5SAndroid Build Coastguard Worker 		BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 0, 1),
855*858ea5e5SAndroid Build Coastguard Worker 		BPF_MOV64_IMM(BPF_REG_0, 1),
856*858ea5e5SAndroid Build Coastguard Worker 		BPF_EXIT_INSN()
857*858ea5e5SAndroid Build Coastguard Worker 	};
858*858ea5e5SAndroid Build Coastguard Worker 
859*858ea5e5SAndroid Build Coastguard Worker 	probe_misc_feature(insns, ARRAY_SIZE(insns),
860*858ea5e5SAndroid Build Coastguard Worker 			   define_prefix, ifindex,
861*858ea5e5SAndroid Build Coastguard Worker 			   "have_v2_isa_extension",
862*858ea5e5SAndroid Build Coastguard Worker 			   "ISA extension v2",
863*858ea5e5SAndroid Build Coastguard Worker 			   "V2_ISA_EXTENSION");
864*858ea5e5SAndroid Build Coastguard Worker }
865*858ea5e5SAndroid Build Coastguard Worker 
866*858ea5e5SAndroid Build Coastguard Worker /*
867*858ea5e5SAndroid Build Coastguard Worker  * Probe for the v3 instruction set extension introduced in commit 092ed0968bb6
868*858ea5e5SAndroid Build Coastguard Worker  * ("bpf: verifier support JMP32").
869*858ea5e5SAndroid Build Coastguard Worker  */
870*858ea5e5SAndroid Build Coastguard Worker static void
probe_v3_isa_extension(const char * define_prefix,__u32 ifindex)871*858ea5e5SAndroid Build Coastguard Worker probe_v3_isa_extension(const char *define_prefix, __u32 ifindex)
872*858ea5e5SAndroid Build Coastguard Worker {
873*858ea5e5SAndroid Build Coastguard Worker 	struct bpf_insn insns[4] = {
874*858ea5e5SAndroid Build Coastguard Worker 		BPF_MOV64_IMM(BPF_REG_0, 0),
875*858ea5e5SAndroid Build Coastguard Worker 		BPF_JMP32_IMM(BPF_JLT, BPF_REG_0, 0, 1),
876*858ea5e5SAndroid Build Coastguard Worker 		BPF_MOV64_IMM(BPF_REG_0, 1),
877*858ea5e5SAndroid Build Coastguard Worker 		BPF_EXIT_INSN()
878*858ea5e5SAndroid Build Coastguard Worker 	};
879*858ea5e5SAndroid Build Coastguard Worker 
880*858ea5e5SAndroid Build Coastguard Worker 	probe_misc_feature(insns, ARRAY_SIZE(insns),
881*858ea5e5SAndroid Build Coastguard Worker 			   define_prefix, ifindex,
882*858ea5e5SAndroid Build Coastguard Worker 			   "have_v3_isa_extension",
883*858ea5e5SAndroid Build Coastguard Worker 			   "ISA extension v3",
884*858ea5e5SAndroid Build Coastguard Worker 			   "V3_ISA_EXTENSION");
885*858ea5e5SAndroid Build Coastguard Worker }
886*858ea5e5SAndroid Build Coastguard Worker 
887*858ea5e5SAndroid Build Coastguard Worker static void
section_system_config(enum probe_component target,const char * define_prefix)888*858ea5e5SAndroid Build Coastguard Worker section_system_config(enum probe_component target, const char *define_prefix)
889*858ea5e5SAndroid Build Coastguard Worker {
890*858ea5e5SAndroid Build Coastguard Worker 	switch (target) {
891*858ea5e5SAndroid Build Coastguard Worker 	case COMPONENT_KERNEL:
892*858ea5e5SAndroid Build Coastguard Worker 	case COMPONENT_UNSPEC:
893*858ea5e5SAndroid Build Coastguard Worker 		print_start_section("system_config",
894*858ea5e5SAndroid Build Coastguard Worker 				    "Scanning system configuration...",
895*858ea5e5SAndroid Build Coastguard Worker 				    "/*** Misc kernel config items ***/",
896*858ea5e5SAndroid Build Coastguard Worker 				    define_prefix);
897*858ea5e5SAndroid Build Coastguard Worker 		if (!define_prefix) {
898*858ea5e5SAndroid Build Coastguard Worker 			if (check_procfs()) {
899*858ea5e5SAndroid Build Coastguard Worker 				probe_unprivileged_disabled();
900*858ea5e5SAndroid Build Coastguard Worker 				probe_jit_enable();
901*858ea5e5SAndroid Build Coastguard Worker 				probe_jit_harden();
902*858ea5e5SAndroid Build Coastguard Worker 				probe_jit_kallsyms();
903*858ea5e5SAndroid Build Coastguard Worker 				probe_jit_limit();
904*858ea5e5SAndroid Build Coastguard Worker 			} else {
905*858ea5e5SAndroid Build Coastguard Worker 				p_info("/* procfs not mounted, skipping related probes */");
906*858ea5e5SAndroid Build Coastguard Worker 			}
907*858ea5e5SAndroid Build Coastguard Worker 		}
908*858ea5e5SAndroid Build Coastguard Worker 		probe_kernel_image_config(define_prefix);
909*858ea5e5SAndroid Build Coastguard Worker 		print_end_section();
910*858ea5e5SAndroid Build Coastguard Worker 		break;
911*858ea5e5SAndroid Build Coastguard Worker 	default:
912*858ea5e5SAndroid Build Coastguard Worker 		break;
913*858ea5e5SAndroid Build Coastguard Worker 	}
914*858ea5e5SAndroid Build Coastguard Worker }
915*858ea5e5SAndroid Build Coastguard Worker 
section_syscall_config(const char * define_prefix)916*858ea5e5SAndroid Build Coastguard Worker static bool section_syscall_config(const char *define_prefix)
917*858ea5e5SAndroid Build Coastguard Worker {
918*858ea5e5SAndroid Build Coastguard Worker 	bool res;
919*858ea5e5SAndroid Build Coastguard Worker 
920*858ea5e5SAndroid Build Coastguard Worker 	print_start_section("syscall_config",
921*858ea5e5SAndroid Build Coastguard Worker 			    "Scanning system call availability...",
922*858ea5e5SAndroid Build Coastguard Worker 			    "/*** System call availability ***/",
923*858ea5e5SAndroid Build Coastguard Worker 			    define_prefix);
924*858ea5e5SAndroid Build Coastguard Worker 	res = probe_bpf_syscall(define_prefix);
925*858ea5e5SAndroid Build Coastguard Worker 	print_end_section();
926*858ea5e5SAndroid Build Coastguard Worker 
927*858ea5e5SAndroid Build Coastguard Worker 	return res;
928*858ea5e5SAndroid Build Coastguard Worker }
929*858ea5e5SAndroid Build Coastguard Worker 
930*858ea5e5SAndroid Build Coastguard Worker static void
section_program_types(bool * supported_types,const char * define_prefix,__u32 ifindex)931*858ea5e5SAndroid Build Coastguard Worker section_program_types(bool *supported_types, const char *define_prefix,
932*858ea5e5SAndroid Build Coastguard Worker 		      __u32 ifindex)
933*858ea5e5SAndroid Build Coastguard Worker {
934*858ea5e5SAndroid Build Coastguard Worker 	unsigned int prog_type = BPF_PROG_TYPE_UNSPEC;
935*858ea5e5SAndroid Build Coastguard Worker 	const char *prog_type_str;
936*858ea5e5SAndroid Build Coastguard Worker 
937*858ea5e5SAndroid Build Coastguard Worker 	print_start_section("program_types",
938*858ea5e5SAndroid Build Coastguard Worker 			    "Scanning eBPF program types...",
939*858ea5e5SAndroid Build Coastguard Worker 			    "/*** eBPF program types ***/",
940*858ea5e5SAndroid Build Coastguard Worker 			    define_prefix);
941*858ea5e5SAndroid Build Coastguard Worker 
942*858ea5e5SAndroid Build Coastguard Worker 	while (true) {
943*858ea5e5SAndroid Build Coastguard Worker 		prog_type++;
944*858ea5e5SAndroid Build Coastguard Worker 		prog_type_str = libbpf_bpf_prog_type_str(prog_type);
945*858ea5e5SAndroid Build Coastguard Worker 		/* libbpf will return NULL for variants unknown to it. */
946*858ea5e5SAndroid Build Coastguard Worker 		if (!prog_type_str)
947*858ea5e5SAndroid Build Coastguard Worker 			break;
948*858ea5e5SAndroid Build Coastguard Worker 
949*858ea5e5SAndroid Build Coastguard Worker 		probe_prog_type(prog_type, prog_type_str, supported_types, define_prefix,
950*858ea5e5SAndroid Build Coastguard Worker 				ifindex);
951*858ea5e5SAndroid Build Coastguard Worker 	}
952*858ea5e5SAndroid Build Coastguard Worker 
953*858ea5e5SAndroid Build Coastguard Worker 	print_end_section();
954*858ea5e5SAndroid Build Coastguard Worker }
955*858ea5e5SAndroid Build Coastguard Worker 
section_map_types(const char * define_prefix,__u32 ifindex)956*858ea5e5SAndroid Build Coastguard Worker static void section_map_types(const char *define_prefix, __u32 ifindex)
957*858ea5e5SAndroid Build Coastguard Worker {
958*858ea5e5SAndroid Build Coastguard Worker 	unsigned int map_type = BPF_MAP_TYPE_UNSPEC;
959*858ea5e5SAndroid Build Coastguard Worker 	const char *map_type_str;
960*858ea5e5SAndroid Build Coastguard Worker 
961*858ea5e5SAndroid Build Coastguard Worker 	print_start_section("map_types",
962*858ea5e5SAndroid Build Coastguard Worker 			    "Scanning eBPF map types...",
963*858ea5e5SAndroid Build Coastguard Worker 			    "/*** eBPF map types ***/",
964*858ea5e5SAndroid Build Coastguard Worker 			    define_prefix);
965*858ea5e5SAndroid Build Coastguard Worker 
966*858ea5e5SAndroid Build Coastguard Worker 	while (true) {
967*858ea5e5SAndroid Build Coastguard Worker 		map_type++;
968*858ea5e5SAndroid Build Coastguard Worker 		map_type_str = libbpf_bpf_map_type_str(map_type);
969*858ea5e5SAndroid Build Coastguard Worker 		/* libbpf will return NULL for variants unknown to it. */
970*858ea5e5SAndroid Build Coastguard Worker 		if (!map_type_str)
971*858ea5e5SAndroid Build Coastguard Worker 			break;
972*858ea5e5SAndroid Build Coastguard Worker 
973*858ea5e5SAndroid Build Coastguard Worker 		probe_map_type(map_type, map_type_str, define_prefix, ifindex);
974*858ea5e5SAndroid Build Coastguard Worker 	}
975*858ea5e5SAndroid Build Coastguard Worker 
976*858ea5e5SAndroid Build Coastguard Worker 	print_end_section();
977*858ea5e5SAndroid Build Coastguard Worker }
978*858ea5e5SAndroid Build Coastguard Worker 
979*858ea5e5SAndroid Build Coastguard Worker static void
section_helpers(bool * supported_types,const char * define_prefix,__u32 ifindex)980*858ea5e5SAndroid Build Coastguard Worker section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex)
981*858ea5e5SAndroid Build Coastguard Worker {
982*858ea5e5SAndroid Build Coastguard Worker 	unsigned int prog_type = BPF_PROG_TYPE_UNSPEC;
983*858ea5e5SAndroid Build Coastguard Worker 	const char *prog_type_str;
984*858ea5e5SAndroid Build Coastguard Worker 
985*858ea5e5SAndroid Build Coastguard Worker 	print_start_section("helpers",
986*858ea5e5SAndroid Build Coastguard Worker 			    "Scanning eBPF helper functions...",
987*858ea5e5SAndroid Build Coastguard Worker 			    "/*** eBPF helper functions ***/",
988*858ea5e5SAndroid Build Coastguard Worker 			    define_prefix);
989*858ea5e5SAndroid Build Coastguard Worker 
990*858ea5e5SAndroid Build Coastguard Worker 	if (define_prefix)
991*858ea5e5SAndroid Build Coastguard Worker 		printf("/*\n"
992*858ea5e5SAndroid Build Coastguard Worker 		       " * Use %sHAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)\n"
993*858ea5e5SAndroid Build Coastguard Worker 		       " * to determine if <helper_name> is available for <prog_type_name>,\n"
994*858ea5e5SAndroid Build Coastguard Worker 		       " * e.g.\n"
995*858ea5e5SAndroid Build Coastguard Worker 		       " *	#if %sHAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)\n"
996*858ea5e5SAndroid Build Coastguard Worker 		       " *		// do stuff with this helper\n"
997*858ea5e5SAndroid Build Coastguard Worker 		       " *	#elif\n"
998*858ea5e5SAndroid Build Coastguard Worker 		       " *		// use a workaround\n"
999*858ea5e5SAndroid Build Coastguard Worker 		       " *	#endif\n"
1000*858ea5e5SAndroid Build Coastguard Worker 		       " */\n"
1001*858ea5e5SAndroid Build Coastguard Worker 		       "#define %sHAVE_PROG_TYPE_HELPER(prog_type, helper)	\\\n"
1002*858ea5e5SAndroid Build Coastguard Worker 		       "	%sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n",
1003*858ea5e5SAndroid Build Coastguard Worker 		       define_prefix, define_prefix, define_prefix,
1004*858ea5e5SAndroid Build Coastguard Worker 		       define_prefix);
1005*858ea5e5SAndroid Build Coastguard Worker 	while (true) {
1006*858ea5e5SAndroid Build Coastguard Worker 		prog_type++;
1007*858ea5e5SAndroid Build Coastguard Worker 		prog_type_str = libbpf_bpf_prog_type_str(prog_type);
1008*858ea5e5SAndroid Build Coastguard Worker 		/* libbpf will return NULL for variants unknown to it. */
1009*858ea5e5SAndroid Build Coastguard Worker 		if (!prog_type_str)
1010*858ea5e5SAndroid Build Coastguard Worker 			break;
1011*858ea5e5SAndroid Build Coastguard Worker 
1012*858ea5e5SAndroid Build Coastguard Worker 		probe_helpers_for_progtype(prog_type, prog_type_str,
1013*858ea5e5SAndroid Build Coastguard Worker 					   supported_types[prog_type],
1014*858ea5e5SAndroid Build Coastguard Worker 					   define_prefix,
1015*858ea5e5SAndroid Build Coastguard Worker 					   ifindex);
1016*858ea5e5SAndroid Build Coastguard Worker 	}
1017*858ea5e5SAndroid Build Coastguard Worker 
1018*858ea5e5SAndroid Build Coastguard Worker 	print_end_section();
1019*858ea5e5SAndroid Build Coastguard Worker }
1020*858ea5e5SAndroid Build Coastguard Worker 
section_misc(const char * define_prefix,__u32 ifindex)1021*858ea5e5SAndroid Build Coastguard Worker static void section_misc(const char *define_prefix, __u32 ifindex)
1022*858ea5e5SAndroid Build Coastguard Worker {
1023*858ea5e5SAndroid Build Coastguard Worker 	print_start_section("misc",
1024*858ea5e5SAndroid Build Coastguard Worker 			    "Scanning miscellaneous eBPF features...",
1025*858ea5e5SAndroid Build Coastguard Worker 			    "/*** eBPF misc features ***/",
1026*858ea5e5SAndroid Build Coastguard Worker 			    define_prefix);
1027*858ea5e5SAndroid Build Coastguard Worker 	probe_large_insn_limit(define_prefix, ifindex);
1028*858ea5e5SAndroid Build Coastguard Worker 	probe_bounded_loops(define_prefix, ifindex);
1029*858ea5e5SAndroid Build Coastguard Worker 	probe_v2_isa_extension(define_prefix, ifindex);
1030*858ea5e5SAndroid Build Coastguard Worker 	probe_v3_isa_extension(define_prefix, ifindex);
1031*858ea5e5SAndroid Build Coastguard Worker 	print_end_section();
1032*858ea5e5SAndroid Build Coastguard Worker }
1033*858ea5e5SAndroid Build Coastguard Worker 
1034*858ea5e5SAndroid Build Coastguard Worker #ifdef USE_LIBCAP
1035*858ea5e5SAndroid Build Coastguard Worker #define capability(c) { c, false, #c }
1036*858ea5e5SAndroid Build Coastguard Worker #define capability_msg(a, i) a[i].set ? "" : a[i].name, a[i].set ? "" : ", "
1037*858ea5e5SAndroid Build Coastguard Worker #endif
1038*858ea5e5SAndroid Build Coastguard Worker 
handle_perms(void)1039*858ea5e5SAndroid Build Coastguard Worker static int handle_perms(void)
1040*858ea5e5SAndroid Build Coastguard Worker {
1041*858ea5e5SAndroid Build Coastguard Worker #ifdef USE_LIBCAP
1042*858ea5e5SAndroid Build Coastguard Worker 	struct {
1043*858ea5e5SAndroid Build Coastguard Worker 		cap_value_t cap;
1044*858ea5e5SAndroid Build Coastguard Worker 		bool set;
1045*858ea5e5SAndroid Build Coastguard Worker 		char name[14];	/* strlen("CAP_SYS_ADMIN") */
1046*858ea5e5SAndroid Build Coastguard Worker 	} bpf_caps[] = {
1047*858ea5e5SAndroid Build Coastguard Worker 		capability(CAP_SYS_ADMIN),
1048*858ea5e5SAndroid Build Coastguard Worker #ifdef CAP_BPF
1049*858ea5e5SAndroid Build Coastguard Worker 		capability(CAP_BPF),
1050*858ea5e5SAndroid Build Coastguard Worker 		capability(CAP_NET_ADMIN),
1051*858ea5e5SAndroid Build Coastguard Worker 		capability(CAP_PERFMON),
1052*858ea5e5SAndroid Build Coastguard Worker #endif
1053*858ea5e5SAndroid Build Coastguard Worker 	};
1054*858ea5e5SAndroid Build Coastguard Worker 	cap_value_t cap_list[ARRAY_SIZE(bpf_caps)];
1055*858ea5e5SAndroid Build Coastguard Worker 	unsigned int i, nb_bpf_caps = 0;
1056*858ea5e5SAndroid Build Coastguard Worker 	bool cap_sys_admin_only = true;
1057*858ea5e5SAndroid Build Coastguard Worker 	cap_flag_value_t val;
1058*858ea5e5SAndroid Build Coastguard Worker 	int res = -1;
1059*858ea5e5SAndroid Build Coastguard Worker 	cap_t caps;
1060*858ea5e5SAndroid Build Coastguard Worker 
1061*858ea5e5SAndroid Build Coastguard Worker 	caps = cap_get_proc();
1062*858ea5e5SAndroid Build Coastguard Worker 	if (!caps) {
1063*858ea5e5SAndroid Build Coastguard Worker 		p_err("failed to get capabilities for process: %s",
1064*858ea5e5SAndroid Build Coastguard Worker 		      strerror(errno));
1065*858ea5e5SAndroid Build Coastguard Worker 		return -1;
1066*858ea5e5SAndroid Build Coastguard Worker 	}
1067*858ea5e5SAndroid Build Coastguard Worker 
1068*858ea5e5SAndroid Build Coastguard Worker #ifdef CAP_BPF
1069*858ea5e5SAndroid Build Coastguard Worker 	if (CAP_IS_SUPPORTED(CAP_BPF))
1070*858ea5e5SAndroid Build Coastguard Worker 		cap_sys_admin_only = false;
1071*858ea5e5SAndroid Build Coastguard Worker #endif
1072*858ea5e5SAndroid Build Coastguard Worker 
1073*858ea5e5SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(bpf_caps); i++) {
1074*858ea5e5SAndroid Build Coastguard Worker 		const char *cap_name = bpf_caps[i].name;
1075*858ea5e5SAndroid Build Coastguard Worker 		cap_value_t cap = bpf_caps[i].cap;
1076*858ea5e5SAndroid Build Coastguard Worker 
1077*858ea5e5SAndroid Build Coastguard Worker 		if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val)) {
1078*858ea5e5SAndroid Build Coastguard Worker 			p_err("bug: failed to retrieve %s status: %s", cap_name,
1079*858ea5e5SAndroid Build Coastguard Worker 			      strerror(errno));
1080*858ea5e5SAndroid Build Coastguard Worker 			goto exit_free;
1081*858ea5e5SAndroid Build Coastguard Worker 		}
1082*858ea5e5SAndroid Build Coastguard Worker 
1083*858ea5e5SAndroid Build Coastguard Worker 		if (val == CAP_SET) {
1084*858ea5e5SAndroid Build Coastguard Worker 			bpf_caps[i].set = true;
1085*858ea5e5SAndroid Build Coastguard Worker 			cap_list[nb_bpf_caps++] = cap;
1086*858ea5e5SAndroid Build Coastguard Worker 		}
1087*858ea5e5SAndroid Build Coastguard Worker 
1088*858ea5e5SAndroid Build Coastguard Worker 		if (cap_sys_admin_only)
1089*858ea5e5SAndroid Build Coastguard Worker 			/* System does not know about CAP_BPF, meaning that
1090*858ea5e5SAndroid Build Coastguard Worker 			 * CAP_SYS_ADMIN is the only capability required. We
1091*858ea5e5SAndroid Build Coastguard Worker 			 * just checked it, break.
1092*858ea5e5SAndroid Build Coastguard Worker 			 */
1093*858ea5e5SAndroid Build Coastguard Worker 			break;
1094*858ea5e5SAndroid Build Coastguard Worker 	}
1095*858ea5e5SAndroid Build Coastguard Worker 
1096*858ea5e5SAndroid Build Coastguard Worker 	if ((run_as_unprivileged && !nb_bpf_caps) ||
1097*858ea5e5SAndroid Build Coastguard Worker 	    (!run_as_unprivileged && nb_bpf_caps == ARRAY_SIZE(bpf_caps)) ||
1098*858ea5e5SAndroid Build Coastguard Worker 	    (!run_as_unprivileged && cap_sys_admin_only && nb_bpf_caps)) {
1099*858ea5e5SAndroid Build Coastguard Worker 		/* We are all good, exit now */
1100*858ea5e5SAndroid Build Coastguard Worker 		res = 0;
1101*858ea5e5SAndroid Build Coastguard Worker 		goto exit_free;
1102*858ea5e5SAndroid Build Coastguard Worker 	}
1103*858ea5e5SAndroid Build Coastguard Worker 
1104*858ea5e5SAndroid Build Coastguard Worker 	if (!run_as_unprivileged) {
1105*858ea5e5SAndroid Build Coastguard Worker 		if (cap_sys_admin_only)
1106*858ea5e5SAndroid Build Coastguard Worker 			p_err("missing %s, required for full feature probing; run as root or use 'unprivileged'",
1107*858ea5e5SAndroid Build Coastguard Worker 			      bpf_caps[0].name);
1108*858ea5e5SAndroid Build Coastguard Worker 		else
1109*858ea5e5SAndroid Build Coastguard Worker 			p_err("missing %s%s%s%s%s%s%s%srequired for full feature probing; run as root or use 'unprivileged'",
1110*858ea5e5SAndroid Build Coastguard Worker 			      capability_msg(bpf_caps, 0),
1111*858ea5e5SAndroid Build Coastguard Worker #ifdef CAP_BPF
1112*858ea5e5SAndroid Build Coastguard Worker 			      capability_msg(bpf_caps, 1),
1113*858ea5e5SAndroid Build Coastguard Worker 			      capability_msg(bpf_caps, 2),
1114*858ea5e5SAndroid Build Coastguard Worker 			      capability_msg(bpf_caps, 3)
1115*858ea5e5SAndroid Build Coastguard Worker #else
1116*858ea5e5SAndroid Build Coastguard Worker 				"", "", "", "", "", ""
1117*858ea5e5SAndroid Build Coastguard Worker #endif /* CAP_BPF */
1118*858ea5e5SAndroid Build Coastguard Worker 				);
1119*858ea5e5SAndroid Build Coastguard Worker 		goto exit_free;
1120*858ea5e5SAndroid Build Coastguard Worker 	}
1121*858ea5e5SAndroid Build Coastguard Worker 
1122*858ea5e5SAndroid Build Coastguard Worker 	/* if (run_as_unprivileged && nb_bpf_caps > 0), drop capabilities. */
1123*858ea5e5SAndroid Build Coastguard Worker 	if (cap_set_flag(caps, CAP_EFFECTIVE, nb_bpf_caps, cap_list,
1124*858ea5e5SAndroid Build Coastguard Worker 			 CAP_CLEAR)) {
1125*858ea5e5SAndroid Build Coastguard Worker 		p_err("bug: failed to clear capabilities: %s", strerror(errno));
1126*858ea5e5SAndroid Build Coastguard Worker 		goto exit_free;
1127*858ea5e5SAndroid Build Coastguard Worker 	}
1128*858ea5e5SAndroid Build Coastguard Worker 
1129*858ea5e5SAndroid Build Coastguard Worker 	if (cap_set_proc(caps)) {
1130*858ea5e5SAndroid Build Coastguard Worker 		p_err("failed to drop capabilities: %s", strerror(errno));
1131*858ea5e5SAndroid Build Coastguard Worker 		goto exit_free;
1132*858ea5e5SAndroid Build Coastguard Worker 	}
1133*858ea5e5SAndroid Build Coastguard Worker 
1134*858ea5e5SAndroid Build Coastguard Worker 	res = 0;
1135*858ea5e5SAndroid Build Coastguard Worker 
1136*858ea5e5SAndroid Build Coastguard Worker exit_free:
1137*858ea5e5SAndroid Build Coastguard Worker 	if (cap_free(caps) && !res) {
1138*858ea5e5SAndroid Build Coastguard Worker 		p_err("failed to clear storage object for capabilities: %s",
1139*858ea5e5SAndroid Build Coastguard Worker 		      strerror(errno));
1140*858ea5e5SAndroid Build Coastguard Worker 		res = -1;
1141*858ea5e5SAndroid Build Coastguard Worker 	}
1142*858ea5e5SAndroid Build Coastguard Worker 
1143*858ea5e5SAndroid Build Coastguard Worker 	return res;
1144*858ea5e5SAndroid Build Coastguard Worker #else
1145*858ea5e5SAndroid Build Coastguard Worker 	/* Detection assumes user has specific privileges.
1146*858ea5e5SAndroid Build Coastguard Worker 	 * We do not use libcap so let's approximate, and restrict usage to
1147*858ea5e5SAndroid Build Coastguard Worker 	 * root user only.
1148*858ea5e5SAndroid Build Coastguard Worker 	 */
1149*858ea5e5SAndroid Build Coastguard Worker 	if (geteuid()) {
1150*858ea5e5SAndroid Build Coastguard Worker 		p_err("full feature probing requires root privileges");
1151*858ea5e5SAndroid Build Coastguard Worker 		return -1;
1152*858ea5e5SAndroid Build Coastguard Worker 	}
1153*858ea5e5SAndroid Build Coastguard Worker 
1154*858ea5e5SAndroid Build Coastguard Worker 	return 0;
1155*858ea5e5SAndroid Build Coastguard Worker #endif /* USE_LIBCAP */
1156*858ea5e5SAndroid Build Coastguard Worker }
1157*858ea5e5SAndroid Build Coastguard Worker 
do_probe(int argc,char ** argv)1158*858ea5e5SAndroid Build Coastguard Worker static int do_probe(int argc, char **argv)
1159*858ea5e5SAndroid Build Coastguard Worker {
1160*858ea5e5SAndroid Build Coastguard Worker 	enum probe_component target = COMPONENT_UNSPEC;
1161*858ea5e5SAndroid Build Coastguard Worker 	const char *define_prefix = NULL;
1162*858ea5e5SAndroid Build Coastguard Worker 	bool supported_types[128] = {};
1163*858ea5e5SAndroid Build Coastguard Worker 	__u32 ifindex = 0;
1164*858ea5e5SAndroid Build Coastguard Worker 	char *ifname;
1165*858ea5e5SAndroid Build Coastguard Worker 
1166*858ea5e5SAndroid Build Coastguard Worker 	set_max_rlimit();
1167*858ea5e5SAndroid Build Coastguard Worker 
1168*858ea5e5SAndroid Build Coastguard Worker 	while (argc) {
1169*858ea5e5SAndroid Build Coastguard Worker 		if (is_prefix(*argv, "kernel")) {
1170*858ea5e5SAndroid Build Coastguard Worker 			if (target != COMPONENT_UNSPEC) {
1171*858ea5e5SAndroid Build Coastguard Worker 				p_err("component to probe already specified");
1172*858ea5e5SAndroid Build Coastguard Worker 				return -1;
1173*858ea5e5SAndroid Build Coastguard Worker 			}
1174*858ea5e5SAndroid Build Coastguard Worker 			target = COMPONENT_KERNEL;
1175*858ea5e5SAndroid Build Coastguard Worker 			NEXT_ARG();
1176*858ea5e5SAndroid Build Coastguard Worker 		} else if (is_prefix(*argv, "dev")) {
1177*858ea5e5SAndroid Build Coastguard Worker 			NEXT_ARG();
1178*858ea5e5SAndroid Build Coastguard Worker 
1179*858ea5e5SAndroid Build Coastguard Worker 			if (target != COMPONENT_UNSPEC || ifindex) {
1180*858ea5e5SAndroid Build Coastguard Worker 				p_err("component to probe already specified");
1181*858ea5e5SAndroid Build Coastguard Worker 				return -1;
1182*858ea5e5SAndroid Build Coastguard Worker 			}
1183*858ea5e5SAndroid Build Coastguard Worker 			if (!REQ_ARGS(1))
1184*858ea5e5SAndroid Build Coastguard Worker 				return -1;
1185*858ea5e5SAndroid Build Coastguard Worker 
1186*858ea5e5SAndroid Build Coastguard Worker 			target = COMPONENT_DEVICE;
1187*858ea5e5SAndroid Build Coastguard Worker 			ifname = GET_ARG();
1188*858ea5e5SAndroid Build Coastguard Worker 			ifindex = if_nametoindex(ifname);
1189*858ea5e5SAndroid Build Coastguard Worker 			if (!ifindex) {
1190*858ea5e5SAndroid Build Coastguard Worker 				p_err("unrecognized netdevice '%s': %s", ifname,
1191*858ea5e5SAndroid Build Coastguard Worker 				      strerror(errno));
1192*858ea5e5SAndroid Build Coastguard Worker 				return -1;
1193*858ea5e5SAndroid Build Coastguard Worker 			}
1194*858ea5e5SAndroid Build Coastguard Worker 		} else if (is_prefix(*argv, "full")) {
1195*858ea5e5SAndroid Build Coastguard Worker 			full_mode = true;
1196*858ea5e5SAndroid Build Coastguard Worker 			NEXT_ARG();
1197*858ea5e5SAndroid Build Coastguard Worker 		} else if (is_prefix(*argv, "macros") && !define_prefix) {
1198*858ea5e5SAndroid Build Coastguard Worker 			define_prefix = "";
1199*858ea5e5SAndroid Build Coastguard Worker 			NEXT_ARG();
1200*858ea5e5SAndroid Build Coastguard Worker 		} else if (is_prefix(*argv, "prefix")) {
1201*858ea5e5SAndroid Build Coastguard Worker 			if (!define_prefix) {
1202*858ea5e5SAndroid Build Coastguard Worker 				p_err("'prefix' argument can only be use after 'macros'");
1203*858ea5e5SAndroid Build Coastguard Worker 				return -1;
1204*858ea5e5SAndroid Build Coastguard Worker 			}
1205*858ea5e5SAndroid Build Coastguard Worker 			if (strcmp(define_prefix, "")) {
1206*858ea5e5SAndroid Build Coastguard Worker 				p_err("'prefix' already defined");
1207*858ea5e5SAndroid Build Coastguard Worker 				return -1;
1208*858ea5e5SAndroid Build Coastguard Worker 			}
1209*858ea5e5SAndroid Build Coastguard Worker 			NEXT_ARG();
1210*858ea5e5SAndroid Build Coastguard Worker 
1211*858ea5e5SAndroid Build Coastguard Worker 			if (!REQ_ARGS(1))
1212*858ea5e5SAndroid Build Coastguard Worker 				return -1;
1213*858ea5e5SAndroid Build Coastguard Worker 			define_prefix = GET_ARG();
1214*858ea5e5SAndroid Build Coastguard Worker 		} else if (is_prefix(*argv, "unprivileged")) {
1215*858ea5e5SAndroid Build Coastguard Worker #ifdef USE_LIBCAP
1216*858ea5e5SAndroid Build Coastguard Worker 			run_as_unprivileged = true;
1217*858ea5e5SAndroid Build Coastguard Worker 			NEXT_ARG();
1218*858ea5e5SAndroid Build Coastguard Worker #else
1219*858ea5e5SAndroid Build Coastguard Worker 			p_err("unprivileged run not supported, recompile bpftool with libcap");
1220*858ea5e5SAndroid Build Coastguard Worker 			return -1;
1221*858ea5e5SAndroid Build Coastguard Worker #endif
1222*858ea5e5SAndroid Build Coastguard Worker 		} else {
1223*858ea5e5SAndroid Build Coastguard Worker 			p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?",
1224*858ea5e5SAndroid Build Coastguard Worker 			      *argv);
1225*858ea5e5SAndroid Build Coastguard Worker 			return -1;
1226*858ea5e5SAndroid Build Coastguard Worker 		}
1227*858ea5e5SAndroid Build Coastguard Worker 	}
1228*858ea5e5SAndroid Build Coastguard Worker 
1229*858ea5e5SAndroid Build Coastguard Worker 	/* Full feature detection requires specific privileges.
1230*858ea5e5SAndroid Build Coastguard Worker 	 * Let's approximate, and warn if user is not root.
1231*858ea5e5SAndroid Build Coastguard Worker 	 */
1232*858ea5e5SAndroid Build Coastguard Worker 	if (handle_perms())
1233*858ea5e5SAndroid Build Coastguard Worker 		return -1;
1234*858ea5e5SAndroid Build Coastguard Worker 
1235*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
1236*858ea5e5SAndroid Build Coastguard Worker 		define_prefix = NULL;
1237*858ea5e5SAndroid Build Coastguard Worker 		jsonw_start_object(json_wtr);
1238*858ea5e5SAndroid Build Coastguard Worker 	}
1239*858ea5e5SAndroid Build Coastguard Worker 
1240*858ea5e5SAndroid Build Coastguard Worker 	section_system_config(target, define_prefix);
1241*858ea5e5SAndroid Build Coastguard Worker 	if (!section_syscall_config(define_prefix))
1242*858ea5e5SAndroid Build Coastguard Worker 		/* bpf() syscall unavailable, don't probe other BPF features */
1243*858ea5e5SAndroid Build Coastguard Worker 		goto exit_close_json;
1244*858ea5e5SAndroid Build Coastguard Worker 	section_program_types(supported_types, define_prefix, ifindex);
1245*858ea5e5SAndroid Build Coastguard Worker 	section_map_types(define_prefix, ifindex);
1246*858ea5e5SAndroid Build Coastguard Worker 	section_helpers(supported_types, define_prefix, ifindex);
1247*858ea5e5SAndroid Build Coastguard Worker 	section_misc(define_prefix, ifindex);
1248*858ea5e5SAndroid Build Coastguard Worker 
1249*858ea5e5SAndroid Build Coastguard Worker exit_close_json:
1250*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
1251*858ea5e5SAndroid Build Coastguard Worker 		/* End root object */
1252*858ea5e5SAndroid Build Coastguard Worker 		jsonw_end_object(json_wtr);
1253*858ea5e5SAndroid Build Coastguard Worker 
1254*858ea5e5SAndroid Build Coastguard Worker 	return 0;
1255*858ea5e5SAndroid Build Coastguard Worker }
1256*858ea5e5SAndroid Build Coastguard Worker 
get_helper_name(unsigned int id)1257*858ea5e5SAndroid Build Coastguard Worker static const char *get_helper_name(unsigned int id)
1258*858ea5e5SAndroid Build Coastguard Worker {
1259*858ea5e5SAndroid Build Coastguard Worker 	if (id >= ARRAY_SIZE(helper_name))
1260*858ea5e5SAndroid Build Coastguard Worker 		return NULL;
1261*858ea5e5SAndroid Build Coastguard Worker 
1262*858ea5e5SAndroid Build Coastguard Worker 	return helper_name[id];
1263*858ea5e5SAndroid Build Coastguard Worker }
1264*858ea5e5SAndroid Build Coastguard Worker 
do_list_builtins(int argc,char ** argv)1265*858ea5e5SAndroid Build Coastguard Worker static int do_list_builtins(int argc, char **argv)
1266*858ea5e5SAndroid Build Coastguard Worker {
1267*858ea5e5SAndroid Build Coastguard Worker 	const char *(*get_name)(unsigned int id);
1268*858ea5e5SAndroid Build Coastguard Worker 	unsigned int id = 0;
1269*858ea5e5SAndroid Build Coastguard Worker 
1270*858ea5e5SAndroid Build Coastguard Worker 	if (argc < 1)
1271*858ea5e5SAndroid Build Coastguard Worker 		usage();
1272*858ea5e5SAndroid Build Coastguard Worker 
1273*858ea5e5SAndroid Build Coastguard Worker 	if (is_prefix(*argv, "prog_types")) {
1274*858ea5e5SAndroid Build Coastguard Worker 		get_name = (const char *(*)(unsigned int))libbpf_bpf_prog_type_str;
1275*858ea5e5SAndroid Build Coastguard Worker 	} else if (is_prefix(*argv, "map_types")) {
1276*858ea5e5SAndroid Build Coastguard Worker 		get_name = (const char *(*)(unsigned int))libbpf_bpf_map_type_str;
1277*858ea5e5SAndroid Build Coastguard Worker 	} else if (is_prefix(*argv, "attach_types")) {
1278*858ea5e5SAndroid Build Coastguard Worker 		get_name = (const char *(*)(unsigned int))libbpf_bpf_attach_type_str;
1279*858ea5e5SAndroid Build Coastguard Worker 	} else if (is_prefix(*argv, "link_types")) {
1280*858ea5e5SAndroid Build Coastguard Worker 		get_name = (const char *(*)(unsigned int))libbpf_bpf_link_type_str;
1281*858ea5e5SAndroid Build Coastguard Worker 	} else if (is_prefix(*argv, "helpers")) {
1282*858ea5e5SAndroid Build Coastguard Worker 		get_name = get_helper_name;
1283*858ea5e5SAndroid Build Coastguard Worker 	} else {
1284*858ea5e5SAndroid Build Coastguard Worker 		p_err("expected 'prog_types', 'map_types', 'attach_types', 'link_types' or 'helpers', got: %s", *argv);
1285*858ea5e5SAndroid Build Coastguard Worker 		return -1;
1286*858ea5e5SAndroid Build Coastguard Worker 	}
1287*858ea5e5SAndroid Build Coastguard Worker 
1288*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
1289*858ea5e5SAndroid Build Coastguard Worker 		jsonw_start_array(json_wtr);	/* root array */
1290*858ea5e5SAndroid Build Coastguard Worker 
1291*858ea5e5SAndroid Build Coastguard Worker 	while (true) {
1292*858ea5e5SAndroid Build Coastguard Worker 		const char *name;
1293*858ea5e5SAndroid Build Coastguard Worker 
1294*858ea5e5SAndroid Build Coastguard Worker 		name = get_name(id++);
1295*858ea5e5SAndroid Build Coastguard Worker 		if (!name)
1296*858ea5e5SAndroid Build Coastguard Worker 			break;
1297*858ea5e5SAndroid Build Coastguard Worker 		if (json_output)
1298*858ea5e5SAndroid Build Coastguard Worker 			jsonw_string(json_wtr, name);
1299*858ea5e5SAndroid Build Coastguard Worker 		else
1300*858ea5e5SAndroid Build Coastguard Worker 			printf("%s\n", name);
1301*858ea5e5SAndroid Build Coastguard Worker 	}
1302*858ea5e5SAndroid Build Coastguard Worker 
1303*858ea5e5SAndroid Build Coastguard Worker 	if (json_output)
1304*858ea5e5SAndroid Build Coastguard Worker 		jsonw_end_array(json_wtr);	/* root array */
1305*858ea5e5SAndroid Build Coastguard Worker 
1306*858ea5e5SAndroid Build Coastguard Worker 	return 0;
1307*858ea5e5SAndroid Build Coastguard Worker }
1308*858ea5e5SAndroid Build Coastguard Worker 
do_help(int argc,char ** argv)1309*858ea5e5SAndroid Build Coastguard Worker static int do_help(int argc, char **argv)
1310*858ea5e5SAndroid Build Coastguard Worker {
1311*858ea5e5SAndroid Build Coastguard Worker 	if (json_output) {
1312*858ea5e5SAndroid Build Coastguard Worker 		jsonw_null(json_wtr);
1313*858ea5e5SAndroid Build Coastguard Worker 		return 0;
1314*858ea5e5SAndroid Build Coastguard Worker 	}
1315*858ea5e5SAndroid Build Coastguard Worker 
1316*858ea5e5SAndroid Build Coastguard Worker 	fprintf(stderr,
1317*858ea5e5SAndroid Build Coastguard Worker 		"Usage: %1$s %2$s probe [COMPONENT] [full] [unprivileged] [macros [prefix PREFIX]]\n"
1318*858ea5e5SAndroid Build Coastguard Worker 		"       %1$s %2$s list_builtins GROUP\n"
1319*858ea5e5SAndroid Build Coastguard Worker 		"       %1$s %2$s help\n"
1320*858ea5e5SAndroid Build Coastguard Worker 		"\n"
1321*858ea5e5SAndroid Build Coastguard Worker 		"       COMPONENT := { kernel | dev NAME }\n"
1322*858ea5e5SAndroid Build Coastguard Worker 		"       GROUP := { prog_types | map_types | attach_types | link_types | helpers }\n"
1323*858ea5e5SAndroid Build Coastguard Worker 		"       " HELP_SPEC_OPTIONS " }\n"
1324*858ea5e5SAndroid Build Coastguard Worker 		"",
1325*858ea5e5SAndroid Build Coastguard Worker 		bin_name, argv[-2]);
1326*858ea5e5SAndroid Build Coastguard Worker 
1327*858ea5e5SAndroid Build Coastguard Worker 	return 0;
1328*858ea5e5SAndroid Build Coastguard Worker }
1329*858ea5e5SAndroid Build Coastguard Worker 
1330*858ea5e5SAndroid Build Coastguard Worker static const struct cmd cmds[] = {
1331*858ea5e5SAndroid Build Coastguard Worker 	{ "probe",		do_probe },
1332*858ea5e5SAndroid Build Coastguard Worker 	{ "list_builtins",	do_list_builtins },
1333*858ea5e5SAndroid Build Coastguard Worker 	{ "help",		do_help },
1334*858ea5e5SAndroid Build Coastguard Worker 	{ 0 }
1335*858ea5e5SAndroid Build Coastguard Worker };
1336*858ea5e5SAndroid Build Coastguard Worker 
do_feature(int argc,char ** argv)1337*858ea5e5SAndroid Build Coastguard Worker int do_feature(int argc, char **argv)
1338*858ea5e5SAndroid Build Coastguard Worker {
1339*858ea5e5SAndroid Build Coastguard Worker 	return cmd_select(cmds, argc, argv, do_help);
1340*858ea5e5SAndroid Build Coastguard Worker }
1341