[RFC PATCH v8 09/20] bpf: Find special BTF fields in union

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxx>
---
 kernel/bpf/btf.c | 74 +++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 64 insertions(+), 10 deletions(-)

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 37fb6143da79..25a5dc840ac3 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -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;
 		}
-- 
2.20.1





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux