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