Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6283fa38 authored by Martin KaFai Lau's avatar Martin KaFai Lau Committed by Daniel Borkmann
Browse files

bpf: btf: Ensure the member->offset is in the right order



This patch ensures the member->offset of a struct
is in the correct order (i.e the later member's offset cannot
go backward).

The current "pahole -J" BTF encoder does not generate something
like this.  However, checking this can ensure future encoder
will not violate this.

Fixes: 69b693f0 ("bpf: btf: Introduce BPF Type Format (BTF)")
Signed-off-by: default avatarMartin KaFai Lau <kafai@fb.com>
Acked-by: default avatarYonghong Song <yhs@fb.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent 1a4f14ba
Loading
Loading
Loading
Loading
+13 −1
Original line number Original line Diff line number Diff line
@@ -1519,9 +1519,9 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
{
{
	bool is_union = BTF_INFO_KIND(t->info) == BTF_KIND_UNION;
	bool is_union = BTF_INFO_KIND(t->info) == BTF_KIND_UNION;
	const struct btf_member *member;
	const struct btf_member *member;
	u32 meta_needed, last_offset;
	struct btf *btf = env->btf;
	struct btf *btf = env->btf;
	u32 struct_size = t->size;
	u32 struct_size = t->size;
	u32 meta_needed;
	u16 i;
	u16 i;


	meta_needed = btf_type_vlen(t) * sizeof(*member);
	meta_needed = btf_type_vlen(t) * sizeof(*member);
@@ -1534,6 +1534,7 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,


	btf_verifier_log_type(env, t, NULL);
	btf_verifier_log_type(env, t, NULL);


	last_offset = 0;
	for_each_member(i, t, member) {
	for_each_member(i, t, member) {
		if (!btf_name_offset_valid(btf, member->name_off)) {
		if (!btf_name_offset_valid(btf, member->name_off)) {
			btf_verifier_log_member(env, t, member,
			btf_verifier_log_member(env, t, member,
@@ -1555,6 +1556,16 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
			return -EINVAL;
			return -EINVAL;
		}
		}


		/*
		 * ">" instead of ">=" because the last member could be
		 * "char a[0];"
		 */
		if (last_offset > member->offset) {
			btf_verifier_log_member(env, t, member,
						"Invalid member bits_offset");
			return -EINVAL;
		}

		if (BITS_ROUNDUP_BYTES(member->offset) > struct_size) {
		if (BITS_ROUNDUP_BYTES(member->offset) > struct_size) {
			btf_verifier_log_member(env, t, member,
			btf_verifier_log_member(env, t, member,
						"Memmber bits_offset exceeds its struct size");
						"Memmber bits_offset exceeds its struct size");
@@ -1562,6 +1573,7 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
		}
		}


		btf_verifier_log_member(env, t, member, NULL);
		btf_verifier_log_member(env, t, member, NULL);
		last_offset = member->offset;
	}
	}


	return meta_needed;
	return meta_needed;
+28 −0
Original line number Original line Diff line number Diff line
@@ -247,6 +247,34 @@ static struct btf_raw_test raw_tests[] = {
	.max_entries = 4,
	.max_entries = 4,
},
},


{
	.descr = "struct test #3 Invalid member offset",
	.raw_types = {
		/* int */					/* [1] */
		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
		/* int64 */					/* [2] */
		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 64, 8),

		/* struct A { */				/* [3] */
		BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 16),
		BTF_MEMBER_ENC(NAME_TBD, 1, 64),	/* int m;		*/
		BTF_MEMBER_ENC(NAME_TBD, 2, 0),		/* int64 n; */
		/* } */
		BTF_END_RAW,
	},
	.str_sec = "\0A\0m\0n\0",
	.str_sec_size = sizeof("\0A\0m\0n\0"),
	.map_type = BPF_MAP_TYPE_ARRAY,
	.map_name = "struct_test3_map",
	.key_size = sizeof(int),
	.value_size = 16,
	.key_type_id = 1,
	.value_type_id = 3,
	.max_entries = 4,
	.btf_load_err = true,
	.err_str = "Invalid member bits_offset",
},

/* Test member exceeds the size of struct.
/* Test member exceeds the size of struct.
 *
 *
 * struct A {
 * struct A {