Skip to content

Commit f56a653

Browse files
iamkafaiborkmann
authored andcommitted
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 <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent b00b8da commit f56a653

File tree

4 files changed

+97
-0
lines changed

4 files changed

+97
-0
lines changed

include/linux/btf.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88

99
struct btf;
1010
struct btf_type;
11+
union bpf_attr;
1112

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);
1216
/* Figure out the size of a type_id. If type_id is a modifier
1317
* (e.g. const), it will be resolved to find out the type with size.
1418
*

include/uapi/linux/bpf.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ enum bpf_cmd {
9595
BPF_OBJ_GET_INFO_BY_FD,
9696
BPF_PROG_QUERY,
9797
BPF_RAW_TRACEPOINT_OPEN,
98+
BPF_BTF_LOAD,
9899
};
99100

100101
enum bpf_map_type {
@@ -363,6 +364,14 @@ union bpf_attr {
363364
__u64 name;
364365
__u32 prog_fd;
365366
} raw_tracepoint;
367+
368+
struct { /* anonymous struct for BPF_BTF_LOAD */
369+
__aligned_u64 btf;
370+
__aligned_u64 btf_log_buf;
371+
__u32 btf_size;
372+
__u32 btf_log_size;
373+
__u32 btf_log_level;
374+
};
366375
} __attribute__((aligned(8)));
367376

368377
/* BPF helper function descriptions:

kernel/bpf/btf.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <linux/compiler.h>
88
#include <linux/errno.h>
99
#include <linux/slab.h>
10+
#include <linux/anon_inodes.h>
11+
#include <linux/file.h>
1012
#include <linux/uaccess.h>
1113
#include <linux/kernel.h>
1214
#include <linux/bpf_verifier.h>
@@ -190,6 +192,7 @@ struct btf {
190192
u32 nr_types;
191193
u32 types_size;
192194
u32 data_size;
195+
refcount_t refcnt;
193196
};
194197

195198
enum verifier_phase {
@@ -604,6 +607,17 @@ static void btf_free(struct btf *btf)
604607
kfree(btf);
605608
}
606609

610+
static void btf_get(struct btf *btf)
611+
{
612+
refcount_inc(&btf->refcnt);
613+
}
614+
615+
void btf_put(struct btf *btf)
616+
{
617+
if (btf && refcount_dec_and_test(&btf->refcnt))
618+
btf_free(btf);
619+
}
620+
607621
static int env_resolve_init(struct btf_verifier_env *env)
608622
{
609623
struct btf *btf = env->btf;
@@ -1963,6 +1977,7 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
19631977

19641978
if (!err) {
19651979
btf_verifier_env_free(env);
1980+
btf_get(btf);
19661981
return btf;
19671982
}
19681983

@@ -1980,3 +1995,55 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,
19801995

19811996
btf_type_ops(t)->seq_show(btf, t, type_id, obj, 0, m);
19821997
}
1998+
1999+
static int btf_release(struct inode *inode, struct file *filp)
2000+
{
2001+
btf_put(filp->private_data);
2002+
return 0;
2003+
}
2004+
2005+
static const struct file_operations btf_fops = {
2006+
.release = btf_release,
2007+
};
2008+
2009+
int btf_new_fd(const union bpf_attr *attr)
2010+
{
2011+
struct btf *btf;
2012+
int fd;
2013+
2014+
btf = btf_parse(u64_to_user_ptr(attr->btf),
2015+
attr->btf_size, attr->btf_log_level,
2016+
u64_to_user_ptr(attr->btf_log_buf),
2017+
attr->btf_log_size);
2018+
if (IS_ERR(btf))
2019+
return PTR_ERR(btf);
2020+
2021+
fd = anon_inode_getfd("btf", &btf_fops, btf,
2022+
O_RDONLY | O_CLOEXEC);
2023+
if (fd < 0)
2024+
btf_put(btf);
2025+
2026+
return fd;
2027+
}
2028+
2029+
struct btf *btf_get_by_fd(int fd)
2030+
{
2031+
struct btf *btf;
2032+
struct fd f;
2033+
2034+
f = fdget(fd);
2035+
2036+
if (!f.file)
2037+
return ERR_PTR(-EBADF);
2038+
2039+
if (f.file->f_op != &btf_fops) {
2040+
fdput(f);
2041+
return ERR_PTR(-EINVAL);
2042+
}
2043+
2044+
btf = f.file->private_data;
2045+
btf_get(btf);
2046+
fdput(f);
2047+
2048+
return btf;
2049+
}

kernel/bpf/syscall.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
#include <linux/bpf.h>
1313
#include <linux/bpf_trace.h>
14+
#include <linux/btf.h>
1415
#include <linux/syscalls.h>
1516
#include <linux/slab.h>
1617
#include <linux/sched/signal.h>
@@ -2023,6 +2024,19 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
20232024
return err;
20242025
}
20252026

2027+
#define BPF_BTF_LOAD_LAST_FIELD btf_log_level
2028+
2029+
static int bpf_btf_load(const union bpf_attr *attr)
2030+
{
2031+
if (CHECK_ATTR(BPF_BTF_LOAD))
2032+
return -EINVAL;
2033+
2034+
if (!capable(CAP_SYS_ADMIN))
2035+
return -EPERM;
2036+
2037+
return btf_new_fd(attr);
2038+
}
2039+
20262040
SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
20272041
{
20282042
union bpf_attr attr = {};
@@ -2103,6 +2117,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
21032117
case BPF_RAW_TRACEPOINT_OPEN:
21042118
err = bpf_raw_tracepoint_open(&attr);
21052119
break;
2120+
case BPF_BTF_LOAD:
2121+
err = bpf_btf_load(&attr);
2122+
break;
21062123
default:
21072124
err = -EINVAL;
21082125
break;

0 commit comments

Comments
 (0)