Commit f19caf57 authored by Kui-Feng Lee's avatar Kui-Feng Lee Committed by Alexei Starovoitov
Browse files

bpf: limit the number of levels of a nested struct type.



Limit the number of levels looking into struct types to avoid running out
of stack space.

Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Signed-off-by: default avatarKui-Feng Lee <thinker.li@gmail.com>
Link: https://lore.kernel.org/r/20240523174202.461236-7-thinker.li@gmail.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 64e8ee81
Loading
Loading
Loading
Loading
+19 −11
Original line number Diff line number Diff line
@@ -3536,7 +3536,8 @@ static int btf_repeat_fields(struct btf_field_info *info,

static int btf_find_struct_field(const struct btf *btf,
				 const struct btf_type *t, u32 field_mask,
				 struct btf_field_info *info, int info_cnt);
				 struct btf_field_info *info, int info_cnt,
				 u32 level);

/* Find special fields in the struct type of a field.
 *
@@ -3547,11 +3548,15 @@ static int btf_find_struct_field(const struct btf *btf,
static int btf_find_nested_struct(const struct btf *btf, const struct btf_type *t,
				  u32 off, u32 nelems,
				  u32 field_mask, struct btf_field_info *info,
				  int info_cnt)
				  int info_cnt, u32 level)
{
	int ret, err, i;

	ret = btf_find_struct_field(btf, t, field_mask, info, info_cnt);
	level++;
	if (level >= MAX_RESOLVE_DEPTH)
		return -E2BIG;

	ret = btf_find_struct_field(btf, t, field_mask, info, info_cnt, level);

	if (ret <= 0)
		return ret;
@@ -3579,7 +3584,8 @@ static int btf_find_field_one(const struct btf *btf,
			      int var_idx,
			      u32 off, u32 expected_size,
			      u32 field_mask, u32 *seen_mask,
			      struct btf_field_info *info, int info_cnt)
			      struct btf_field_info *info, int info_cnt,
			      u32 level)
{
	int ret, align, sz, field_type;
	struct btf_field_info tmp;
@@ -3607,7 +3613,7 @@ static int btf_find_field_one(const struct btf *btf,
		if (expected_size && expected_size != sz * nelems)
			return 0;
		ret = btf_find_nested_struct(btf, var_type, off, nelems, field_mask,
					     &info[0], info_cnt);
					     &info[0], info_cnt, level);
		return ret;
	}

@@ -3668,7 +3674,8 @@ static int btf_find_field_one(const struct btf *btf,

static int btf_find_struct_field(const struct btf *btf,
				 const struct btf_type *t, u32 field_mask,
				 struct btf_field_info *info, int info_cnt)
				 struct btf_field_info *info, int info_cnt,
				 u32 level)
{
	int ret, idx = 0;
	const struct btf_member *member;
@@ -3687,7 +3694,7 @@ static int btf_find_struct_field(const struct btf *btf,
		ret = btf_find_field_one(btf, t, member_type, i,
					 off, 0,
					 field_mask, &seen_mask,
					 &info[idx], info_cnt - idx);
					 &info[idx], info_cnt - idx, level);
		if (ret < 0)
			return ret;
		idx += ret;
@@ -3697,7 +3704,7 @@ static int btf_find_struct_field(const struct btf *btf,

static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t,
				u32 field_mask, struct btf_field_info *info,
				int info_cnt)
				int info_cnt, u32 level)
{
	int ret, idx = 0;
	const struct btf_var_secinfo *vsi;
@@ -3710,7 +3717,8 @@ static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t,
		off = vsi->offset;
		ret = btf_find_field_one(btf, var, var_type, -1, off, vsi->size,
					 field_mask, &seen_mask,
					 &info[idx], info_cnt - idx);
					 &info[idx], info_cnt - idx,
					 level);
		if (ret < 0)
			return ret;
		idx += ret;
@@ -3723,9 +3731,9 @@ static int btf_find_field(const struct btf *btf, const struct btf_type *t,
			  int info_cnt)
{
	if (__btf_type_is_struct(t))
		return btf_find_struct_field(btf, t, field_mask, info, info_cnt);
		return btf_find_struct_field(btf, t, field_mask, info, info_cnt, 0);
	else if (btf_type_is_datasec(t))
		return btf_find_datasec_var(btf, t, field_mask, info, info_cnt);
		return btf_find_datasec_var(btf, t, field_mask, info, info_cnt, 0);
	return -EINVAL;
}