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