@@ -3305,7 +3305,7 @@ static int btf_find_struct(const struct btf *btf, const struct btf_type *t,
u32 off, int sz, enum btf_field_type field_type,
struct btf_field_info *info)
{
- if (!__btf_type_is_struct(t))
+ if (!btf_type_is_struct(t))
return BTF_FIELD_IGNORE;
if (t->size != sz)
return BTF_FIELD_IGNORE;
@@ -3497,6 +3497,24 @@ static int btf_get_field_type(const char *name, u32 field_mask, u32 *seen_mask,
return type;
}
+static int btf_get_union_field_types(const struct btf *btf, const struct btf_type *u,
+ u32 field_mask, u32 *seen_mask, int *align, int *sz)
+{
+ int i, field_type, field_types = 0;
+ const struct btf_member *member;
+ const struct btf_type *t;
+
+ for_each_member(i, u, member) {
+ t = btf_type_by_id(btf, member->type);
+ field_type = btf_get_field_type(__btf_name_by_offset(btf, t->name_off),
+ field_mask, seen_mask, align, sz);
+ if (field_type == 0 || field_type == BPF_KPTR_REF)
+ continue;
+ field_types = field_types | field_type;
+ }
+ return field_types;
+}
+
#undef field_mask_test_name
static int btf_find_struct_field(const struct btf *btf,
@@ -3512,8 +3530,12 @@ static int btf_find_struct_field(const struct btf *btf,
const struct btf_type *member_type = btf_type_by_id(btf,
member->type);
- field_type = btf_get_field_type(__btf_name_by_offset(btf, member_type->name_off),
- field_mask, &seen_mask, &align, &sz);
+ field_type = BTF_INFO_KIND(member_type->info) == BTF_KIND_UNION ?
+ btf_get_union_field_types(btf, member_type, field_mask,
+ &seen_mask, &align, &sz) :
+ btf_get_field_type(__btf_name_by_offset(btf, member_type->name_off),
+ field_mask, &seen_mask, &align, &sz);
+
if (field_type == 0)
continue;
if (field_type < 0)
@@ -3521,8 +3543,7 @@ static int btf_find_struct_field(const struct btf *btf,
off = __btf_member_bit_offset(t, member);
if (off % 8)
- /* valid C code cannot generate such BTF */
- return -EINVAL;
+ continue;
off /= 8;
if (off % align)
continue;
@@ -3737,6 +3758,20 @@ static int btf_parse_kptr(const struct btf *btf, struct btf_field *field,
return ret;
}
+static const struct btf_type *
+btf_find_member_by_name(const struct btf *btf, const struct btf_type *t,
+ const char *member_name)
+{
+ const struct btf_member *member;
+ int i;
+
+ for_each_member(i, t, member) {
+ if (!strcmp(member_name, __btf_name_by_offset(btf, member->name_off)))
+ return btf_type_by_id(btf, member->type);
+ }
+ return NULL;
+}
+
static int btf_parse_graph_root(struct btf_field *field,
struct btf_field_info *info,
const char *node_type_name,
@@ -3754,18 +3789,27 @@ static int btf_parse_graph_root(struct btf_field *field,
* verify its type.
*/
for_each_member(i, t, member) {
- if (strcmp(info->graph_root.node_name,
- __btf_name_by_offset(btf, member->name_off)))
+ const struct btf_type *member_type = btf_type_by_id(btf, member->type);
+
+ if (BTF_INFO_KIND(member_type->info) == BTF_KIND_UNION) {
+ member_type = btf_find_member_by_name(btf, member_type,
+ info->graph_root.node_name);
+ if (!member_type)
+ continue;
+ } else if (strcmp(info->graph_root.node_name,
+ __btf_name_by_offset(btf, member->name_off))) {
continue;
+ }
+
/* Invalid BTF, two members with same name */
if (n)
return -EINVAL;
- n = btf_type_by_id(btf, member->type);
+ n = member_type;
if (!__btf_type_is_struct(n))
return -EINVAL;
if (strcmp(node_type_name, __btf_name_by_offset(btf, n->name_off)))
return -EINVAL;
- offset = __btf_member_bit_offset(n, member);
+ offset = __btf_member_bit_offset(member_type, member);
if (offset % 8)
return -EINVAL;
offset /= 8;
@@ -5440,7 +5484,7 @@ btf_parse_struct_metas(struct bpf_verifier_log *log, struct btf *btf)
const struct btf_member *member;
struct btf_struct_meta *type;
struct btf_record *record;
- const struct btf_type *t;
+ const struct btf_type *t, *member_type;
int j, tab_cnt, id;
id = btf_is_base_kernel ?
@@ -5462,6 +5506,16 @@ btf_parse_struct_metas(struct bpf_verifier_log *log, struct btf *btf)
cond_resched();
for_each_member(j, t, member) {
+ member_type = btf_type_by_id(btf, member->type);
+ if (BTF_INFO_KIND(member_type->info) == BTF_KIND_UNION) {
+ const struct btf_member *umember;
+ int k;
+
+ for_each_member(k, member_type, umember) {
+ if (btf_id_set_contains(&aof.set, umember->type))
+ goto parse;
+ }
+ }
if (btf_id_set_contains(&aof.set, member->type))
goto parse;
}
This patch looks into unions when parsing BTF. While we would like to support adding a skb to bpf collections, the bpf graph node in sk_buff will happen to be in a union due to space constraint. Therefore, Signed-off-by: Amery Hung <amery.hung@bytedance.com> --- kernel/bpf/btf.c | 74 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 10 deletions(-)