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>
This commit is contained in:
parent
b00b8daec8
commit
f56a653c1f
|
@ -8,7 +8,11 @@
|
|||
|
||||
struct btf;
|
||||
struct btf_type;
|
||||
union bpf_attr;
|
||||
|
||||
void btf_put(struct btf *btf);
|
||||
int btf_new_fd(const union bpf_attr *attr);
|
||||
struct btf *btf_get_by_fd(int fd);
|
||||
/* Figure out the size of a type_id. If type_id is a modifier
|
||||
* (e.g. const), it will be resolved to find out the type with size.
|
||||
*
|
||||
|
|
|
@ -95,6 +95,7 @@ enum bpf_cmd {
|
|||
BPF_OBJ_GET_INFO_BY_FD,
|
||||
BPF_PROG_QUERY,
|
||||
BPF_RAW_TRACEPOINT_OPEN,
|
||||
BPF_BTF_LOAD,
|
||||
};
|
||||
|
||||
enum bpf_map_type {
|
||||
|
@ -363,6 +364,14 @@ union bpf_attr {
|
|||
__u64 name;
|
||||
__u32 prog_fd;
|
||||
} raw_tracepoint;
|
||||
|
||||
struct { /* anonymous struct for BPF_BTF_LOAD */
|
||||
__aligned_u64 btf;
|
||||
__aligned_u64 btf_log_buf;
|
||||
__u32 btf_size;
|
||||
__u32 btf_log_size;
|
||||
__u32 btf_log_level;
|
||||
};
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
/* BPF helper function descriptions:
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <linux/compiler.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bpf_verifier.h>
|
||||
|
@ -190,6 +192,7 @@ struct btf {
|
|||
u32 nr_types;
|
||||
u32 types_size;
|
||||
u32 data_size;
|
||||
refcount_t refcnt;
|
||||
};
|
||||
|
||||
enum verifier_phase {
|
||||
|
@ -604,6 +607,17 @@ static void btf_free(struct btf *btf)
|
|||
kfree(btf);
|
||||
}
|
||||
|
||||
static void btf_get(struct btf *btf)
|
||||
{
|
||||
refcount_inc(&btf->refcnt);
|
||||
}
|
||||
|
||||
void btf_put(struct btf *btf)
|
||||
{
|
||||
if (btf && refcount_dec_and_test(&btf->refcnt))
|
||||
btf_free(btf);
|
||||
}
|
||||
|
||||
static int env_resolve_init(struct btf_verifier_env *env)
|
||||
{
|
||||
struct btf *btf = env->btf;
|
||||
|
@ -1963,6 +1977,7 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
|
|||
|
||||
if (!err) {
|
||||
btf_verifier_env_free(env);
|
||||
btf_get(btf);
|
||||
return btf;
|
||||
}
|
||||
|
||||
|
@ -1980,3 +1995,55 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,
|
|||
|
||||
btf_type_ops(t)->seq_show(btf, t, type_id, obj, 0, m);
|
||||
}
|
||||
|
||||
static int btf_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
btf_put(filp->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations btf_fops = {
|
||||
.release = btf_release,
|
||||
};
|
||||
|
||||
int btf_new_fd(const union bpf_attr *attr)
|
||||
{
|
||||
struct btf *btf;
|
||||
int fd;
|
||||
|
||||
btf = btf_parse(u64_to_user_ptr(attr->btf),
|
||||
attr->btf_size, attr->btf_log_level,
|
||||
u64_to_user_ptr(attr->btf_log_buf),
|
||||
attr->btf_log_size);
|
||||
if (IS_ERR(btf))
|
||||
return PTR_ERR(btf);
|
||||
|
||||
fd = anon_inode_getfd("btf", &btf_fops, btf,
|
||||
O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
btf_put(btf);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct btf *btf_get_by_fd(int fd)
|
||||
{
|
||||
struct btf *btf;
|
||||
struct fd f;
|
||||
|
||||
f = fdget(fd);
|
||||
|
||||
if (!f.file)
|
||||
return ERR_PTR(-EBADF);
|
||||
|
||||
if (f.file->f_op != &btf_fops) {
|
||||
fdput(f);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
btf = f.file->private_data;
|
||||
btf_get(btf);
|
||||
fdput(f);
|
||||
|
||||
return btf;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/bpf_trace.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched/signal.h>
|
||||
|
@ -2023,6 +2024,19 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
|
|||
return err;
|
||||
}
|
||||
|
||||
#define BPF_BTF_LOAD_LAST_FIELD btf_log_level
|
||||
|
||||
static int bpf_btf_load(const union bpf_attr *attr)
|
||||
{
|
||||
if (CHECK_ATTR(BPF_BTF_LOAD))
|
||||
return -EINVAL;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
return btf_new_fd(attr);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
|
||||
{
|
||||
union bpf_attr attr = {};
|
||||
|
@ -2103,6 +2117,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
|
|||
case BPF_RAW_TRACEPOINT_OPEN:
|
||||
err = bpf_raw_tracepoint_open(&attr);
|
||||
break;
|
||||
case BPF_BTF_LOAD:
|
||||
err = bpf_btf_load(&attr);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue