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

libbpf_probes.c (11995B)


      1// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
      2/* Copyright (c) 2019 Netronome Systems, Inc. */
      3
      4#include <errno.h>
      5#include <fcntl.h>
      6#include <string.h>
      7#include <stdlib.h>
      8#include <unistd.h>
      9#include <net/if.h>
     10#include <sys/utsname.h>
     11
     12#include <linux/btf.h>
     13#include <linux/filter.h>
     14#include <linux/kernel.h>
     15
     16#include "bpf.h"
     17#include "libbpf.h"
     18#include "libbpf_internal.h"
     19
     20static bool grep(const char *buffer, const char *pattern)
     21{
     22	return !!strstr(buffer, pattern);
     23}
     24
     25static int get_vendor_id(int ifindex)
     26{
     27	char ifname[IF_NAMESIZE], path[64], buf[8];
     28	ssize_t len;
     29	int fd;
     30
     31	if (!if_indextoname(ifindex, ifname))
     32		return -1;
     33
     34	snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname);
     35
     36	fd = open(path, O_RDONLY | O_CLOEXEC);
     37	if (fd < 0)
     38		return -1;
     39
     40	len = read(fd, buf, sizeof(buf));
     41	close(fd);
     42	if (len < 0)
     43		return -1;
     44	if (len >= (ssize_t)sizeof(buf))
     45		return -1;
     46	buf[len] = '\0';
     47
     48	return strtol(buf, NULL, 0);
     49}
     50
     51static int probe_prog_load(enum bpf_prog_type prog_type,
     52			   const struct bpf_insn *insns, size_t insns_cnt,
     53			   char *log_buf, size_t log_buf_sz,
     54			   __u32 ifindex)
     55{
     56	LIBBPF_OPTS(bpf_prog_load_opts, opts,
     57		.log_buf = log_buf,
     58		.log_size = log_buf_sz,
     59		.log_level = log_buf ? 1 : 0,
     60		.prog_ifindex = ifindex,
     61	);
     62	int fd, err, exp_err = 0;
     63	const char *exp_msg = NULL;
     64	char buf[4096];
     65
     66	switch (prog_type) {
     67	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
     68		opts.expected_attach_type = BPF_CGROUP_INET4_CONNECT;
     69		break;
     70	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
     71		opts.expected_attach_type = BPF_CGROUP_GETSOCKOPT;
     72		break;
     73	case BPF_PROG_TYPE_SK_LOOKUP:
     74		opts.expected_attach_type = BPF_SK_LOOKUP;
     75		break;
     76	case BPF_PROG_TYPE_KPROBE:
     77		opts.kern_version = get_kernel_version();
     78		break;
     79	case BPF_PROG_TYPE_LIRC_MODE2:
     80		opts.expected_attach_type = BPF_LIRC_MODE2;
     81		break;
     82	case BPF_PROG_TYPE_TRACING:
     83	case BPF_PROG_TYPE_LSM:
     84		opts.log_buf = buf;
     85		opts.log_size = sizeof(buf);
     86		opts.log_level = 1;
     87		if (prog_type == BPF_PROG_TYPE_TRACING)
     88			opts.expected_attach_type = BPF_TRACE_FENTRY;
     89		else
     90			opts.expected_attach_type = BPF_MODIFY_RETURN;
     91		opts.attach_btf_id = 1;
     92
     93		exp_err = -EINVAL;
     94		exp_msg = "attach_btf_id 1 is not a function";
     95		break;
     96	case BPF_PROG_TYPE_EXT:
     97		opts.log_buf = buf;
     98		opts.log_size = sizeof(buf);
     99		opts.log_level = 1;
    100		opts.attach_btf_id = 1;
    101
    102		exp_err = -EINVAL;
    103		exp_msg = "Cannot replace kernel functions";
    104		break;
    105	case BPF_PROG_TYPE_SYSCALL:
    106		opts.prog_flags = BPF_F_SLEEPABLE;
    107		break;
    108	case BPF_PROG_TYPE_STRUCT_OPS:
    109		exp_err = -524; /* -ENOTSUPP */
    110		break;
    111	case BPF_PROG_TYPE_UNSPEC:
    112	case BPF_PROG_TYPE_SOCKET_FILTER:
    113	case BPF_PROG_TYPE_SCHED_CLS:
    114	case BPF_PROG_TYPE_SCHED_ACT:
    115	case BPF_PROG_TYPE_TRACEPOINT:
    116	case BPF_PROG_TYPE_XDP:
    117	case BPF_PROG_TYPE_PERF_EVENT:
    118	case BPF_PROG_TYPE_CGROUP_SKB:
    119	case BPF_PROG_TYPE_CGROUP_SOCK:
    120	case BPF_PROG_TYPE_LWT_IN:
    121	case BPF_PROG_TYPE_LWT_OUT:
    122	case BPF_PROG_TYPE_LWT_XMIT:
    123	case BPF_PROG_TYPE_SOCK_OPS:
    124	case BPF_PROG_TYPE_SK_SKB:
    125	case BPF_PROG_TYPE_CGROUP_DEVICE:
    126	case BPF_PROG_TYPE_SK_MSG:
    127	case BPF_PROG_TYPE_RAW_TRACEPOINT:
    128	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
    129	case BPF_PROG_TYPE_LWT_SEG6LOCAL:
    130	case BPF_PROG_TYPE_SK_REUSEPORT:
    131	case BPF_PROG_TYPE_FLOW_DISSECTOR:
    132	case BPF_PROG_TYPE_CGROUP_SYSCTL:
    133		break;
    134	default:
    135		return -EOPNOTSUPP;
    136	}
    137
    138	fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insns_cnt, &opts);
    139	err = -errno;
    140	if (fd >= 0)
    141		close(fd);
    142	if (exp_err) {
    143		if (fd >= 0 || err != exp_err)
    144			return 0;
    145		if (exp_msg && !strstr(buf, exp_msg))
    146			return 0;
    147		return 1;
    148	}
    149	return fd >= 0 ? 1 : 0;
    150}
    151
    152int libbpf_probe_bpf_prog_type(enum bpf_prog_type prog_type, const void *opts)
    153{
    154	struct bpf_insn insns[] = {
    155		BPF_MOV64_IMM(BPF_REG_0, 0),
    156		BPF_EXIT_INSN()
    157	};
    158	const size_t insn_cnt = ARRAY_SIZE(insns);
    159	int ret;
    160
    161	if (opts)
    162		return libbpf_err(-EINVAL);
    163
    164	ret = probe_prog_load(prog_type, insns, insn_cnt, NULL, 0, 0);
    165	return libbpf_err(ret);
    166}
    167
    168bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex)
    169{
    170	struct bpf_insn insns[2] = {
    171		BPF_MOV64_IMM(BPF_REG_0, 0),
    172		BPF_EXIT_INSN()
    173	};
    174
    175	/* prefer libbpf_probe_bpf_prog_type() unless offload is requested */
    176	if (ifindex == 0)
    177		return libbpf_probe_bpf_prog_type(prog_type, NULL) == 1;
    178
    179	if (ifindex && prog_type == BPF_PROG_TYPE_SCHED_CLS)
    180		/* nfp returns -EINVAL on exit(0) with TC offload */
    181		insns[0].imm = 2;
    182
    183	errno = 0;
    184	probe_prog_load(prog_type, insns, ARRAY_SIZE(insns), NULL, 0, ifindex);
    185
    186	return errno != EINVAL && errno != EOPNOTSUPP;
    187}
    188
    189int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
    190			 const char *str_sec, size_t str_len)
    191{
    192	struct btf_header hdr = {
    193		.magic = BTF_MAGIC,
    194		.version = BTF_VERSION,
    195		.hdr_len = sizeof(struct btf_header),
    196		.type_len = types_len,
    197		.str_off = types_len,
    198		.str_len = str_len,
    199	};
    200	int btf_fd, btf_len;
    201	__u8 *raw_btf;
    202
    203	btf_len = hdr.hdr_len + hdr.type_len + hdr.str_len;
    204	raw_btf = malloc(btf_len);
    205	if (!raw_btf)
    206		return -ENOMEM;
    207
    208	memcpy(raw_btf, &hdr, sizeof(hdr));
    209	memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len);
    210	memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len);
    211
    212	btf_fd = bpf_btf_load(raw_btf, btf_len, NULL);
    213
    214	free(raw_btf);
    215	return btf_fd;
    216}
    217
    218static int load_local_storage_btf(void)
    219{
    220	const char strs[] = "\0bpf_spin_lock\0val\0cnt\0l";
    221	/* struct bpf_spin_lock {
    222	 *   int val;
    223	 * };
    224	 * struct val {
    225	 *   int cnt;
    226	 *   struct bpf_spin_lock l;
    227	 * };
    228	 */
    229	__u32 types[] = {
    230		/* int */
    231		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
    232		/* struct bpf_spin_lock */                      /* [2] */
    233		BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 4),
    234		BTF_MEMBER_ENC(15, 1, 0), /* int val; */
    235		/* struct val */                                /* [3] */
    236		BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8),
    237		BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */
    238		BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
    239	};
    240
    241	return libbpf__load_raw_btf((char *)types, sizeof(types),
    242				     strs, sizeof(strs));
    243}
    244
    245static int probe_map_create(enum bpf_map_type map_type, __u32 ifindex)
    246{
    247	LIBBPF_OPTS(bpf_map_create_opts, opts);
    248	int key_size, value_size, max_entries;
    249	__u32 btf_key_type_id = 0, btf_value_type_id = 0;
    250	int fd = -1, btf_fd = -1, fd_inner = -1, exp_err = 0, err;
    251
    252	opts.map_ifindex = ifindex;
    253
    254	key_size	= sizeof(__u32);
    255	value_size	= sizeof(__u32);
    256	max_entries	= 1;
    257
    258	switch (map_type) {
    259	case BPF_MAP_TYPE_STACK_TRACE:
    260		value_size	= sizeof(__u64);
    261		break;
    262	case BPF_MAP_TYPE_LPM_TRIE:
    263		key_size	= sizeof(__u64);
    264		value_size	= sizeof(__u64);
    265		opts.map_flags	= BPF_F_NO_PREALLOC;
    266		break;
    267	case BPF_MAP_TYPE_CGROUP_STORAGE:
    268	case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
    269		key_size	= sizeof(struct bpf_cgroup_storage_key);
    270		value_size	= sizeof(__u64);
    271		max_entries	= 0;
    272		break;
    273	case BPF_MAP_TYPE_QUEUE:
    274	case BPF_MAP_TYPE_STACK:
    275		key_size	= 0;
    276		break;
    277	case BPF_MAP_TYPE_SK_STORAGE:
    278	case BPF_MAP_TYPE_INODE_STORAGE:
    279	case BPF_MAP_TYPE_TASK_STORAGE:
    280		btf_key_type_id = 1;
    281		btf_value_type_id = 3;
    282		value_size = 8;
    283		max_entries = 0;
    284		opts.map_flags = BPF_F_NO_PREALLOC;
    285		btf_fd = load_local_storage_btf();
    286		if (btf_fd < 0)
    287			return btf_fd;
    288		break;
    289	case BPF_MAP_TYPE_RINGBUF:
    290		key_size = 0;
    291		value_size = 0;
    292		max_entries = 4096;
    293		break;
    294	case BPF_MAP_TYPE_STRUCT_OPS:
    295		/* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */
    296		opts.btf_vmlinux_value_type_id = 1;
    297		exp_err = -524; /* -ENOTSUPP */
    298		break;
    299	case BPF_MAP_TYPE_BLOOM_FILTER:
    300		key_size = 0;
    301		max_entries = 1;
    302		break;
    303	case BPF_MAP_TYPE_HASH:
    304	case BPF_MAP_TYPE_ARRAY:
    305	case BPF_MAP_TYPE_PROG_ARRAY:
    306	case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
    307	case BPF_MAP_TYPE_PERCPU_HASH:
    308	case BPF_MAP_TYPE_PERCPU_ARRAY:
    309	case BPF_MAP_TYPE_CGROUP_ARRAY:
    310	case BPF_MAP_TYPE_LRU_HASH:
    311	case BPF_MAP_TYPE_LRU_PERCPU_HASH:
    312	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
    313	case BPF_MAP_TYPE_HASH_OF_MAPS:
    314	case BPF_MAP_TYPE_DEVMAP:
    315	case BPF_MAP_TYPE_DEVMAP_HASH:
    316	case BPF_MAP_TYPE_SOCKMAP:
    317	case BPF_MAP_TYPE_CPUMAP:
    318	case BPF_MAP_TYPE_XSKMAP:
    319	case BPF_MAP_TYPE_SOCKHASH:
    320	case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
    321		break;
    322	case BPF_MAP_TYPE_UNSPEC:
    323	default:
    324		return -EOPNOTSUPP;
    325	}
    326
    327	if (map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
    328	    map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
    329		/* TODO: probe for device, once libbpf has a function to create
    330		 * map-in-map for offload
    331		 */
    332		if (ifindex)
    333			goto cleanup;
    334
    335		fd_inner = bpf_map_create(BPF_MAP_TYPE_HASH, NULL,
    336					  sizeof(__u32), sizeof(__u32), 1, NULL);
    337		if (fd_inner < 0)
    338			goto cleanup;
    339
    340		opts.inner_map_fd = fd_inner;
    341	}
    342
    343	if (btf_fd >= 0) {
    344		opts.btf_fd = btf_fd;
    345		opts.btf_key_type_id = btf_key_type_id;
    346		opts.btf_value_type_id = btf_value_type_id;
    347	}
    348
    349	fd = bpf_map_create(map_type, NULL, key_size, value_size, max_entries, &opts);
    350	err = -errno;
    351
    352cleanup:
    353	if (fd >= 0)
    354		close(fd);
    355	if (fd_inner >= 0)
    356		close(fd_inner);
    357	if (btf_fd >= 0)
    358		close(btf_fd);
    359
    360	if (exp_err)
    361		return fd < 0 && err == exp_err ? 1 : 0;
    362	else
    363		return fd >= 0 ? 1 : 0;
    364}
    365
    366int libbpf_probe_bpf_map_type(enum bpf_map_type map_type, const void *opts)
    367{
    368	int ret;
    369
    370	if (opts)
    371		return libbpf_err(-EINVAL);
    372
    373	ret = probe_map_create(map_type, 0);
    374	return libbpf_err(ret);
    375}
    376
    377bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
    378{
    379	return probe_map_create(map_type, ifindex) == 1;
    380}
    381
    382int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type, enum bpf_func_id helper_id,
    383			    const void *opts)
    384{
    385	struct bpf_insn insns[] = {
    386		BPF_EMIT_CALL((__u32)helper_id),
    387		BPF_EXIT_INSN(),
    388	};
    389	const size_t insn_cnt = ARRAY_SIZE(insns);
    390	char buf[4096];
    391	int ret;
    392
    393	if (opts)
    394		return libbpf_err(-EINVAL);
    395
    396	/* we can't successfully load all prog types to check for BPF helper
    397	 * support, so bail out with -EOPNOTSUPP error
    398	 */
    399	switch (prog_type) {
    400	case BPF_PROG_TYPE_TRACING:
    401	case BPF_PROG_TYPE_EXT:
    402	case BPF_PROG_TYPE_LSM:
    403	case BPF_PROG_TYPE_STRUCT_OPS:
    404		return -EOPNOTSUPP;
    405	default:
    406		break;
    407	}
    408
    409	buf[0] = '\0';
    410	ret = probe_prog_load(prog_type, insns, insn_cnt, buf, sizeof(buf), 0);
    411	if (ret < 0)
    412		return libbpf_err(ret);
    413
    414	/* If BPF verifier doesn't recognize BPF helper ID (enum bpf_func_id)
    415	 * at all, it will emit something like "invalid func unknown#181".
    416	 * If BPF verifier recognizes BPF helper but it's not supported for
    417	 * given BPF program type, it will emit "unknown func bpf_sys_bpf#166".
    418	 * In both cases, provided combination of BPF program type and BPF
    419	 * helper is not supported by the kernel.
    420	 * In all other cases, probe_prog_load() above will either succeed (e.g.,
    421	 * because BPF helper happens to accept no input arguments or it
    422	 * accepts one input argument and initial PTR_TO_CTX is fine for
    423	 * that), or we'll get some more specific BPF verifier error about
    424	 * some unsatisfied conditions.
    425	 */
    426	if (ret == 0 && (strstr(buf, "invalid func ") || strstr(buf, "unknown func ")))
    427		return 0;
    428	return 1; /* assume supported */
    429}
    430
    431bool bpf_probe_helper(enum bpf_func_id id, enum bpf_prog_type prog_type,
    432		      __u32 ifindex)
    433{
    434	struct bpf_insn insns[2] = {
    435		BPF_EMIT_CALL(id),
    436		BPF_EXIT_INSN()
    437	};
    438	char buf[4096] = {};
    439	bool res;
    440
    441	probe_prog_load(prog_type, insns, ARRAY_SIZE(insns), buf, sizeof(buf), ifindex);
    442	res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
    443
    444	if (ifindex) {
    445		switch (get_vendor_id(ifindex)) {
    446		case 0x19ee: /* Netronome specific */
    447			res = res && !grep(buf, "not supported by FW") &&
    448				!grep(buf, "unsupported function id");
    449			break;
    450		default:
    451			break;
    452		}
    453	}
    454
    455	return res;
    456}
    457
    458/*
    459 * Probe for availability of kernel commit (5.3):
    460 *
    461 * c04c0d2b968a ("bpf: increase complexity limit and maximum program size")
    462 */
    463bool bpf_probe_large_insn_limit(__u32 ifindex)
    464{
    465	struct bpf_insn insns[BPF_MAXINSNS + 1];
    466	int i;
    467
    468	for (i = 0; i < BPF_MAXINSNS; i++)
    469		insns[i] = BPF_MOV64_IMM(BPF_REG_0, 1);
    470	insns[BPF_MAXINSNS] = BPF_EXIT_INSN();
    471
    472	errno = 0;
    473	probe_prog_load(BPF_PROG_TYPE_SCHED_CLS, insns, ARRAY_SIZE(insns), NULL, 0,
    474			ifindex);
    475
    476	return errno != E2BIG && errno != EINVAL;
    477}