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