bpf: Allow to specify kernel module BTFs when attaching BPF programs
Add ability for user-space programs to specify non-vmlinux BTF when attaching BTF-powered BPF programs: raw_tp, fentry/fexit/fmod_ret, LSM, etc. For this, attach_prog_fd (now with the alias name attach_btf_obj_fd) should specify FD of a module or vmlinux BTF object. For backwards compatibility reasons, 0 denotes vmlinux BTF. Only kernel BTF (vmlinux or module) can be specified. Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20201203204634.1325171-11-andrii@kernel.org
This commit is contained in:
parent
22dc4a0f5e
commit
290248a5b7
|
@ -90,6 +90,7 @@ int btf_type_snprintf_show(const struct btf *btf, u32 type_id, void *obj,
|
||||||
|
|
||||||
int btf_get_fd_by_id(u32 id);
|
int btf_get_fd_by_id(u32 id);
|
||||||
u32 btf_obj_id(const struct btf *btf);
|
u32 btf_obj_id(const struct btf *btf);
|
||||||
|
bool btf_is_kernel(const struct btf *btf);
|
||||||
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
|
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
|
||||||
const struct btf_member *m,
|
const struct btf_member *m,
|
||||||
u32 expected_offset, u32 expected_size);
|
u32 expected_offset, u32 expected_size);
|
||||||
|
|
|
@ -557,7 +557,12 @@ union bpf_attr {
|
||||||
__aligned_u64 line_info; /* line info */
|
__aligned_u64 line_info; /* line info */
|
||||||
__u32 line_info_cnt; /* number of bpf_line_info records */
|
__u32 line_info_cnt; /* number of bpf_line_info records */
|
||||||
__u32 attach_btf_id; /* in-kernel BTF type id to attach to */
|
__u32 attach_btf_id; /* in-kernel BTF type id to attach to */
|
||||||
__u32 attach_prog_fd; /* 0 to attach to vmlinux */
|
union {
|
||||||
|
/* valid prog_fd to attach to bpf prog */
|
||||||
|
__u32 attach_prog_fd;
|
||||||
|
/* or valid module BTF object fd or 0 to attach to vmlinux */
|
||||||
|
__u32 attach_btf_obj_fd;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||||
|
|
|
@ -5738,6 +5738,11 @@ u32 btf_obj_id(const struct btf *btf)
|
||||||
return btf->id;
|
return btf->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool btf_is_kernel(const struct btf *btf)
|
||||||
|
{
|
||||||
|
return btf->kernel_btf;
|
||||||
|
}
|
||||||
|
|
||||||
static int btf_id_cmp_func(const void *a, const void *b)
|
static int btf_id_cmp_func(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
const int *pa = a, *pb = b;
|
const int *pa = a, *pb = b;
|
||||||
|
|
|
@ -1926,12 +1926,16 @@ static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr)
|
||||||
static int
|
static int
|
||||||
bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
|
bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
|
||||||
enum bpf_attach_type expected_attach_type,
|
enum bpf_attach_type expected_attach_type,
|
||||||
u32 btf_id, u32 prog_fd)
|
struct btf *attach_btf, u32 btf_id,
|
||||||
|
struct bpf_prog *dst_prog)
|
||||||
{
|
{
|
||||||
if (btf_id) {
|
if (btf_id) {
|
||||||
if (btf_id > BTF_MAX_TYPE)
|
if (btf_id > BTF_MAX_TYPE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!attach_btf && !dst_prog)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
switch (prog_type) {
|
switch (prog_type) {
|
||||||
case BPF_PROG_TYPE_TRACING:
|
case BPF_PROG_TYPE_TRACING:
|
||||||
case BPF_PROG_TYPE_LSM:
|
case BPF_PROG_TYPE_LSM:
|
||||||
|
@ -1943,7 +1947,10 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prog_fd && prog_type != BPF_PROG_TYPE_TRACING &&
|
if (attach_btf && (!btf_id || dst_prog))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (dst_prog && prog_type != BPF_PROG_TYPE_TRACING &&
|
||||||
prog_type != BPF_PROG_TYPE_EXT)
|
prog_type != BPF_PROG_TYPE_EXT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -2060,7 +2067,8 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
|
||||||
static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
|
static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
|
||||||
{
|
{
|
||||||
enum bpf_prog_type type = attr->prog_type;
|
enum bpf_prog_type type = attr->prog_type;
|
||||||
struct bpf_prog *prog;
|
struct bpf_prog *prog, *dst_prog = NULL;
|
||||||
|
struct btf *attach_btf = NULL;
|
||||||
int err;
|
int err;
|
||||||
char license[128];
|
char license[128];
|
||||||
bool is_gpl;
|
bool is_gpl;
|
||||||
|
@ -2102,44 +2110,56 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
|
||||||
if (is_perfmon_prog_type(type) && !perfmon_capable())
|
if (is_perfmon_prog_type(type) && !perfmon_capable())
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
/* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog
|
||||||
|
* or btf, we need to check which one it is
|
||||||
|
*/
|
||||||
|
if (attr->attach_prog_fd) {
|
||||||
|
dst_prog = bpf_prog_get(attr->attach_prog_fd);
|
||||||
|
if (IS_ERR(dst_prog)) {
|
||||||
|
dst_prog = NULL;
|
||||||
|
attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd);
|
||||||
|
if (IS_ERR(attach_btf))
|
||||||
|
return -EINVAL;
|
||||||
|
if (!btf_is_kernel(attach_btf)) {
|
||||||
|
btf_put(attach_btf);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (attr->attach_btf_id) {
|
||||||
|
/* fall back to vmlinux BTF, if BTF type ID is specified */
|
||||||
|
attach_btf = bpf_get_btf_vmlinux();
|
||||||
|
if (IS_ERR(attach_btf))
|
||||||
|
return PTR_ERR(attach_btf);
|
||||||
|
if (!attach_btf)
|
||||||
|
return -EINVAL;
|
||||||
|
btf_get(attach_btf);
|
||||||
|
}
|
||||||
|
|
||||||
bpf_prog_load_fixup_attach_type(attr);
|
bpf_prog_load_fixup_attach_type(attr);
|
||||||
if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
|
if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
|
||||||
attr->attach_btf_id,
|
attach_btf, attr->attach_btf_id,
|
||||||
attr->attach_prog_fd))
|
dst_prog)) {
|
||||||
|
if (dst_prog)
|
||||||
|
bpf_prog_put(dst_prog);
|
||||||
|
if (attach_btf)
|
||||||
|
btf_put(attach_btf);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* plain bpf_prog allocation */
|
/* plain bpf_prog allocation */
|
||||||
prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
|
prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
|
||||||
if (!prog)
|
if (!prog) {
|
||||||
|
if (dst_prog)
|
||||||
|
bpf_prog_put(dst_prog);
|
||||||
|
if (attach_btf)
|
||||||
|
btf_put(attach_btf);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
prog->expected_attach_type = attr->expected_attach_type;
|
prog->expected_attach_type = attr->expected_attach_type;
|
||||||
|
prog->aux->attach_btf = attach_btf;
|
||||||
prog->aux->attach_btf_id = attr->attach_btf_id;
|
prog->aux->attach_btf_id = attr->attach_btf_id;
|
||||||
|
prog->aux->dst_prog = dst_prog;
|
||||||
if (attr->attach_btf_id && !attr->attach_prog_fd) {
|
|
||||||
struct btf *btf;
|
|
||||||
|
|
||||||
btf = bpf_get_btf_vmlinux();
|
|
||||||
if (IS_ERR(btf))
|
|
||||||
return PTR_ERR(btf);
|
|
||||||
if (!btf)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
btf_get(btf);
|
|
||||||
prog->aux->attach_btf = btf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attr->attach_prog_fd) {
|
|
||||||
struct bpf_prog *dst_prog;
|
|
||||||
|
|
||||||
dst_prog = bpf_prog_get(attr->attach_prog_fd);
|
|
||||||
if (IS_ERR(dst_prog)) {
|
|
||||||
err = PTR_ERR(dst_prog);
|
|
||||||
goto free_prog;
|
|
||||||
}
|
|
||||||
prog->aux->dst_prog = dst_prog;
|
|
||||||
}
|
|
||||||
|
|
||||||
prog->aux->offload_requested = !!attr->prog_ifindex;
|
prog->aux->offload_requested = !!attr->prog_ifindex;
|
||||||
prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE;
|
prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE;
|
||||||
|
|
||||||
|
|
|
@ -557,7 +557,12 @@ union bpf_attr {
|
||||||
__aligned_u64 line_info; /* line info */
|
__aligned_u64 line_info; /* line info */
|
||||||
__u32 line_info_cnt; /* number of bpf_line_info records */
|
__u32 line_info_cnt; /* number of bpf_line_info records */
|
||||||
__u32 attach_btf_id; /* in-kernel BTF type id to attach to */
|
__u32 attach_btf_id; /* in-kernel BTF type id to attach to */
|
||||||
__u32 attach_prog_fd; /* 0 to attach to vmlinux */
|
union {
|
||||||
|
/* valid prog_fd to attach to bpf prog */
|
||||||
|
__u32 attach_prog_fd;
|
||||||
|
/* or valid module BTF object fd or 0 to attach to vmlinux */
|
||||||
|
__u32 attach_btf_obj_fd;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||||
|
|
Loading…
Reference in New Issue