cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

feature.c (30467B)


      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
     29enum 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
     36static const char * const helper_name[] = {
     37	__BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY)
     38};
     39
     40#undef BPF_HELPER_MAKE_ENTRY
     41
     42static bool full_mode;
     43#ifdef USE_LIBCAP
     44static bool run_as_unprivileged;
     45#endif
     46
     47/* Miscellaneous utility functions */
     48
     49static bool grep(const char *buffer, const char *pattern)
     50{
     51	return !!strstr(buffer, pattern);
     52}
     53
     54static 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
     66static 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
     76static void
     77print_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
     89static 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
    120static void
    121print_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
    134static 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
    144static 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
    170static int read_procfs(const char *path)
    171{
    172	char *endptr, *line = NULL;
    173	size_t len = 0;
    174	FILE *fd;
    175	int 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
    195static void probe_unprivileged_disabled(void)
    196{
    197	int res;
    198
    199	/* No support for C-style ouptut */
    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 %d\n", res);
    220		}
    221	}
    222}
    223
    224static void probe_jit_enable(void)
    225{
    226	int res;
    227
    228	/* No support for C-style ouptut */
    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 %d\n",
    249			       res);
    250		}
    251	}
    252}
    253
    254static void probe_jit_harden(void)
    255{
    256	int res;
    257
    258	/* No support for C-style ouptut */
    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 %d\n",
    279			       res);
    280		}
    281	}
    282}
    283
    284static void probe_jit_kallsyms(void)
    285{
    286	int res;
    287
    288	/* No support for C-style ouptut */
    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 %d\n", res);
    306		}
    307	}
    308}
    309
    310static void probe_jit_limit(void)
    311{
    312	int res;
    313
    314	/* No support for C-style ouptut */
    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 %d bytes\n", res);
    326		}
    327	}
    328}
    329
    330static 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
    358static 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		/* bpfilter back-end for iptables */
    430		{ "CONFIG_BPFILTER", },
    431		/* bpftilter module with "user mode helper" */
    432		{ "CONFIG_BPFILTER_UMH", },
    433
    434		/* test_bpf module for BPF tests */
    435		{ "CONFIG_TEST_BPF", },
    436
    437		/* Misc configs useful in BPF C programs */
    438		/* jiffies <-> sec conversion for bpf_jiffies64() helper */
    439		{ "CONFIG_HZ", true, }
    440	};
    441	char *values[ARRAY_SIZE(options)] = { };
    442	struct utsname utsn;
    443	char path[PATH_MAX];
    444	gzFile file = NULL;
    445	char buf[4096];
    446	char *value;
    447	size_t i;
    448
    449	if (!uname(&utsn)) {
    450		snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);
    451
    452		/* gzopen also accepts uncompressed files. */
    453		file = gzopen(path, "r");
    454	}
    455
    456	if (!file) {
    457		/* Some distributions build with CONFIG_IKCONFIG=y and put the
    458		 * config file at /proc/config.gz.
    459		 */
    460		file = gzopen("/proc/config.gz", "r");
    461	}
    462	if (!file) {
    463		p_info("skipping kernel config, can't open file: %s",
    464		       strerror(errno));
    465		goto end_parse;
    466	}
    467	/* Sanity checks */
    468	if (!gzgets(file, buf, sizeof(buf)) ||
    469	    !gzgets(file, buf, sizeof(buf))) {
    470		p_info("skipping kernel config, can't read from file: %s",
    471		       strerror(errno));
    472		goto end_parse;
    473	}
    474	if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
    475		p_info("skipping kernel config, can't find correct file");
    476		goto end_parse;
    477	}
    478
    479	while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) {
    480		for (i = 0; i < ARRAY_SIZE(options); i++) {
    481			if ((define_prefix && !options[i].macro_dump) ||
    482			    values[i] || strcmp(buf, options[i].name))
    483				continue;
    484
    485			values[i] = strdup(value);
    486		}
    487	}
    488
    489end_parse:
    490	if (file)
    491		gzclose(file);
    492
    493	for (i = 0; i < ARRAY_SIZE(options); i++) {
    494		if (define_prefix && !options[i].macro_dump)
    495			continue;
    496		print_kernel_option(options[i].name, values[i], define_prefix);
    497		free(values[i]);
    498	}
    499}
    500
    501static bool probe_bpf_syscall(const char *define_prefix)
    502{
    503	bool res;
    504
    505	bpf_prog_load(BPF_PROG_TYPE_UNSPEC, NULL, NULL, NULL, 0, NULL);
    506	res = (errno != ENOSYS);
    507
    508	print_bool_feature("have_bpf_syscall",
    509			   "bpf() syscall",
    510			   "BPF_SYSCALL",
    511			   res, define_prefix);
    512
    513	return res;
    514}
    515
    516static bool
    517probe_prog_load_ifindex(enum bpf_prog_type prog_type,
    518			const struct bpf_insn *insns, size_t insns_cnt,
    519			char *log_buf, size_t log_buf_sz,
    520			__u32 ifindex)
    521{
    522	LIBBPF_OPTS(bpf_prog_load_opts, opts,
    523		    .log_buf = log_buf,
    524		    .log_size = log_buf_sz,
    525		    .log_level = log_buf ? 1 : 0,
    526		    .prog_ifindex = ifindex,
    527		   );
    528	int fd;
    529
    530	errno = 0;
    531	fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insns_cnt, &opts);
    532	if (fd >= 0)
    533		close(fd);
    534
    535	return fd >= 0 && errno != EINVAL && errno != EOPNOTSUPP;
    536}
    537
    538static bool probe_prog_type_ifindex(enum bpf_prog_type prog_type, __u32 ifindex)
    539{
    540	/* nfp returns -EINVAL on exit(0) with TC offload */
    541	struct bpf_insn insns[2] = {
    542		BPF_MOV64_IMM(BPF_REG_0, 2),
    543		BPF_EXIT_INSN()
    544	};
    545
    546	return probe_prog_load_ifindex(prog_type, insns, ARRAY_SIZE(insns),
    547				       NULL, 0, ifindex);
    548}
    549
    550static void
    551probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
    552		const char *define_prefix, __u32 ifindex)
    553{
    554	char feat_name[128], plain_desc[128], define_name[128];
    555	const char *plain_comment = "eBPF program_type ";
    556	size_t maxlen;
    557	bool res;
    558
    559	if (ifindex) {
    560		switch (prog_type) {
    561		case BPF_PROG_TYPE_SCHED_CLS:
    562		case BPF_PROG_TYPE_XDP:
    563			break;
    564		default:
    565			return;
    566		}
    567
    568		res = probe_prog_type_ifindex(prog_type, ifindex);
    569	} else {
    570		res = libbpf_probe_bpf_prog_type(prog_type, NULL) > 0;
    571	}
    572
    573#ifdef USE_LIBCAP
    574	/* Probe may succeed even if program load fails, for unprivileged users
    575	 * check that we did not fail because of insufficient permissions
    576	 */
    577	if (run_as_unprivileged && errno == EPERM)
    578		res = false;
    579#endif
    580
    581	supported_types[prog_type] |= res;
    582
    583	if (!prog_type_name[prog_type]) {
    584		p_info("program type name not found (type %d)", prog_type);
    585		return;
    586	}
    587	maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
    588	if (strlen(prog_type_name[prog_type]) > maxlen) {
    589		p_info("program type name too long");
    590		return;
    591	}
    592
    593	sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]);
    594	sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]);
    595	uppercase(define_name, sizeof(define_name));
    596	sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]);
    597	print_bool_feature(feat_name, plain_desc, define_name, res,
    598			   define_prefix);
    599}
    600
    601static bool probe_map_type_ifindex(enum bpf_map_type map_type, __u32 ifindex)
    602{
    603	LIBBPF_OPTS(bpf_map_create_opts, opts);
    604	int key_size, value_size, max_entries;
    605	int fd;
    606
    607	opts.map_ifindex = ifindex;
    608
    609	key_size = sizeof(__u32);
    610	value_size = sizeof(__u32);
    611	max_entries = 1;
    612
    613	fd = bpf_map_create(map_type, NULL, key_size, value_size, max_entries,
    614			    &opts);
    615	if (fd >= 0)
    616		close(fd);
    617
    618	return fd >= 0;
    619}
    620
    621static void
    622probe_map_type(enum bpf_map_type map_type, const char *define_prefix,
    623	       __u32 ifindex)
    624{
    625	char feat_name[128], plain_desc[128], define_name[128];
    626	const char *plain_comment = "eBPF map_type ";
    627	size_t maxlen;
    628	bool res;
    629
    630	if (ifindex) {
    631		switch (map_type) {
    632		case BPF_MAP_TYPE_HASH:
    633		case BPF_MAP_TYPE_ARRAY:
    634			break;
    635		default:
    636			return;
    637		}
    638
    639		res = probe_map_type_ifindex(map_type, ifindex);
    640	} else {
    641		res = libbpf_probe_bpf_map_type(map_type, NULL) > 0;
    642	}
    643
    644	/* Probe result depends on the success of map creation, no additional
    645	 * check required for unprivileged users
    646	 */
    647
    648	if (!map_type_name[map_type]) {
    649		p_info("map type name not found (type %d)", map_type);
    650		return;
    651	}
    652	maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
    653	if (strlen(map_type_name[map_type]) > maxlen) {
    654		p_info("map type name too long");
    655		return;
    656	}
    657
    658	sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]);
    659	sprintf(define_name, "%s_map_type", map_type_name[map_type]);
    660	uppercase(define_name, sizeof(define_name));
    661	sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]);
    662	print_bool_feature(feat_name, plain_desc, define_name, res,
    663			   define_prefix);
    664}
    665
    666static bool
    667probe_helper_ifindex(enum bpf_func_id id, enum bpf_prog_type prog_type,
    668		     __u32 ifindex)
    669{
    670	struct bpf_insn insns[2] = {
    671		BPF_EMIT_CALL(id),
    672		BPF_EXIT_INSN()
    673	};
    674	char buf[4096] = {};
    675	bool res;
    676
    677	probe_prog_load_ifindex(prog_type, insns, ARRAY_SIZE(insns), buf,
    678				sizeof(buf), ifindex);
    679	res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
    680
    681	switch (get_vendor_id(ifindex)) {
    682	case 0x19ee: /* Netronome specific */
    683		res = res && !grep(buf, "not supported by FW") &&
    684			!grep(buf, "unsupported function id");
    685		break;
    686	default:
    687		break;
    688	}
    689
    690	return res;
    691}
    692
    693static bool
    694probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
    695			  const char *define_prefix, unsigned int id,
    696			  const char *ptype_name, __u32 ifindex)
    697{
    698	bool res = false;
    699
    700	if (supported_type) {
    701		if (ifindex)
    702			res = probe_helper_ifindex(id, prog_type, ifindex);
    703		else
    704			res = libbpf_probe_bpf_helper(prog_type, id, NULL) > 0;
    705#ifdef USE_LIBCAP
    706		/* Probe may succeed even if program load fails, for
    707		 * unprivileged users check that we did not fail because of
    708		 * insufficient permissions
    709		 */
    710		if (run_as_unprivileged && errno == EPERM)
    711			res = false;
    712#endif
    713	}
    714
    715	if (json_output) {
    716		if (res)
    717			jsonw_string(json_wtr, helper_name[id]);
    718	} else if (define_prefix) {
    719		printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n",
    720		       define_prefix, ptype_name, helper_name[id],
    721		       res ? "1" : "0");
    722	} else {
    723		if (res)
    724			printf("\n\t- %s", helper_name[id]);
    725	}
    726
    727	return res;
    728}
    729
    730static void
    731probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
    732			   const char *define_prefix, __u32 ifindex)
    733{
    734	const char *ptype_name = prog_type_name[prog_type];
    735	char feat_name[128];
    736	unsigned int id;
    737	bool probe_res = false;
    738
    739	if (ifindex)
    740		/* Only test helpers for offload-able program types */
    741		switch (prog_type) {
    742		case BPF_PROG_TYPE_SCHED_CLS:
    743		case BPF_PROG_TYPE_XDP:
    744			break;
    745		default:
    746			return;
    747		}
    748
    749	if (json_output) {
    750		sprintf(feat_name, "%s_available_helpers", ptype_name);
    751		jsonw_name(json_wtr, feat_name);
    752		jsonw_start_array(json_wtr);
    753	} else if (!define_prefix) {
    754		printf("eBPF helpers supported for program type %s:",
    755		       ptype_name);
    756	}
    757
    758	for (id = 1; id < ARRAY_SIZE(helper_name); id++) {
    759		/* Skip helper functions which emit dmesg messages when not in
    760		 * the full mode.
    761		 */
    762		switch (id) {
    763		case BPF_FUNC_trace_printk:
    764		case BPF_FUNC_trace_vprintk:
    765		case BPF_FUNC_probe_write_user:
    766			if (!full_mode)
    767				continue;
    768			/* fallthrough */
    769		default:
    770			probe_res |= probe_helper_for_progtype(prog_type, supported_type,
    771						  define_prefix, id, ptype_name,
    772						  ifindex);
    773		}
    774	}
    775
    776	if (json_output)
    777		jsonw_end_array(json_wtr);
    778	else if (!define_prefix) {
    779		printf("\n");
    780		if (!probe_res) {
    781			if (!supported_type)
    782				printf("\tProgram type not supported\n");
    783			else
    784				printf("\tCould not determine which helpers are available\n");
    785		}
    786	}
    787
    788
    789}
    790
    791static void
    792probe_misc_feature(struct bpf_insn *insns, size_t len,
    793		   const char *define_prefix, __u32 ifindex,
    794		   const char *feat_name, const char *plain_name,
    795		   const char *define_name)
    796{
    797	LIBBPF_OPTS(bpf_prog_load_opts, opts,
    798		.prog_ifindex = ifindex,
    799	);
    800	bool res;
    801	int fd;
    802
    803	errno = 0;
    804	fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL",
    805			   insns, len, &opts);
    806	res = fd >= 0 || !errno;
    807
    808	if (fd >= 0)
    809		close(fd);
    810
    811	print_bool_feature(feat_name, plain_name, define_name, res,
    812			   define_prefix);
    813}
    814
    815/*
    816 * Probe for availability of kernel commit (5.3):
    817 *
    818 * c04c0d2b968a ("bpf: increase complexity limit and maximum program size")
    819 */
    820static void probe_large_insn_limit(const char *define_prefix, __u32 ifindex)
    821{
    822	struct bpf_insn insns[BPF_MAXINSNS + 1];
    823	int i;
    824
    825	for (i = 0; i < BPF_MAXINSNS; i++)
    826		insns[i] = BPF_MOV64_IMM(BPF_REG_0, 1);
    827	insns[BPF_MAXINSNS] = BPF_EXIT_INSN();
    828
    829	probe_misc_feature(insns, ARRAY_SIZE(insns),
    830			   define_prefix, ifindex,
    831			   "have_large_insn_limit",
    832			   "Large program size limit",
    833			   "LARGE_INSN_LIMIT");
    834}
    835
    836/*
    837 * Probe for bounded loop support introduced in commit 2589726d12a1
    838 * ("bpf: introduce bounded loops").
    839 */
    840static void
    841probe_bounded_loops(const char *define_prefix, __u32 ifindex)
    842{
    843	struct bpf_insn insns[4] = {
    844		BPF_MOV64_IMM(BPF_REG_0, 10),
    845		BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 1),
    846		BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, -2),
    847		BPF_EXIT_INSN()
    848	};
    849
    850	probe_misc_feature(insns, ARRAY_SIZE(insns),
    851			   define_prefix, ifindex,
    852			   "have_bounded_loops",
    853			   "Bounded loop support",
    854			   "BOUNDED_LOOPS");
    855}
    856
    857/*
    858 * Probe for the v2 instruction set extension introduced in commit 92b31a9af73b
    859 * ("bpf: add BPF_J{LT,LE,SLT,SLE} instructions").
    860 */
    861static void
    862probe_v2_isa_extension(const char *define_prefix, __u32 ifindex)
    863{
    864	struct bpf_insn insns[4] = {
    865		BPF_MOV64_IMM(BPF_REG_0, 0),
    866		BPF_JMP_IMM(BPF_JLT, BPF_REG_0, 0, 1),
    867		BPF_MOV64_IMM(BPF_REG_0, 1),
    868		BPF_EXIT_INSN()
    869	};
    870
    871	probe_misc_feature(insns, ARRAY_SIZE(insns),
    872			   define_prefix, ifindex,
    873			   "have_v2_isa_extension",
    874			   "ISA extension v2",
    875			   "V2_ISA_EXTENSION");
    876}
    877
    878/*
    879 * Probe for the v3 instruction set extension introduced in commit 092ed0968bb6
    880 * ("bpf: verifier support JMP32").
    881 */
    882static void
    883probe_v3_isa_extension(const char *define_prefix, __u32 ifindex)
    884{
    885	struct bpf_insn insns[4] = {
    886		BPF_MOV64_IMM(BPF_REG_0, 0),
    887		BPF_JMP32_IMM(BPF_JLT, BPF_REG_0, 0, 1),
    888		BPF_MOV64_IMM(BPF_REG_0, 1),
    889		BPF_EXIT_INSN()
    890	};
    891
    892	probe_misc_feature(insns, ARRAY_SIZE(insns),
    893			   define_prefix, ifindex,
    894			   "have_v3_isa_extension",
    895			   "ISA extension v3",
    896			   "V3_ISA_EXTENSION");
    897}
    898
    899static void
    900section_system_config(enum probe_component target, const char *define_prefix)
    901{
    902	switch (target) {
    903	case COMPONENT_KERNEL:
    904	case COMPONENT_UNSPEC:
    905		print_start_section("system_config",
    906				    "Scanning system configuration...",
    907				    "/*** Misc kernel config items ***/",
    908				    define_prefix);
    909		if (!define_prefix) {
    910			if (check_procfs()) {
    911				probe_unprivileged_disabled();
    912				probe_jit_enable();
    913				probe_jit_harden();
    914				probe_jit_kallsyms();
    915				probe_jit_limit();
    916			} else {
    917				p_info("/* procfs not mounted, skipping related probes */");
    918			}
    919		}
    920		probe_kernel_image_config(define_prefix);
    921		print_end_section();
    922		break;
    923	default:
    924		break;
    925	}
    926}
    927
    928static bool section_syscall_config(const char *define_prefix)
    929{
    930	bool res;
    931
    932	print_start_section("syscall_config",
    933			    "Scanning system call availability...",
    934			    "/*** System call availability ***/",
    935			    define_prefix);
    936	res = probe_bpf_syscall(define_prefix);
    937	print_end_section();
    938
    939	return res;
    940}
    941
    942static void
    943section_program_types(bool *supported_types, const char *define_prefix,
    944		      __u32 ifindex)
    945{
    946	unsigned int i;
    947
    948	print_start_section("program_types",
    949			    "Scanning eBPF program types...",
    950			    "/*** eBPF program types ***/",
    951			    define_prefix);
    952
    953	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < prog_type_name_size; i++)
    954		probe_prog_type(i, supported_types, define_prefix, ifindex);
    955
    956	print_end_section();
    957}
    958
    959static void section_map_types(const char *define_prefix, __u32 ifindex)
    960{
    961	unsigned int i;
    962
    963	print_start_section("map_types",
    964			    "Scanning eBPF map types...",
    965			    "/*** eBPF map types ***/",
    966			    define_prefix);
    967
    968	for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
    969		probe_map_type(i, define_prefix, ifindex);
    970
    971	print_end_section();
    972}
    973
    974static void
    975section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex)
    976{
    977	unsigned int i;
    978
    979	print_start_section("helpers",
    980			    "Scanning eBPF helper functions...",
    981			    "/*** eBPF helper functions ***/",
    982			    define_prefix);
    983
    984	if (define_prefix)
    985		printf("/*\n"
    986		       " * Use %sHAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)\n"
    987		       " * to determine if <helper_name> is available for <prog_type_name>,\n"
    988		       " * e.g.\n"
    989		       " *	#if %sHAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)\n"
    990		       " *		// do stuff with this helper\n"
    991		       " *	#elif\n"
    992		       " *		// use a workaround\n"
    993		       " *	#endif\n"
    994		       " */\n"
    995		       "#define %sHAVE_PROG_TYPE_HELPER(prog_type, helper)	\\\n"
    996		       "	%sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n",
    997		       define_prefix, define_prefix, define_prefix,
    998		       define_prefix);
    999	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < prog_type_name_size; i++)
   1000		probe_helpers_for_progtype(i, supported_types[i], define_prefix,
   1001					   ifindex);
   1002
   1003	print_end_section();
   1004}
   1005
   1006static void section_misc(const char *define_prefix, __u32 ifindex)
   1007{
   1008	print_start_section("misc",
   1009			    "Scanning miscellaneous eBPF features...",
   1010			    "/*** eBPF misc features ***/",
   1011			    define_prefix);
   1012	probe_large_insn_limit(define_prefix, ifindex);
   1013	probe_bounded_loops(define_prefix, ifindex);
   1014	probe_v2_isa_extension(define_prefix, ifindex);
   1015	probe_v3_isa_extension(define_prefix, ifindex);
   1016	print_end_section();
   1017}
   1018
   1019#ifdef USE_LIBCAP
   1020#define capability(c) { c, false, #c }
   1021#define capability_msg(a, i) a[i].set ? "" : a[i].name, a[i].set ? "" : ", "
   1022#endif
   1023
   1024static int handle_perms(void)
   1025{
   1026#ifdef USE_LIBCAP
   1027	struct {
   1028		cap_value_t cap;
   1029		bool set;
   1030		char name[14];	/* strlen("CAP_SYS_ADMIN") */
   1031	} bpf_caps[] = {
   1032		capability(CAP_SYS_ADMIN),
   1033#ifdef CAP_BPF
   1034		capability(CAP_BPF),
   1035		capability(CAP_NET_ADMIN),
   1036		capability(CAP_PERFMON),
   1037#endif
   1038	};
   1039	cap_value_t cap_list[ARRAY_SIZE(bpf_caps)];
   1040	unsigned int i, nb_bpf_caps = 0;
   1041	bool cap_sys_admin_only = true;
   1042	cap_flag_value_t val;
   1043	int res = -1;
   1044	cap_t caps;
   1045
   1046	caps = cap_get_proc();
   1047	if (!caps) {
   1048		p_err("failed to get capabilities for process: %s",
   1049		      strerror(errno));
   1050		return -1;
   1051	}
   1052
   1053#ifdef CAP_BPF
   1054	if (CAP_IS_SUPPORTED(CAP_BPF))
   1055		cap_sys_admin_only = false;
   1056#endif
   1057
   1058	for (i = 0; i < ARRAY_SIZE(bpf_caps); i++) {
   1059		const char *cap_name = bpf_caps[i].name;
   1060		cap_value_t cap = bpf_caps[i].cap;
   1061
   1062		if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val)) {
   1063			p_err("bug: failed to retrieve %s status: %s", cap_name,
   1064			      strerror(errno));
   1065			goto exit_free;
   1066		}
   1067
   1068		if (val == CAP_SET) {
   1069			bpf_caps[i].set = true;
   1070			cap_list[nb_bpf_caps++] = cap;
   1071		}
   1072
   1073		if (cap_sys_admin_only)
   1074			/* System does not know about CAP_BPF, meaning that
   1075			 * CAP_SYS_ADMIN is the only capability required. We
   1076			 * just checked it, break.
   1077			 */
   1078			break;
   1079	}
   1080
   1081	if ((run_as_unprivileged && !nb_bpf_caps) ||
   1082	    (!run_as_unprivileged && nb_bpf_caps == ARRAY_SIZE(bpf_caps)) ||
   1083	    (!run_as_unprivileged && cap_sys_admin_only && nb_bpf_caps)) {
   1084		/* We are all good, exit now */
   1085		res = 0;
   1086		goto exit_free;
   1087	}
   1088
   1089	if (!run_as_unprivileged) {
   1090		if (cap_sys_admin_only)
   1091			p_err("missing %s, required for full feature probing; run as root or use 'unprivileged'",
   1092			      bpf_caps[0].name);
   1093		else
   1094			p_err("missing %s%s%s%s%s%s%s%srequired for full feature probing; run as root or use 'unprivileged'",
   1095			      capability_msg(bpf_caps, 0),
   1096#ifdef CAP_BPF
   1097			      capability_msg(bpf_caps, 1),
   1098			      capability_msg(bpf_caps, 2),
   1099			      capability_msg(bpf_caps, 3)
   1100#else
   1101				"", "", "", "", "", ""
   1102#endif /* CAP_BPF */
   1103				);
   1104		goto exit_free;
   1105	}
   1106
   1107	/* if (run_as_unprivileged && nb_bpf_caps > 0), drop capabilities. */
   1108	if (cap_set_flag(caps, CAP_EFFECTIVE, nb_bpf_caps, cap_list,
   1109			 CAP_CLEAR)) {
   1110		p_err("bug: failed to clear capabilities: %s", strerror(errno));
   1111		goto exit_free;
   1112	}
   1113
   1114	if (cap_set_proc(caps)) {
   1115		p_err("failed to drop capabilities: %s", strerror(errno));
   1116		goto exit_free;
   1117	}
   1118
   1119	res = 0;
   1120
   1121exit_free:
   1122	if (cap_free(caps) && !res) {
   1123		p_err("failed to clear storage object for capabilities: %s",
   1124		      strerror(errno));
   1125		res = -1;
   1126	}
   1127
   1128	return res;
   1129#else
   1130	/* Detection assumes user has specific privileges.
   1131	 * We do not use libpcap so let's approximate, and restrict usage to
   1132	 * root user only.
   1133	 */
   1134	if (geteuid()) {
   1135		p_err("full feature probing requires root privileges");
   1136		return -1;
   1137	}
   1138
   1139	return 0;
   1140#endif /* USE_LIBCAP */
   1141}
   1142
   1143static int do_probe(int argc, char **argv)
   1144{
   1145	enum probe_component target = COMPONENT_UNSPEC;
   1146	const char *define_prefix = NULL;
   1147	bool supported_types[128] = {};
   1148	__u32 ifindex = 0;
   1149	char *ifname;
   1150
   1151	while (argc) {
   1152		if (is_prefix(*argv, "kernel")) {
   1153			if (target != COMPONENT_UNSPEC) {
   1154				p_err("component to probe already specified");
   1155				return -1;
   1156			}
   1157			target = COMPONENT_KERNEL;
   1158			NEXT_ARG();
   1159		} else if (is_prefix(*argv, "dev")) {
   1160			NEXT_ARG();
   1161
   1162			if (target != COMPONENT_UNSPEC || ifindex) {
   1163				p_err("component to probe already specified");
   1164				return -1;
   1165			}
   1166			if (!REQ_ARGS(1))
   1167				return -1;
   1168
   1169			target = COMPONENT_DEVICE;
   1170			ifname = GET_ARG();
   1171			ifindex = if_nametoindex(ifname);
   1172			if (!ifindex) {
   1173				p_err("unrecognized netdevice '%s': %s", ifname,
   1174				      strerror(errno));
   1175				return -1;
   1176			}
   1177		} else if (is_prefix(*argv, "full")) {
   1178			full_mode = true;
   1179			NEXT_ARG();
   1180		} else if (is_prefix(*argv, "macros") && !define_prefix) {
   1181			define_prefix = "";
   1182			NEXT_ARG();
   1183		} else if (is_prefix(*argv, "prefix")) {
   1184			if (!define_prefix) {
   1185				p_err("'prefix' argument can only be use after 'macros'");
   1186				return -1;
   1187			}
   1188			if (strcmp(define_prefix, "")) {
   1189				p_err("'prefix' already defined");
   1190				return -1;
   1191			}
   1192			NEXT_ARG();
   1193
   1194			if (!REQ_ARGS(1))
   1195				return -1;
   1196			define_prefix = GET_ARG();
   1197		} else if (is_prefix(*argv, "unprivileged")) {
   1198#ifdef USE_LIBCAP
   1199			run_as_unprivileged = true;
   1200			NEXT_ARG();
   1201#else
   1202			p_err("unprivileged run not supported, recompile bpftool with libcap");
   1203			return -1;
   1204#endif
   1205		} else {
   1206			p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?",
   1207			      *argv);
   1208			return -1;
   1209		}
   1210	}
   1211
   1212	/* Full feature detection requires specific privileges.
   1213	 * Let's approximate, and warn if user is not root.
   1214	 */
   1215	if (handle_perms())
   1216		return -1;
   1217
   1218	if (json_output) {
   1219		define_prefix = NULL;
   1220		jsonw_start_object(json_wtr);
   1221	}
   1222
   1223	section_system_config(target, define_prefix);
   1224	if (!section_syscall_config(define_prefix))
   1225		/* bpf() syscall unavailable, don't probe other BPF features */
   1226		goto exit_close_json;
   1227	section_program_types(supported_types, define_prefix, ifindex);
   1228	section_map_types(define_prefix, ifindex);
   1229	section_helpers(supported_types, define_prefix, ifindex);
   1230	section_misc(define_prefix, ifindex);
   1231
   1232exit_close_json:
   1233	if (json_output)
   1234		/* End root object */
   1235		jsonw_end_object(json_wtr);
   1236
   1237	return 0;
   1238}
   1239
   1240static int do_help(int argc, char **argv)
   1241{
   1242	if (json_output) {
   1243		jsonw_null(json_wtr);
   1244		return 0;
   1245	}
   1246
   1247	fprintf(stderr,
   1248		"Usage: %1$s %2$s probe [COMPONENT] [full] [unprivileged] [macros [prefix PREFIX]]\n"
   1249		"       %1$s %2$s help\n"
   1250		"\n"
   1251		"       COMPONENT := { kernel | dev NAME }\n"
   1252		"       " HELP_SPEC_OPTIONS " }\n"
   1253		"",
   1254		bin_name, argv[-2]);
   1255
   1256	return 0;
   1257}
   1258
   1259static const struct cmd cmds[] = {
   1260	{ "probe",	do_probe },
   1261	{ "help",	do_help },
   1262	{ 0 }
   1263};
   1264
   1265int do_feature(int argc, char **argv)
   1266{
   1267	return cmd_select(cmds, argc, argv, do_help);
   1268}