466 lines · c
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#include <linux/version.h>16 17#include "bpf.h"18#include "libbpf.h"19#include "libbpf_internal.h"20 21/* On Ubuntu LINUX_VERSION_CODE doesn't correspond to info.release,22 * but Ubuntu provides /proc/version_signature file, as described at23 * https://ubuntu.com/kernel, with an example contents below, which we24 * can use to get a proper LINUX_VERSION_CODE.25 *26 * Ubuntu 5.4.0-12.15-generic 5.4.827 *28 * In the above, 5.4.8 is what kernel is actually expecting, while29 * uname() call will return 5.4.0 in info.release.30 */31static __u32 get_ubuntu_kernel_version(void)32{33 const char *ubuntu_kver_file = "/proc/version_signature";34 __u32 major, minor, patch;35 int ret;36 FILE *f;37 38 if (faccessat(AT_FDCWD, ubuntu_kver_file, R_OK, AT_EACCESS) != 0)39 return 0;40 41 f = fopen(ubuntu_kver_file, "re");42 if (!f)43 return 0;44 45 ret = fscanf(f, "%*s %*s %u.%u.%u\n", &major, &minor, &patch);46 fclose(f);47 if (ret != 3)48 return 0;49 50 return KERNEL_VERSION(major, minor, patch);51}52 53/* On Debian LINUX_VERSION_CODE doesn't correspond to info.release.54 * Instead, it is provided in info.version. An example content of55 * Debian 10 looks like the below.56 *57 * utsname::release 4.19.0-22-amd6458 * utsname::version #1 SMP Debian 4.19.260-1 (2022-09-29)59 *60 * In the above, 4.19.260 is what kernel is actually expecting, while61 * uname() call will return 4.19.0 in info.release.62 */63static __u32 get_debian_kernel_version(struct utsname *info)64{65 __u32 major, minor, patch;66 char *p;67 68 p = strstr(info->version, "Debian ");69 if (!p) {70 /* This is not a Debian kernel. */71 return 0;72 }73 74 if (sscanf(p, "Debian %u.%u.%u", &major, &minor, &patch) != 3)75 return 0;76 77 return KERNEL_VERSION(major, minor, patch);78}79 80__u32 get_kernel_version(void)81{82 __u32 major, minor, patch, version;83 struct utsname info;84 85 /* Check if this is an Ubuntu kernel. */86 version = get_ubuntu_kernel_version();87 if (version != 0)88 return version;89 90 uname(&info);91 92 /* Check if this is a Debian kernel. */93 version = get_debian_kernel_version(&info);94 if (version != 0)95 return version;96 97 if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)98 return 0;99 100 return KERNEL_VERSION(major, minor, patch);101}102 103static int probe_prog_load(enum bpf_prog_type prog_type,104 const struct bpf_insn *insns, size_t insns_cnt,105 char *log_buf, size_t log_buf_sz)106{107 LIBBPF_OPTS(bpf_prog_load_opts, opts,108 .log_buf = log_buf,109 .log_size = log_buf_sz,110 .log_level = log_buf ? 1 : 0,111 );112 int fd, err, exp_err = 0;113 const char *exp_msg = NULL;114 char buf[4096];115 116 switch (prog_type) {117 case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:118 opts.expected_attach_type = BPF_CGROUP_INET4_CONNECT;119 break;120 case BPF_PROG_TYPE_CGROUP_SOCKOPT:121 opts.expected_attach_type = BPF_CGROUP_GETSOCKOPT;122 break;123 case BPF_PROG_TYPE_SK_LOOKUP:124 opts.expected_attach_type = BPF_SK_LOOKUP;125 break;126 case BPF_PROG_TYPE_KPROBE:127 opts.kern_version = get_kernel_version();128 break;129 case BPF_PROG_TYPE_LIRC_MODE2:130 opts.expected_attach_type = BPF_LIRC_MODE2;131 break;132 case BPF_PROG_TYPE_TRACING:133 case BPF_PROG_TYPE_LSM:134 opts.log_buf = buf;135 opts.log_size = sizeof(buf);136 opts.log_level = 1;137 if (prog_type == BPF_PROG_TYPE_TRACING)138 opts.expected_attach_type = BPF_TRACE_FENTRY;139 else140 opts.expected_attach_type = BPF_MODIFY_RETURN;141 opts.attach_btf_id = 1;142 143 exp_err = -EINVAL;144 exp_msg = "attach_btf_id 1 is not a function";145 break;146 case BPF_PROG_TYPE_EXT:147 opts.log_buf = buf;148 opts.log_size = sizeof(buf);149 opts.log_level = 1;150 opts.attach_btf_id = 1;151 152 exp_err = -EINVAL;153 exp_msg = "Cannot replace kernel functions";154 break;155 case BPF_PROG_TYPE_SYSCALL:156 opts.prog_flags = BPF_F_SLEEPABLE;157 break;158 case BPF_PROG_TYPE_STRUCT_OPS:159 exp_err = -524; /* -ENOTSUPP */160 break;161 case BPF_PROG_TYPE_UNSPEC:162 case BPF_PROG_TYPE_SOCKET_FILTER:163 case BPF_PROG_TYPE_SCHED_CLS:164 case BPF_PROG_TYPE_SCHED_ACT:165 case BPF_PROG_TYPE_TRACEPOINT:166 case BPF_PROG_TYPE_XDP:167 case BPF_PROG_TYPE_PERF_EVENT:168 case BPF_PROG_TYPE_CGROUP_SKB:169 case BPF_PROG_TYPE_CGROUP_SOCK:170 case BPF_PROG_TYPE_LWT_IN:171 case BPF_PROG_TYPE_LWT_OUT:172 case BPF_PROG_TYPE_LWT_XMIT:173 case BPF_PROG_TYPE_SOCK_OPS:174 case BPF_PROG_TYPE_SK_SKB:175 case BPF_PROG_TYPE_CGROUP_DEVICE:176 case BPF_PROG_TYPE_SK_MSG:177 case BPF_PROG_TYPE_RAW_TRACEPOINT:178 case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:179 case BPF_PROG_TYPE_LWT_SEG6LOCAL:180 case BPF_PROG_TYPE_SK_REUSEPORT:181 case BPF_PROG_TYPE_FLOW_DISSECTOR:182 case BPF_PROG_TYPE_CGROUP_SYSCTL:183 break;184 case BPF_PROG_TYPE_NETFILTER:185 opts.expected_attach_type = BPF_NETFILTER;186 break;187 default:188 return -EOPNOTSUPP;189 }190 191 fd = bpf_prog_load(prog_type, NULL, "GPL", insns, insns_cnt, &opts);192 err = -errno;193 if (fd >= 0)194 close(fd);195 if (exp_err) {196 if (fd >= 0 || err != exp_err)197 return 0;198 if (exp_msg && !strstr(buf, exp_msg))199 return 0;200 return 1;201 }202 return fd >= 0 ? 1 : 0;203}204 205int libbpf_probe_bpf_prog_type(enum bpf_prog_type prog_type, const void *opts)206{207 struct bpf_insn insns[] = {208 BPF_MOV64_IMM(BPF_REG_0, 0),209 BPF_EXIT_INSN()210 };211 const size_t insn_cnt = ARRAY_SIZE(insns);212 int ret;213 214 if (opts)215 return libbpf_err(-EINVAL);216 217 ret = probe_prog_load(prog_type, insns, insn_cnt, NULL, 0);218 return libbpf_err(ret);219}220 221int libbpf__load_raw_btf(const char *raw_types, size_t types_len,222 const char *str_sec, size_t str_len,223 int token_fd)224{225 struct btf_header hdr = {226 .magic = BTF_MAGIC,227 .version = BTF_VERSION,228 .hdr_len = sizeof(struct btf_header),229 .type_len = types_len,230 .str_off = types_len,231 .str_len = str_len,232 };233 LIBBPF_OPTS(bpf_btf_load_opts, opts,234 .token_fd = token_fd,235 .btf_flags = token_fd ? BPF_F_TOKEN_FD : 0,236 );237 int btf_fd, btf_len;238 __u8 *raw_btf;239 240 btf_len = hdr.hdr_len + hdr.type_len + hdr.str_len;241 raw_btf = malloc(btf_len);242 if (!raw_btf)243 return -ENOMEM;244 245 memcpy(raw_btf, &hdr, sizeof(hdr));246 memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len);247 memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len);248 249 btf_fd = bpf_btf_load(raw_btf, btf_len, &opts);250 251 free(raw_btf);252 return btf_fd;253}254 255static int load_local_storage_btf(void)256{257 const char strs[] = "\0bpf_spin_lock\0val\0cnt\0l";258 /* struct bpf_spin_lock {259 * int val;260 * };261 * struct val {262 * int cnt;263 * struct bpf_spin_lock l;264 * };265 */266 __u32 types[] = {267 /* int */268 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */269 /* struct bpf_spin_lock */ /* [2] */270 BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 4),271 BTF_MEMBER_ENC(15, 1, 0), /* int val; */272 /* struct val */ /* [3] */273 BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8),274 BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */275 BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */276 };277 278 return libbpf__load_raw_btf((char *)types, sizeof(types),279 strs, sizeof(strs), 0);280}281 282static int probe_map_create(enum bpf_map_type map_type)283{284 LIBBPF_OPTS(bpf_map_create_opts, opts);285 int key_size, value_size, max_entries;286 __u32 btf_key_type_id = 0, btf_value_type_id = 0;287 int fd = -1, btf_fd = -1, fd_inner = -1, exp_err = 0, err = 0;288 289 key_size = sizeof(__u32);290 value_size = sizeof(__u32);291 max_entries = 1;292 293 switch (map_type) {294 case BPF_MAP_TYPE_STACK_TRACE:295 value_size = sizeof(__u64);296 break;297 case BPF_MAP_TYPE_LPM_TRIE:298 key_size = sizeof(__u64);299 value_size = sizeof(__u64);300 opts.map_flags = BPF_F_NO_PREALLOC;301 break;302 case BPF_MAP_TYPE_CGROUP_STORAGE:303 case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:304 key_size = sizeof(struct bpf_cgroup_storage_key);305 value_size = sizeof(__u64);306 max_entries = 0;307 break;308 case BPF_MAP_TYPE_QUEUE:309 case BPF_MAP_TYPE_STACK:310 key_size = 0;311 break;312 case BPF_MAP_TYPE_SK_STORAGE:313 case BPF_MAP_TYPE_INODE_STORAGE:314 case BPF_MAP_TYPE_TASK_STORAGE:315 case BPF_MAP_TYPE_CGRP_STORAGE:316 btf_key_type_id = 1;317 btf_value_type_id = 3;318 value_size = 8;319 max_entries = 0;320 opts.map_flags = BPF_F_NO_PREALLOC;321 btf_fd = load_local_storage_btf();322 if (btf_fd < 0)323 return btf_fd;324 break;325 case BPF_MAP_TYPE_RINGBUF:326 case BPF_MAP_TYPE_USER_RINGBUF:327 key_size = 0;328 value_size = 0;329 max_entries = sysconf(_SC_PAGE_SIZE);330 break;331 case BPF_MAP_TYPE_STRUCT_OPS:332 /* we'll get -ENOTSUPP for invalid BTF type ID for struct_ops */333 opts.btf_vmlinux_value_type_id = 1;334 opts.value_type_btf_obj_fd = -1;335 exp_err = -524; /* -ENOTSUPP */336 break;337 case BPF_MAP_TYPE_BLOOM_FILTER:338 key_size = 0;339 max_entries = 1;340 break;341 case BPF_MAP_TYPE_ARENA:342 key_size = 0;343 value_size = 0;344 max_entries = 1; /* one page */345 opts.map_extra = 0; /* can mmap() at any address */346 opts.map_flags = BPF_F_MMAPABLE;347 break;348 case BPF_MAP_TYPE_HASH:349 case BPF_MAP_TYPE_ARRAY:350 case BPF_MAP_TYPE_PROG_ARRAY:351 case BPF_MAP_TYPE_PERF_EVENT_ARRAY:352 case BPF_MAP_TYPE_PERCPU_HASH:353 case BPF_MAP_TYPE_PERCPU_ARRAY:354 case BPF_MAP_TYPE_CGROUP_ARRAY:355 case BPF_MAP_TYPE_LRU_HASH:356 case BPF_MAP_TYPE_LRU_PERCPU_HASH:357 case BPF_MAP_TYPE_ARRAY_OF_MAPS:358 case BPF_MAP_TYPE_HASH_OF_MAPS:359 case BPF_MAP_TYPE_DEVMAP:360 case BPF_MAP_TYPE_DEVMAP_HASH:361 case BPF_MAP_TYPE_SOCKMAP:362 case BPF_MAP_TYPE_CPUMAP:363 case BPF_MAP_TYPE_XSKMAP:364 case BPF_MAP_TYPE_SOCKHASH:365 case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:366 break;367 case BPF_MAP_TYPE_UNSPEC:368 default:369 return -EOPNOTSUPP;370 }371 372 if (map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||373 map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {374 fd_inner = bpf_map_create(BPF_MAP_TYPE_HASH, NULL,375 sizeof(__u32), sizeof(__u32), 1, NULL);376 if (fd_inner < 0)377 goto cleanup;378 379 opts.inner_map_fd = fd_inner;380 }381 382 if (btf_fd >= 0) {383 opts.btf_fd = btf_fd;384 opts.btf_key_type_id = btf_key_type_id;385 opts.btf_value_type_id = btf_value_type_id;386 }387 388 fd = bpf_map_create(map_type, NULL, key_size, value_size, max_entries, &opts);389 err = -errno;390 391cleanup:392 if (fd >= 0)393 close(fd);394 if (fd_inner >= 0)395 close(fd_inner);396 if (btf_fd >= 0)397 close(btf_fd);398 399 if (exp_err)400 return fd < 0 && err == exp_err ? 1 : 0;401 else402 return fd >= 0 ? 1 : 0;403}404 405int libbpf_probe_bpf_map_type(enum bpf_map_type map_type, const void *opts)406{407 int ret;408 409 if (opts)410 return libbpf_err(-EINVAL);411 412 ret = probe_map_create(map_type);413 return libbpf_err(ret);414}415 416int libbpf_probe_bpf_helper(enum bpf_prog_type prog_type, enum bpf_func_id helper_id,417 const void *opts)418{419 struct bpf_insn insns[] = {420 BPF_EMIT_CALL((__u32)helper_id),421 BPF_EXIT_INSN(),422 };423 const size_t insn_cnt = ARRAY_SIZE(insns);424 char buf[4096];425 int ret;426 427 if (opts)428 return libbpf_err(-EINVAL);429 430 /* we can't successfully load all prog types to check for BPF helper431 * support, so bail out with -EOPNOTSUPP error432 */433 switch (prog_type) {434 case BPF_PROG_TYPE_TRACING:435 case BPF_PROG_TYPE_EXT:436 case BPF_PROG_TYPE_LSM:437 case BPF_PROG_TYPE_STRUCT_OPS:438 return -EOPNOTSUPP;439 default:440 break;441 }442 443 buf[0] = '\0';444 ret = probe_prog_load(prog_type, insns, insn_cnt, buf, sizeof(buf));445 if (ret < 0)446 return libbpf_err(ret);447 448 /* If BPF verifier doesn't recognize BPF helper ID (enum bpf_func_id)449 * at all, it will emit something like "invalid func unknown#181".450 * If BPF verifier recognizes BPF helper but it's not supported for451 * given BPF program type, it will emit "unknown func bpf_sys_bpf#166"452 * or "program of this type cannot use helper bpf_sys_bpf#166".453 * In both cases, provided combination of BPF program type and BPF454 * helper is not supported by the kernel.455 * In all other cases, probe_prog_load() above will either succeed (e.g.,456 * because BPF helper happens to accept no input arguments or it457 * accepts one input argument and initial PTR_TO_CTX is fine for458 * that), or we'll get some more specific BPF verifier error about459 * some unsatisfied conditions.460 */461 if (ret == 0 && (strstr(buf, "invalid func ") || strstr(buf, "unknown func ") ||462 strstr(buf, "program of this type cannot use helper ")))463 return 0;464 return 1; /* assume supported */465}466