bpf: Introduce BPF_PROG_TYPE_STRUCT_OPS
This patch allows the kernel's struct ops (i.e. func ptr) to be implemented in BPF. The first use case in this series is the "struct tcp_congestion_ops" which will be introduced in a latter patch. This patch introduces a new prog type BPF_PROG_TYPE_STRUCT_OPS. The BPF_PROG_TYPE_STRUCT_OPS prog is verified against a particular func ptr of a kernel struct. The attr->attach_btf_id is the btf id of a kernel struct. The attr->expected_attach_type is the member "index" of that kernel struct. The first member of a struct starts with member index 0. That will avoid ambiguity when a kernel struct has multiple func ptrs with the same func signature. For example, a BPF_PROG_TYPE_STRUCT_OPS prog is written to implement the "init" func ptr of the "struct tcp_congestion_ops". The attr->attach_btf_id is the btf id of the "struct tcp_congestion_ops" of the _running_ kernel. The attr->expected_attach_type is 3. The ctx of BPF_PROG_TYPE_STRUCT_OPS is an array of u64 args saved by arch_prepare_bpf_trampoline that will be done in the next patch when introducing BPF_MAP_TYPE_STRUCT_OPS. "struct bpf_struct_ops" is introduced as a common interface for the kernel struct that supports BPF_PROG_TYPE_STRUCT_OPS prog. The supporting kernel struct will need to implement an instance of the "struct bpf_struct_ops". The supporting kernel struct also needs to implement a bpf_verifier_ops. During BPF_PROG_LOAD, bpf_struct_ops_find() will find the right bpf_verifier_ops by searching the attr->attach_btf_id. A new "btf_struct_access" is also added to the bpf_verifier_ops such that the supporting kernel struct can optionally provide its own specific check on accessing the func arg (e.g. provide limited write access). After btf_vmlinux is parsed, the new bpf_struct_ops_init() is called to initialize some values (e.g. the btf id of the supporting kernel struct) and it can only be done once the btf_vmlinux is available. The R0 checks at BPF_EXIT is excluded for the BPF_PROG_TYPE_STRUCT_OPS prog if the return type of the prog->aux->attach_func_proto is "void". Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Andrii Nakryiko <andriin@fb.com> Acked-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/bpf/20200109003503.3855825-1-kafai@fb.com
This commit is contained in:

committed by
Alexei Starovoitov

parent
976aba002f
commit
27ae7997a6
@@ -180,11 +180,6 @@
|
||||
*/
|
||||
#define BTF_MAX_SIZE (16 * 1024 * 1024)
|
||||
|
||||
#define for_each_member(i, struct_type, member) \
|
||||
for (i = 0, member = btf_type_member(struct_type); \
|
||||
i < btf_type_vlen(struct_type); \
|
||||
i++, member++)
|
||||
|
||||
#define for_each_member_from(i, from, struct_type, member) \
|
||||
for (i = from, member = btf_type_member(struct_type) + from; \
|
||||
i < btf_type_vlen(struct_type); \
|
||||
@@ -382,6 +377,65 @@ static bool btf_type_is_datasec(const struct btf_type *t)
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC;
|
||||
}
|
||||
|
||||
s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind)
|
||||
{
|
||||
const struct btf_type *t;
|
||||
const char *tname;
|
||||
u32 i;
|
||||
|
||||
for (i = 1; i <= btf->nr_types; i++) {
|
||||
t = btf->types[i];
|
||||
if (BTF_INFO_KIND(t->info) != kind)
|
||||
continue;
|
||||
|
||||
tname = btf_name_by_offset(btf, t->name_off);
|
||||
if (!strcmp(tname, name))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
const struct btf_type *btf_type_skip_modifiers(const struct btf *btf,
|
||||
u32 id, u32 *res_id)
|
||||
{
|
||||
const struct btf_type *t = btf_type_by_id(btf, id);
|
||||
|
||||
while (btf_type_is_modifier(t)) {
|
||||
id = t->type;
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
}
|
||||
|
||||
if (res_id)
|
||||
*res_id = id;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
const struct btf_type *btf_type_resolve_ptr(const struct btf *btf,
|
||||
u32 id, u32 *res_id)
|
||||
{
|
||||
const struct btf_type *t;
|
||||
|
||||
t = btf_type_skip_modifiers(btf, id, NULL);
|
||||
if (!btf_type_is_ptr(t))
|
||||
return NULL;
|
||||
|
||||
return btf_type_skip_modifiers(btf, t->type, res_id);
|
||||
}
|
||||
|
||||
const struct btf_type *btf_type_resolve_func_ptr(const struct btf *btf,
|
||||
u32 id, u32 *res_id)
|
||||
{
|
||||
const struct btf_type *ptype;
|
||||
|
||||
ptype = btf_type_resolve_ptr(btf, id, res_id);
|
||||
if (ptype && btf_type_is_func_proto(ptype))
|
||||
return ptype;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Types that act only as a source, not sink or intermediate
|
||||
* type when resolving.
|
||||
*/
|
||||
@@ -446,16 +500,6 @@ static const char *btf_int_encoding_str(u8 encoding)
|
||||
return "UNKN";
|
||||
}
|
||||
|
||||
static u16 btf_type_vlen(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_VLEN(t->info);
|
||||
}
|
||||
|
||||
static bool btf_type_kflag(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KFLAG(t->info);
|
||||
}
|
||||
|
||||
static u32 btf_member_bit_offset(const struct btf_type *struct_type,
|
||||
const struct btf_member *member)
|
||||
{
|
||||
@@ -463,13 +507,6 @@ static u32 btf_member_bit_offset(const struct btf_type *struct_type,
|
||||
: member->offset;
|
||||
}
|
||||
|
||||
static u32 btf_member_bitfield_size(const struct btf_type *struct_type,
|
||||
const struct btf_member *member)
|
||||
{
|
||||
return btf_type_kflag(struct_type) ? BTF_MEMBER_BITFIELD_SIZE(member->offset)
|
||||
: 0;
|
||||
}
|
||||
|
||||
static u32 btf_type_int(const struct btf_type *t)
|
||||
{
|
||||
return *(u32 *)(t + 1);
|
||||
@@ -480,11 +517,6 @@ static const struct btf_array *btf_type_array(const struct btf_type *t)
|
||||
return (const struct btf_array *)(t + 1);
|
||||
}
|
||||
|
||||
static const struct btf_member *btf_type_member(const struct btf_type *t)
|
||||
{
|
||||
return (const struct btf_member *)(t + 1);
|
||||
}
|
||||
|
||||
static const struct btf_enum *btf_type_enum(const struct btf_type *t)
|
||||
{
|
||||
return (const struct btf_enum *)(t + 1);
|
||||
@@ -3605,6 +3637,8 @@ struct btf *btf_parse_vmlinux(void)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
bpf_struct_ops_init(btf);
|
||||
|
||||
btf_verifier_env_free(env);
|
||||
refcount_set(&btf->refcnt, 1);
|
||||
return btf;
|
||||
|
Reference in New Issue
Block a user