15223 lines · 408.0 KB · C
RawDownload
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* * Common eBPF ELF object loading operations. * * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> * Copyright (C) 2015 Huawei Inc. * Copyright (C) 2017 Nicira, Inc. * Copyright (C) 2019 Isovalent, Inc. */ #ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <libgen.h>#include <inttypes.h>#include <limits.h>#include <string.h>#include <unistd.h>#include <endian.h>#include <fcntl.h>#include <errno.h>#include <ctype.h>#include <asm/unistd.h>#include <linux/err.h>#include <linux/kernel.h>#include <linux/bpf.h>#include <linux/btf.h>#include <linux/filter.h>#include <linux/limits.h>#include <linux/perf_event.h>#include <linux/bpf_perf_event.h>#include <linux/ring_buffer.h>#include <sys/epoll.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/vfs.h>#include <sys/utsname.h>#include <sys/resource.h>#include <libelf.h>#include <gelf.h>#include <zlib.h> #include "libbpf.h"#include "bpf.h"#include "btf.h"#include "libbpf_internal.h"#include "hashmap.h"#include "bpf_gen_internal.h"#include "zip.h" #ifndef BPF_FS_MAGIC#define BPF_FS_MAGIC		0xcafe4a11#endif #define MAX_EVENT_NAME_LEN	64 #define BPF_FS_DEFAULT_PATH "/sys/fs/bpf" #define BPF_INSN_SZ (sizeof(struct bpf_insn)) /* vsprintf() in __base_pr() uses nonliteral format string. It may break * compilation if user enables corresponding warning. Disable it explicitly. */#pragma GCC diagnostic ignored "-Wformat-nonliteral" #define __printf(a, b)	__attribute__((format(printf, a, b))) static struct bpf_map *bpf_object__add_map(struct bpf_object *obj);static bool prog_is_subprog(const struct bpf_object *obj, const struct bpf_program *prog);static int map_set_def_max_entries(struct bpf_map *map); static const char * const attach_type_name[] = {	[BPF_CGROUP_INET_INGRESS]	= "cgroup_inet_ingress",	[BPF_CGROUP_INET_EGRESS]	= "cgroup_inet_egress",	[BPF_CGROUP_INET_SOCK_CREATE]	= "cgroup_inet_sock_create",	[BPF_CGROUP_INET_SOCK_RELEASE]	= "cgroup_inet_sock_release",	[BPF_CGROUP_SOCK_OPS]		= "cgroup_sock_ops",	[BPF_CGROUP_DEVICE]		= "cgroup_device",	[BPF_CGROUP_INET4_BIND]		= "cgroup_inet4_bind",	[BPF_CGROUP_INET6_BIND]		= "cgroup_inet6_bind",	[BPF_CGROUP_INET4_CONNECT]	= "cgroup_inet4_connect",	[BPF_CGROUP_INET6_CONNECT]	= "cgroup_inet6_connect",	[BPF_CGROUP_UNIX_CONNECT]       = "cgroup_unix_connect",	[BPF_CGROUP_INET4_POST_BIND]	= "cgroup_inet4_post_bind",	[BPF_CGROUP_INET6_POST_BIND]	= "cgroup_inet6_post_bind",	[BPF_CGROUP_INET4_GETPEERNAME]	= "cgroup_inet4_getpeername",	[BPF_CGROUP_INET6_GETPEERNAME]	= "cgroup_inet6_getpeername",	[BPF_CGROUP_UNIX_GETPEERNAME]	= "cgroup_unix_getpeername",	[BPF_CGROUP_INET4_GETSOCKNAME]	= "cgroup_inet4_getsockname",	[BPF_CGROUP_INET6_GETSOCKNAME]	= "cgroup_inet6_getsockname",	[BPF_CGROUP_UNIX_GETSOCKNAME]	= "cgroup_unix_getsockname",	[BPF_CGROUP_UDP4_SENDMSG]	= "cgroup_udp4_sendmsg",	[BPF_CGROUP_UDP6_SENDMSG]	= "cgroup_udp6_sendmsg",	[BPF_CGROUP_UNIX_SENDMSG]	= "cgroup_unix_sendmsg",	[BPF_CGROUP_SYSCTL]		= "cgroup_sysctl",	[BPF_CGROUP_UDP4_RECVMSG]	= "cgroup_udp4_recvmsg",	[BPF_CGROUP_UDP6_RECVMSG]	= "cgroup_udp6_recvmsg",	[BPF_CGROUP_UNIX_RECVMSG]	= "cgroup_unix_recvmsg",	[BPF_CGROUP_GETSOCKOPT]		= "cgroup_getsockopt",	[BPF_CGROUP_SETSOCKOPT]		= "cgroup_setsockopt",	[BPF_SK_SKB_STREAM_PARSER]	= "sk_skb_stream_parser",	[BPF_SK_SKB_STREAM_VERDICT]	= "sk_skb_stream_verdict",	[BPF_SK_SKB_VERDICT]		= "sk_skb_verdict",	[BPF_SK_MSG_VERDICT]		= "sk_msg_verdict",	[BPF_LIRC_MODE2]		= "lirc_mode2",	[BPF_FLOW_DISSECTOR]		= "flow_dissector",	[BPF_TRACE_RAW_TP]		= "trace_raw_tp",	[BPF_TRACE_FENTRY]		= "trace_fentry",	[BPF_TRACE_FEXIT]		= "trace_fexit",	[BPF_MODIFY_RETURN]		= "modify_return",	[BPF_TRACE_FSESSION]		= "trace_fsession",	[BPF_LSM_MAC]			= "lsm_mac",	[BPF_LSM_CGROUP]		= "lsm_cgroup",	[BPF_SK_LOOKUP]			= "sk_lookup",	[BPF_TRACE_ITER]		= "trace_iter",	[BPF_XDP_DEVMAP]		= "xdp_devmap",	[BPF_XDP_CPUMAP]		= "xdp_cpumap",	[BPF_XDP]			= "xdp",	[BPF_SK_REUSEPORT_SELECT]	= "sk_reuseport_select",	[BPF_SK_REUSEPORT_SELECT_OR_MIGRATE]	= "sk_reuseport_select_or_migrate",	[BPF_PERF_EVENT]		= "perf_event",	[BPF_TRACE_KPROBE_MULTI]	= "trace_kprobe_multi",	[BPF_STRUCT_OPS]		= "struct_ops",	[BPF_NETFILTER]			= "netfilter",	[BPF_TCX_INGRESS]		= "tcx_ingress",	[BPF_TCX_EGRESS]		= "tcx_egress",	[BPF_TRACE_UPROBE_MULTI]	= "trace_uprobe_multi",	[BPF_NETKIT_PRIMARY]		= "netkit_primary",	[BPF_NETKIT_PEER]		= "netkit_peer",	[BPF_TRACE_KPROBE_SESSION]	= "trace_kprobe_session",	[BPF_TRACE_UPROBE_SESSION]	= "trace_uprobe_session",	[BPF_TRACE_FENTRY_MULTI]	= "trace_fentry_multi",	[BPF_TRACE_FEXIT_MULTI]		= "trace_fexit_multi",	[BPF_TRACE_FSESSION_MULTI]	= "trace_fsession_multi",}; static const char * const link_type_name[] = {	[BPF_LINK_TYPE_UNSPEC]			= "unspec",	[BPF_LINK_TYPE_RAW_TRACEPOINT]		= "raw_tracepoint",	[BPF_LINK_TYPE_TRACING]			= "tracing",	[BPF_LINK_TYPE_CGROUP]			= "cgroup",	[BPF_LINK_TYPE_ITER]			= "iter",	[BPF_LINK_TYPE_NETNS]			= "netns",	[BPF_LINK_TYPE_XDP]			= "xdp",	[BPF_LINK_TYPE_PERF_EVENT]		= "perf_event",	[BPF_LINK_TYPE_KPROBE_MULTI]		= "kprobe_multi",	[BPF_LINK_TYPE_STRUCT_OPS]		= "struct_ops",	[BPF_LINK_TYPE_NETFILTER]		= "netfilter",	[BPF_LINK_TYPE_TCX]			= "tcx",	[BPF_LINK_TYPE_UPROBE_MULTI]		= "uprobe_multi",	[BPF_LINK_TYPE_NETKIT]			= "netkit",	[BPF_LINK_TYPE_SOCKMAP]			= "sockmap",	[BPF_LINK_TYPE_TRACING_MULTI]		= "tracing_multi",}; static const char * const map_type_name[] = {	[BPF_MAP_TYPE_UNSPEC]			= "unspec",	[BPF_MAP_TYPE_HASH]			= "hash",	[BPF_MAP_TYPE_ARRAY]			= "array",	[BPF_MAP_TYPE_PROG_ARRAY]		= "prog_array",	[BPF_MAP_TYPE_PERF_EVENT_ARRAY]		= "perf_event_array",	[BPF_MAP_TYPE_PERCPU_HASH]		= "percpu_hash",	[BPF_MAP_TYPE_PERCPU_ARRAY]		= "percpu_array",	[BPF_MAP_TYPE_STACK_TRACE]		= "stack_trace",	[BPF_MAP_TYPE_CGROUP_ARRAY]		= "cgroup_array",	[BPF_MAP_TYPE_LRU_HASH]			= "lru_hash",	[BPF_MAP_TYPE_LRU_PERCPU_HASH]		= "lru_percpu_hash",	[BPF_MAP_TYPE_LPM_TRIE]			= "lpm_trie",	[BPF_MAP_TYPE_ARRAY_OF_MAPS]		= "array_of_maps",	[BPF_MAP_TYPE_HASH_OF_MAPS]		= "hash_of_maps",	[BPF_MAP_TYPE_DEVMAP]			= "devmap",	[BPF_MAP_TYPE_DEVMAP_HASH]		= "devmap_hash",	[BPF_MAP_TYPE_SOCKMAP]			= "sockmap",	[BPF_MAP_TYPE_CPUMAP]			= "cpumap",	[BPF_MAP_TYPE_XSKMAP]			= "xskmap",	[BPF_MAP_TYPE_SOCKHASH]			= "sockhash",	[BPF_MAP_TYPE_CGROUP_STORAGE]		= "cgroup_storage",	[BPF_MAP_TYPE_REUSEPORT_SOCKARRAY]	= "reuseport_sockarray",	[BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE]	= "percpu_cgroup_storage",	[BPF_MAP_TYPE_QUEUE]			= "queue",	[BPF_MAP_TYPE_STACK]			= "stack",	[BPF_MAP_TYPE_SK_STORAGE]		= "sk_storage",	[BPF_MAP_TYPE_STRUCT_OPS]		= "struct_ops",	[BPF_MAP_TYPE_RINGBUF]			= "ringbuf",	[BPF_MAP_TYPE_INODE_STORAGE]		= "inode_storage",	[BPF_MAP_TYPE_TASK_STORAGE]		= "task_storage",	[BPF_MAP_TYPE_BLOOM_FILTER]		= "bloom_filter",	[BPF_MAP_TYPE_USER_RINGBUF]             = "user_ringbuf",	[BPF_MAP_TYPE_CGRP_STORAGE]		= "cgrp_storage",	[BPF_MAP_TYPE_ARENA]			= "arena",	[BPF_MAP_TYPE_INSN_ARRAY]		= "insn_array",	[BPF_MAP_TYPE_RHASH]			= "rhash",}; static const char * const prog_type_name[] = {	[BPF_PROG_TYPE_UNSPEC]			= "unspec",	[BPF_PROG_TYPE_SOCKET_FILTER]		= "socket_filter",	[BPF_PROG_TYPE_KPROBE]			= "kprobe",	[BPF_PROG_TYPE_SCHED_CLS]		= "sched_cls",	[BPF_PROG_TYPE_SCHED_ACT]		= "sched_act",	[BPF_PROG_TYPE_TRACEPOINT]		= "tracepoint",	[BPF_PROG_TYPE_XDP]			= "xdp",	[BPF_PROG_TYPE_PERF_EVENT]		= "perf_event",	[BPF_PROG_TYPE_CGROUP_SKB]		= "cgroup_skb",	[BPF_PROG_TYPE_CGROUP_SOCK]		= "cgroup_sock",	[BPF_PROG_TYPE_LWT_IN]			= "lwt_in",	[BPF_PROG_TYPE_LWT_OUT]			= "lwt_out",	[BPF_PROG_TYPE_LWT_XMIT]		= "lwt_xmit",	[BPF_PROG_TYPE_SOCK_OPS]		= "sock_ops",	[BPF_PROG_TYPE_SK_SKB]			= "sk_skb",	[BPF_PROG_TYPE_CGROUP_DEVICE]		= "cgroup_device",	[BPF_PROG_TYPE_SK_MSG]			= "sk_msg",	[BPF_PROG_TYPE_RAW_TRACEPOINT]		= "raw_tracepoint",	[BPF_PROG_TYPE_CGROUP_SOCK_ADDR]	= "cgroup_sock_addr",	[BPF_PROG_TYPE_LWT_SEG6LOCAL]		= "lwt_seg6local",	[BPF_PROG_TYPE_LIRC_MODE2]		= "lirc_mode2",	[BPF_PROG_TYPE_SK_REUSEPORT]		= "sk_reuseport",	[BPF_PROG_TYPE_FLOW_DISSECTOR]		= "flow_dissector",	[BPF_PROG_TYPE_CGROUP_SYSCTL]		= "cgroup_sysctl",	[BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE]	= "raw_tracepoint_writable",	[BPF_PROG_TYPE_CGROUP_SOCKOPT]		= "cgroup_sockopt",	[BPF_PROG_TYPE_TRACING]			= "tracing",	[BPF_PROG_TYPE_STRUCT_OPS]		= "struct_ops",	[BPF_PROG_TYPE_EXT]			= "ext",	[BPF_PROG_TYPE_LSM]			= "lsm",	[BPF_PROG_TYPE_SK_LOOKUP]		= "sk_lookup",	[BPF_PROG_TYPE_SYSCALL]			= "syscall",	[BPF_PROG_TYPE_NETFILTER]		= "netfilter",}; static int __base_pr(enum libbpf_print_level level, const char *format,		     va_list args){	const char *env_var = "LIBBPF_LOG_LEVEL";	static enum libbpf_print_level min_level = LIBBPF_INFO;	static bool initialized; 	if (!initialized) {		char *verbosity; 		initialized = true;		verbosity = getenv(env_var);		if (verbosity) {			if (strcasecmp(verbosity, "warn") == 0)				min_level = LIBBPF_WARN;			else if (strcasecmp(verbosity, "debug") == 0)				min_level = LIBBPF_DEBUG;			else if (strcasecmp(verbosity, "info") == 0)				min_level = LIBBPF_INFO;			else				fprintf(stderr, "libbpf: unrecognized '%s' envvar value: '%s', should be one of 'warn', 'debug', or 'info'.\n",					env_var, verbosity);		}	} 	/* if too verbose, skip logging  */	if (level > min_level)		return 0; 	return vfprintf(stderr, format, args);} static libbpf_print_fn_t __libbpf_pr = __base_pr; libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn){	libbpf_print_fn_t old_print_fn; 	old_print_fn = __atomic_exchange_n(&__libbpf_pr, fn, __ATOMIC_RELAXED); 	return old_print_fn;} __printf(2, 3)void libbpf_print(enum libbpf_print_level level, const char *format, ...){	va_list args;	int old_errno;	libbpf_print_fn_t print_fn; 	print_fn = __atomic_load_n(&__libbpf_pr, __ATOMIC_RELAXED);	if (!print_fn)		return; 	old_errno = errno; 	va_start(args, format);	print_fn(level, format, args);	va_end(args); 	errno = old_errno;} static void pr_perm_msg(int err){	struct rlimit limit;	char buf[100]; 	if (err != -EPERM || geteuid() != 0)		return; 	err = getrlimit(RLIMIT_MEMLOCK, &limit);	if (err)		return; 	if (limit.rlim_cur == RLIM_INFINITY)		return; 	if (limit.rlim_cur < 1024)		snprintf(buf, sizeof(buf), "%zu bytes", (size_t)limit.rlim_cur);	else if (limit.rlim_cur < 1024*1024)		snprintf(buf, sizeof(buf), "%.1f KiB", (double)limit.rlim_cur / 1024);	else		snprintf(buf, sizeof(buf), "%.1f MiB", (double)limit.rlim_cur / (1024*1024)); 	pr_warn("permission error while running as root; try raising 'ulimit -l'? current value: %s\n",		buf);} /* Copied from tools/perf/util/util.h */#ifndef zfree# define zfree(ptr) ({ free(*ptr); *ptr = NULL; })#endif #ifndef zclose# define zclose(fd) ({			\	int ___err = 0;			\	if ((fd) >= 0)			\		___err = close((fd));	\	fd = -1;			\	___err; })#endif static inline __u64 ptr_to_u64(const void *ptr){	return (__u64) (unsigned long) ptr;} int libbpf_set_strict_mode(enum libbpf_strict_mode mode){	/* as of v1.0 libbpf_set_strict_mode() is a no-op */	return 0;} __u32 libbpf_major_version(void){	return LIBBPF_MAJOR_VERSION;} __u32 libbpf_minor_version(void){	return LIBBPF_MINOR_VERSION;} const char *libbpf_version_string(void){#define __S(X) #X#define _S(X) __S(X)	return  "v" _S(LIBBPF_MAJOR_VERSION) "." _S(LIBBPF_MINOR_VERSION);#undef _S#undef __S} enum reloc_type {	RELO_LD64,	RELO_CALL,	RELO_DATA,	RELO_EXTERN_LD64,	RELO_EXTERN_CALL,	RELO_SUBPROG_ADDR,	RELO_CORE,	RELO_INSN_ARRAY,}; struct reloc_desc {	enum reloc_type type;	int insn_idx;	union {		const struct bpf_core_relo *core_relo; /* used when type == RELO_CORE */		struct {			int map_idx;			unsigned int sym_off;			/*			 * The following two fields can be unionized, as the			 * ext_idx field is used for extern symbols, and the			 * sym_size is used for jump tables, which are never			 * extern			 */			union {				int ext_idx;				int sym_size;			};		};	};}; /* stored as sec_def->cookie for all libbpf-supported SEC()s */enum sec_def_flags {	SEC_NONE = 0,	/* expected_attach_type is optional, if kernel doesn't support that */	SEC_EXP_ATTACH_OPT = 1,	/* legacy, only used by libbpf_get_type_names() and	 * libbpf_attach_type_by_name(), not used by libbpf itself at all.	 * This used to be associated with cgroup (and few other) BPF programs	 * that were attachable through BPF_PROG_ATTACH command. Pretty	 * meaningless nowadays, though.	 */	SEC_ATTACHABLE = 2,	SEC_ATTACHABLE_OPT = SEC_ATTACHABLE | SEC_EXP_ATTACH_OPT,	/* attachment target is specified through BTF ID in either kernel or	 * other BPF program's BTF object	 */	SEC_ATTACH_BTF = 4,	/* BPF program type allows sleeping/blocking in kernel */	SEC_SLEEPABLE = 8,	/* BPF program support non-linear XDP buffer */	SEC_XDP_FRAGS = 16,	/* Setup proper attach type for usdt probes. */	SEC_USDT = 32,}; struct bpf_sec_def {	char *sec;	enum bpf_prog_type prog_type;	enum bpf_attach_type expected_attach_type;	long cookie;	int handler_id; 	libbpf_prog_setup_fn_t prog_setup_fn;	libbpf_prog_prepare_load_fn_t prog_prepare_load_fn;	libbpf_prog_attach_fn_t prog_attach_fn;}; struct bpf_light_subprog {	__u32 sec_insn_off;	__u32 sub_insn_off;}; /* * bpf_prog should be a better name but it has been used in * linux/filter.h. */struct bpf_program {	char *name;	char *sec_name;	size_t sec_idx;	const struct bpf_sec_def *sec_def;	/* this program's instruction offset (in number of instructions)	 * within its containing ELF section	 */	size_t sec_insn_off;	/* number of original instructions in ELF section belonging to this	 * program, not taking into account subprogram instructions possible	 * appended later during relocation	 */	size_t sec_insn_cnt;	/* Offset (in number of instructions) of the start of instruction	 * belonging to this BPF program  within its containing main BPF	 * program. For the entry-point (main) BPF program, this is always	 * zero. For a sub-program, this gets reset before each of main BPF	 * programs are processed and relocated and is used to determined	 * whether sub-program was already appended to the main program, and	 * if yes, at which instruction offset.	 */	size_t sub_insn_off; 	/* instructions that belong to BPF program; insns[0] is located at	 * sec_insn_off instruction within its ELF section in ELF file, so	 * when mapping ELF file instruction index to the local instruction,	 * one needs to subtract sec_insn_off; and vice versa.	 */	struct bpf_insn *insns;	/* actual number of instruction in this BPF program's image; for	 * entry-point BPF programs this includes the size of main program	 * itself plus all the used sub-programs, appended at the end	 */	size_t insns_cnt; 	struct reloc_desc *reloc_desc;	int nr_reloc; 	/* BPF verifier log settings */	char *log_buf;	size_t log_size;	__u32 log_level; 	struct bpf_object *obj; 	int fd;	bool autoload;	bool autoattach;	bool sym_global;	bool mark_btf_static;

Lines 1–500 of 15223.