Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: btf: Add BPF_BTF_LOAD command

This patch adds a BPF_BTF_LOAD command which
1) loads and verifies the BTF (implemented in earlier patches)
2) returns a BTF fd to userspace. In the next patch, the
BTF fd can be specified during BPF_MAP_CREATE.

It currently limits to CAP_SYS_ADMIN.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Alexei Starovoitov <ast@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

authored by

Martin KaFai Lau and committed by
Daniel Borkmann
f56a653c b00b8dae

+97
+4
include/linux/btf.h
··· 8 8 9 9 struct btf; 10 10 struct btf_type; 11 + union bpf_attr; 11 12 13 + void btf_put(struct btf *btf); 14 + int btf_new_fd(const union bpf_attr *attr); 15 + struct btf *btf_get_by_fd(int fd); 12 16 /* Figure out the size of a type_id. If type_id is a modifier 13 17 * (e.g. const), it will be resolved to find out the type with size. 14 18 *
+9
include/uapi/linux/bpf.h
··· 95 95 BPF_OBJ_GET_INFO_BY_FD, 96 96 BPF_PROG_QUERY, 97 97 BPF_RAW_TRACEPOINT_OPEN, 98 + BPF_BTF_LOAD, 98 99 }; 99 100 100 101 enum bpf_map_type { ··· 364 363 __u64 name; 365 364 __u32 prog_fd; 366 365 } raw_tracepoint; 366 + 367 + struct { /* anonymous struct for BPF_BTF_LOAD */ 368 + __aligned_u64 btf; 369 + __aligned_u64 btf_log_buf; 370 + __u32 btf_size; 371 + __u32 btf_log_size; 372 + __u32 btf_log_level; 373 + }; 367 374 } __attribute__((aligned(8))); 368 375 369 376 /* BPF helper function descriptions:
+67
kernel/bpf/btf.c
··· 7 7 #include <linux/compiler.h> 8 8 #include <linux/errno.h> 9 9 #include <linux/slab.h> 10 + #include <linux/anon_inodes.h> 11 + #include <linux/file.h> 10 12 #include <linux/uaccess.h> 11 13 #include <linux/kernel.h> 12 14 #include <linux/bpf_verifier.h> ··· 192 190 u32 nr_types; 193 191 u32 types_size; 194 192 u32 data_size; 193 + refcount_t refcnt; 195 194 }; 196 195 197 196 enum verifier_phase { ··· 605 602 kvfree(btf->resolved_ids); 606 603 kvfree(btf->data); 607 604 kfree(btf); 605 + } 606 + 607 + static void btf_get(struct btf *btf) 608 + { 609 + refcount_inc(&btf->refcnt); 610 + } 611 + 612 + void btf_put(struct btf *btf) 613 + { 614 + if (btf && refcount_dec_and_test(&btf->refcnt)) 615 + btf_free(btf); 608 616 } 609 617 610 618 static int env_resolve_init(struct btf_verifier_env *env) ··· 1977 1963 1978 1964 if (!err) { 1979 1965 btf_verifier_env_free(env); 1966 + btf_get(btf); 1980 1967 return btf; 1981 1968 } 1982 1969 ··· 1994 1979 const struct btf_type *t = btf_type_by_id(btf, type_id); 1995 1980 1996 1981 btf_type_ops(t)->seq_show(btf, t, type_id, obj, 0, m); 1982 + } 1983 + 1984 + static int btf_release(struct inode *inode, struct file *filp) 1985 + { 1986 + btf_put(filp->private_data); 1987 + return 0; 1988 + } 1989 + 1990 + static const struct file_operations btf_fops = { 1991 + .release = btf_release, 1992 + }; 1993 + 1994 + int btf_new_fd(const union bpf_attr *attr) 1995 + { 1996 + struct btf *btf; 1997 + int fd; 1998 + 1999 + btf = btf_parse(u64_to_user_ptr(attr->btf), 2000 + attr->btf_size, attr->btf_log_level, 2001 + u64_to_user_ptr(attr->btf_log_buf), 2002 + attr->btf_log_size); 2003 + if (IS_ERR(btf)) 2004 + return PTR_ERR(btf); 2005 + 2006 + fd = anon_inode_getfd("btf", &btf_fops, btf, 2007 + O_RDONLY | O_CLOEXEC); 2008 + if (fd < 0) 2009 + btf_put(btf); 2010 + 2011 + return fd; 2012 + } 2013 + 2014 + struct btf *btf_get_by_fd(int fd) 2015 + { 2016 + struct btf *btf; 2017 + struct fd f; 2018 + 2019 + f = fdget(fd); 2020 + 2021 + if (!f.file) 2022 + return ERR_PTR(-EBADF); 2023 + 2024 + if (f.file->f_op != &btf_fops) { 2025 + fdput(f); 2026 + return ERR_PTR(-EINVAL); 2027 + } 2028 + 2029 + btf = f.file->private_data; 2030 + btf_get(btf); 2031 + fdput(f); 2032 + 2033 + return btf; 1997 2034 }
+17
kernel/bpf/syscall.c
··· 11 11 */ 12 12 #include <linux/bpf.h> 13 13 #include <linux/bpf_trace.h> 14 + #include <linux/btf.h> 14 15 #include <linux/syscalls.h> 15 16 #include <linux/slab.h> 16 17 #include <linux/sched/signal.h> ··· 2024 2023 return err; 2025 2024 } 2026 2025 2026 + #define BPF_BTF_LOAD_LAST_FIELD btf_log_level 2027 + 2028 + static int bpf_btf_load(const union bpf_attr *attr) 2029 + { 2030 + if (CHECK_ATTR(BPF_BTF_LOAD)) 2031 + return -EINVAL; 2032 + 2033 + if (!capable(CAP_SYS_ADMIN)) 2034 + return -EPERM; 2035 + 2036 + return btf_new_fd(attr); 2037 + } 2038 + 2027 2039 SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 2028 2040 { 2029 2041 union bpf_attr attr = {}; ··· 2116 2102 break; 2117 2103 case BPF_RAW_TRACEPOINT_OPEN: 2118 2104 err = bpf_raw_tracepoint_open(&attr); 2105 + break; 2106 + case BPF_BTF_LOAD: 2107 + err = bpf_btf_load(&attr); 2119 2108 break; 2120 2109 default: 2121 2110 err = -EINVAL;