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

Commit ff4fb475 authored by Daniel Borkmann's avatar Daniel Borkmann
Browse files

Merge branch 'btf-uapi-cleanups'



Martin KaFai Lau says:

====================
This patch set makes some changes to cleanup the unused
bits in BTF uapi.  It also makes the btf_header extensible.

Please see individual patches for details.

v2:
- Remove NR_SECS from patch 2
- Remove "unsigned" check on array->index_type from patch 3
- Remove BTF_INT_VARARGS and further limit BTF_INT_ENCODING
  from 8 bits to 4 bits in patch 4
- Adjustments in test_btf.c to reflect changes in v2
====================

Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parents 3fb48d88 61746dbe
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -69,8 +69,8 @@ struct bpf_map {
	u32 pages;
	u32 id;
	int numa_node;
	u32 btf_key_id;
	u32 btf_value_id;
	u32 btf_key_type_id;
	u32 btf_value_type_id;
	struct btf *btf;
	bool unpriv_array;
	/* 55 bytes hole */
@@ -463,6 +463,8 @@ int bpf_fd_htab_map_update_elem(struct bpf_map *map, struct file *map_file,
int bpf_fd_htab_map_lookup_elem(struct bpf_map *map, void *key, u32 *value);

int bpf_get_file_flag(int flags);
int bpf_check_uarg_tail_zero(void __user *uaddr, size_t expected_size,
			     size_t actual_size);

/* memcpy that is used with 8-byte aligned pointers, power-of-8 size and
 * forced to use 'long' read/writes to try to atomically copy long counters.
+4 −4
Original line number Diff line number Diff line
@@ -284,8 +284,8 @@ union bpf_attr {
		char	map_name[BPF_OBJ_NAME_LEN];
		__u32	map_ifindex;	/* ifindex of netdev to create on */
		__u32	btf_fd;		/* fd pointing to a BTF type data */
		__u32	btf_key_id;	/* BTF type_id of the key */
		__u32	btf_value_id;	/* BTF type_id of the value */
		__u32	btf_key_type_id;	/* BTF type_id of the key */
		__u32	btf_value_type_id;	/* BTF type_id of the value */
	};

	struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
@@ -2219,8 +2219,8 @@ struct bpf_map_info {
	__u64 netns_dev;
	__u64 netns_ino;
	__u32 btf_id;
	__u32 btf_key_id;
	__u32 btf_value_id;
	__u32 btf_key_type_id;
	__u32 btf_value_type_id;
} __attribute__((aligned(8)));

struct bpf_btf_info {
+11 −26
Original line number Diff line number Diff line
@@ -12,42 +12,29 @@ struct btf_header {
	__u16	magic;
	__u8	version;
	__u8	flags;

	__u32	parent_label;
	__u32	parent_name;
	__u32	hdr_len;

	/* All offsets are in bytes relative to the end of this header */
	__u32	label_off;	/* offset of label section	*/
	__u32	object_off;	/* offset of data object section*/
	__u32	func_off;	/* offset of function section	*/
	__u32	type_off;	/* offset of type section	*/
	__u32	type_len;	/* length of type section	*/
	__u32	str_off;	/* offset of string section	*/
	__u32	str_len;	/* length of string section	*/
};

/* Max # of type identifier */
#define BTF_MAX_TYPE	0x7fffffff
#define BTF_MAX_TYPE	0x0000ffff
/* Max offset into the string section */
#define BTF_MAX_NAME_OFFSET	0x7fffffff
#define BTF_MAX_NAME_OFFSET	0x0000ffff
/* Max # of struct/union/enum members or func args */
#define BTF_MAX_VLEN	0xffff

/* The type id is referring to a parent BTF */
#define BTF_TYPE_PARENT(id)	(((id) >> 31) & 0x1)
#define BTF_TYPE_ID(id)		((id) & BTF_MAX_TYPE)

/* String is in the ELF string section */
#define BTF_STR_TBL_ELF_ID(ref)	(((ref) >> 31) & 0x1)
#define BTF_STR_OFFSET(ref)	((ref) & BTF_MAX_NAME_OFFSET)

struct btf_type {
	__u32 name_off;
	/* "info" bits arrangement
	 * bits  0-15: vlen (e.g. # of struct's members)
	 * bits 16-23: unused
	 * bits 24-28: kind (e.g. int, ptr, array...etc)
	 * bits 29-30: unused
	 * bits    31: root
	 * bits 24-27: kind (e.g. int, ptr, array...etc)
	 * bits 28-31: unused
	 */
	__u32 info;
	/* "size" is used by INT, ENUM, STRUCT and UNION.
@@ -62,8 +49,7 @@ struct btf_type {
	};
};

#define BTF_INFO_KIND(info)	(((info) >> 24) & 0x1f)
#define BTF_INFO_ISROOT(info)	(!!(((info) >> 24) & 0x80))
#define BTF_INFO_KIND(info)	(((info) >> 24) & 0x0f)
#define BTF_INFO_VLEN(info)	((info) & 0xffff)

#define BTF_KIND_UNKN		0	/* Unknown	*/
@@ -88,15 +74,14 @@ struct btf_type {
/* BTF_KIND_INT is followed by a u32 and the following
 * is the 32 bits arrangement:
 */
#define BTF_INT_ENCODING(VAL)	(((VAL) & 0xff000000) >> 24)
#define BTF_INT_ENCODING(VAL)	(((VAL) & 0x0f000000) >> 24)
#define BTF_INT_OFFSET(VAL)	(((VAL  & 0x00ff0000)) >> 16)
#define BTF_INT_BITS(VAL)	((VAL)  & 0x0000ffff)

/* Attributes stored in the BTF_INT_ENCODING */
#define BTF_INT_SIGNED	0x1
#define BTF_INT_CHAR	0x2
#define BTF_INT_BOOL	0x4
#define BTF_INT_VARARGS	0x8
#define BTF_INT_SIGNED	(1 << 0)
#define BTF_INT_CHAR	(1 << 1)
#define BTF_INT_BOOL	(1 << 2)

/* BTF_KIND_ENUM is followed by multiple "struct btf_enum".
 * The exact number of btf_enum is stored in the vlen (of the
+1 −1
Original line number Diff line number Diff line
@@ -352,7 +352,7 @@ static void array_map_seq_show_elem(struct bpf_map *map, void *key,
	}

	seq_printf(m, "%u: ", *(u32 *)key);
	btf_type_seq_show(map->btf, map->btf_value_id, value, m);
	btf_type_seq_show(map->btf, map->btf_value_type_id, value, m);
	seq_puts(m, "\n");

	rcu_read_unlock();
+246 −89
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/idr.h>
#include <linux/sort.h>
#include <linux/bpf_verifier.h>
#include <linux/btf.h>

@@ -162,13 +163,16 @@
#define BITS_ROUNDUP_BYTES(bits) \
	(BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))

#define BTF_INFO_MASK 0x0f00ffff
#define BTF_INT_MASK 0x0fffffff
#define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE)
#define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET)

/* 16MB for 64k structs and each has 16 members and
 * a few MB spaces for the string section.
 * The hard limit is S32_MAX.
 */
#define BTF_MAX_SIZE (16 * 1024 * 1024)
/* 64k. We can raise it later. The hard limit is S32_MAX. */
#define BTF_MAX_NR_TYPES 65535

#define for_each_member(i, struct_type, member)			\
	for (i = 0, member = btf_type_member(struct_type);	\
@@ -184,15 +188,13 @@ static DEFINE_IDR(btf_idr);
static DEFINE_SPINLOCK(btf_idr_lock);

struct btf {
	union {
		struct btf_header *hdr;
	void *data;
	};
	struct btf_type **types;
	u32 *resolved_ids;
	u32 *resolved_sizes;
	const char *strings;
	void *nohdr_data;
	struct btf_header hdr;
	u32 nr_types;
	u32 types_size;
	u32 data_size;
@@ -228,6 +230,11 @@ enum resolve_mode {

#define MAX_RESOLVE_DEPTH 32

struct btf_sec_info {
	u32 off;
	u32 len;
};

struct btf_verifier_env {
	struct btf *btf;
	u8 *visit_states;
@@ -379,8 +386,6 @@ static const char *btf_int_encoding_str(u8 encoding)
		return "CHAR";
	else if (encoding == BTF_INT_BOOL)
		return "BOOL";
	else if (encoding == BTF_INT_VARARGS)
		return "VARARGS";
	else
		return "UNKN";
}
@@ -417,16 +422,16 @@ static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t)

static bool btf_name_offset_valid(const struct btf *btf, u32 offset)
{
	return !BTF_STR_TBL_ELF_ID(offset) &&
		BTF_STR_OFFSET(offset) < btf->hdr->str_len;
	return BTF_STR_OFFSET_VALID(offset) &&
		offset < btf->hdr.str_len;
}

static const char *btf_name_by_offset(const struct btf *btf, u32 offset)
{
	if (!BTF_STR_OFFSET(offset))
	if (!offset)
		return "(anon)";
	else if (BTF_STR_OFFSET(offset) < btf->hdr->str_len)
		return &btf->strings[BTF_STR_OFFSET(offset)];
	else if (offset < btf->hdr.str_len)
		return &btf->strings[offset];
	else
		return "(invalid-name-offset)";
}
@@ -439,6 +444,28 @@ static const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id)
	return btf->types[type_id];
}

/*
 * Regular int is not a bit field and it must be either
 * u8/u16/u32/u64.
 */
static bool btf_type_int_is_regular(const struct btf_type *t)
{
	u16 nr_bits, nr_bytes;
	u32 int_data;

	int_data = btf_type_int(t);
	nr_bits = BTF_INT_BITS(int_data);
	nr_bytes = BITS_ROUNDUP_BYTES(nr_bits);
	if (BITS_PER_BYTE_MASKED(nr_bits) ||
	    BTF_INT_OFFSET(int_data) ||
	    (nr_bytes != sizeof(u8) && nr_bytes != sizeof(u16) &&
	     nr_bytes != sizeof(u32) && nr_bytes != sizeof(u64))) {
		return false;
	}

	return true;
}

__printf(2, 3) static void __btf_verifier_log(struct bpf_verifier_log *log,
					      const char *fmt, ...)
{
@@ -536,7 +563,8 @@ static void btf_verifier_log_member(struct btf_verifier_env *env,
	__btf_verifier_log(log, "\n");
}

static void btf_verifier_log_hdr(struct btf_verifier_env *env)
static void btf_verifier_log_hdr(struct btf_verifier_env *env,
				 u32 btf_data_size)
{
	struct bpf_verifier_log *log = &env->log;
	const struct btf *btf = env->btf;
@@ -545,19 +573,16 @@ static void btf_verifier_log_hdr(struct btf_verifier_env *env)
	if (!bpf_verifier_log_needed(log))
		return;

	hdr = btf->hdr;
	hdr = &btf->hdr;
	__btf_verifier_log(log, "magic: 0x%x\n", hdr->magic);
	__btf_verifier_log(log, "version: %u\n", hdr->version);
	__btf_verifier_log(log, "flags: 0x%x\n", hdr->flags);
	__btf_verifier_log(log, "parent_label: %u\n", hdr->parent_label);
	__btf_verifier_log(log, "parent_name: %u\n", hdr->parent_name);
	__btf_verifier_log(log, "label_off: %u\n", hdr->label_off);
	__btf_verifier_log(log, "object_off: %u\n", hdr->object_off);
	__btf_verifier_log(log, "func_off: %u\n", hdr->func_off);
	__btf_verifier_log(log, "hdr_len: %u\n", hdr->hdr_len);
	__btf_verifier_log(log, "type_off: %u\n", hdr->type_off);
	__btf_verifier_log(log, "type_len: %u\n", hdr->type_len);
	__btf_verifier_log(log, "str_off: %u\n", hdr->str_off);
	__btf_verifier_log(log, "str_len: %u\n", hdr->str_len);
	__btf_verifier_log(log, "btf_total_size: %u\n", btf->data_size);
	__btf_verifier_log(log, "btf_total_size: %u\n", btf_data_size);
}

static int btf_add_type(struct btf_verifier_env *env, struct btf_type *t)
@@ -574,13 +599,13 @@ static int btf_add_type(struct btf_verifier_env *env, struct btf_type *t)
		struct btf_type **new_types;
		u32 expand_by, new_size;

		if (btf->types_size == BTF_MAX_NR_TYPES) {
		if (btf->types_size == BTF_MAX_TYPE) {
			btf_verifier_log(env, "Exceeded max num of types");
			return -E2BIG;
		}

		expand_by = max_t(u32, btf->types_size >> 2, 16);
		new_size = min_t(u32, BTF_MAX_NR_TYPES,
		new_size = min_t(u32, BTF_MAX_TYPE,
				 btf->types_size + expand_by);

		new_types = kvzalloc(new_size * sizeof(*new_types),
@@ -910,6 +935,12 @@ static s32 btf_int_check_meta(struct btf_verifier_env *env,
	}

	int_data = btf_type_int(t);
	if (int_data & ~BTF_INT_MASK) {
		btf_verifier_log_basic(env, t, "Invalid int_data:%x",
				       int_data);
		return -EINVAL;
	}

	nr_bits = BTF_INT_BITS(int_data) + BTF_INT_OFFSET(int_data);

	if (nr_bits > BITS_PER_U64) {
@@ -923,12 +954,17 @@ static s32 btf_int_check_meta(struct btf_verifier_env *env,
		return -EINVAL;
	}

	/*
	 * Only one of the encoding bits is allowed and it
	 * should be sufficient for the pretty print purpose (i.e. decoding).
	 * Multiple bits can be allowed later if it is found
	 * to be insufficient.
	 */
	encoding = BTF_INT_ENCODING(int_data);
	if (encoding &&
	    encoding != BTF_INT_SIGNED &&
	    encoding != BTF_INT_CHAR &&
	    encoding != BTF_INT_BOOL &&
	    encoding != BTF_INT_VARARGS) {
	    encoding != BTF_INT_BOOL) {
		btf_verifier_log_type(env, t, "Unsupported encoding");
		return -ENOTSUPP;
	}
@@ -1102,7 +1138,7 @@ static int btf_ref_type_check_meta(struct btf_verifier_env *env,
		return -EINVAL;
	}

	if (BTF_TYPE_PARENT(t->type)) {
	if (!BTF_TYPE_ID_VALID(t->type)) {
		btf_verifier_log_type(env, t, "Invalid type_id");
		return -EINVAL;
	}
@@ -1306,14 +1342,16 @@ static s32 btf_array_check_meta(struct btf_verifier_env *env,
		return -EINVAL;
	}

	/* We are a little forgiving on array->index_type since
	 * the kernel is not using it.
	 */
	/* Array elem cannot be in type void,
	 * so !array->type is not allowed.
	/* Array elem type and index type cannot be in type void,
	 * so !array->type and !array->index_type are not allowed.
	 */
	if (!array->type || BTF_TYPE_PARENT(array->type)) {
		btf_verifier_log_type(env, t, "Invalid type_id");
	if (!array->type || !BTF_TYPE_ID_VALID(array->type)) {
		btf_verifier_log_type(env, t, "Invalid elem");
		return -EINVAL;
	}

	if (!array->index_type || !BTF_TYPE_ID_VALID(array->index_type)) {
		btf_verifier_log_type(env, t, "Invalid index");
		return -EINVAL;
	}

@@ -1326,11 +1364,32 @@ static int btf_array_resolve(struct btf_verifier_env *env,
			     const struct resolve_vertex *v)
{
	const struct btf_array *array = btf_type_array(v->t);
	const struct btf_type *elem_type;
	u32 elem_type_id = array->type;
	const struct btf_type *elem_type, *index_type;
	u32 elem_type_id, index_type_id;
	struct btf *btf = env->btf;
	u32 elem_size;

	/* Check array->index_type */
	index_type_id = array->index_type;
	index_type = btf_type_by_id(btf, index_type_id);
	if (btf_type_is_void_or_null(index_type)) {
		btf_verifier_log_type(env, v->t, "Invalid index");
		return -EINVAL;
	}

	if (!env_type_is_resolve_sink(env, index_type) &&
	    !env_type_is_resolved(env, index_type_id))
		return env_stack_push(env, index_type, index_type_id);

	index_type = btf_type_id_size(btf, &index_type_id, NULL);
	if (!index_type || !btf_type_is_int(index_type) ||
	    !btf_type_int_is_regular(index_type)) {
		btf_verifier_log_type(env, v->t, "Invalid index");
		return -EINVAL;
	}

	/* Check array->type */
	elem_type_id = array->type;
	elem_type = btf_type_by_id(btf, elem_type_id);
	if (btf_type_is_void_or_null(elem_type)) {
		btf_verifier_log_type(env, v->t,
@@ -1348,23 +1407,10 @@ static int btf_array_resolve(struct btf_verifier_env *env,
		return -EINVAL;
	}

	if (btf_type_is_int(elem_type)) {
		int int_type_data = btf_type_int(elem_type);
		u16 nr_bits = BTF_INT_BITS(int_type_data);
		u16 nr_bytes = BITS_ROUNDUP_BYTES(nr_bits);

		/* Put more restriction on array of int.  The int cannot
		 * be a bit field and it must be either u8/u16/u32/u64.
		 */
		if (BITS_PER_BYTE_MASKED(nr_bits) ||
		    BTF_INT_OFFSET(int_type_data) ||
		    (nr_bytes != sizeof(u8) && nr_bytes != sizeof(u16) &&
		     nr_bytes != sizeof(u32) && nr_bytes != sizeof(u64))) {
			btf_verifier_log_type(env, v->t,
					      "Invalid array of int");
	if (btf_type_is_int(elem_type) && !btf_type_int_is_regular(elem_type)) {
		btf_verifier_log_type(env, v->t, "Invalid array of int");
		return -EINVAL;
	}
	}

	if (array->nelems && elem_size > U32_MAX / array->nelems) {
		btf_verifier_log_type(env, v->t,
@@ -1473,7 +1519,7 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
		}

		/* A member cannot be in type void */
		if (!member->type || BTF_TYPE_PARENT(member->type)) {
		if (!member->type || !BTF_TYPE_ID_VALID(member->type)) {
			btf_verifier_log_member(env, t, member,
						"Invalid type_id");
			return -EINVAL;
@@ -1726,6 +1772,12 @@ static s32 btf_check_meta(struct btf_verifier_env *env,
	}
	meta_left -= sizeof(*t);

	if (t->info & ~BTF_INFO_MASK) {
		btf_verifier_log(env, "[%u] Invalid btf_info:%x",
				 env->log_type_id, t->info);
		return -EINVAL;
	}

	if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX ||
	    BTF_INFO_KIND(t->info) == BTF_KIND_UNKN) {
		btf_verifier_log(env, "[%u] Invalid kind:%u",
@@ -1754,9 +1806,9 @@ static int btf_check_all_metas(struct btf_verifier_env *env)
	struct btf_header *hdr;
	void *cur, *end;

	hdr = btf->hdr;
	hdr = &btf->hdr;
	cur = btf->nohdr_data + hdr->type_off;
	end = btf->nohdr_data + hdr->str_off;
	end = btf->nohdr_data + hdr->type_len;

	env->log_type_id = 1;
	while (cur < end) {
@@ -1866,8 +1918,20 @@ static int btf_check_all_types(struct btf_verifier_env *env)

static int btf_parse_type_sec(struct btf_verifier_env *env)
{
	const struct btf_header *hdr = &env->btf->hdr;
	int err;

	/* Type section must align to 4 bytes */
	if (hdr->type_off & (sizeof(u32) - 1)) {
		btf_verifier_log(env, "Unaligned type_off");
		return -EINVAL;
	}

	if (!hdr->type_len) {
		btf_verifier_log(env, "No type found");
		return -EINVAL;
	}

	err = btf_check_all_metas(env);
	if (err)
		return err;
@@ -1881,10 +1945,15 @@ static int btf_parse_str_sec(struct btf_verifier_env *env)
	struct btf *btf = env->btf;
	const char *start, *end;

	hdr = btf->hdr;
	hdr = &btf->hdr;
	start = btf->nohdr_data + hdr->str_off;
	end = start + hdr->str_len;

	if (end != btf->data + btf->data_size) {
		btf_verifier_log(env, "String section is not at the end");
		return -EINVAL;
	}

	if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_NAME_OFFSET ||
	    start[0] || end[-1]) {
		btf_verifier_log(env, "Invalid string section");
@@ -1896,20 +1965,122 @@ static int btf_parse_str_sec(struct btf_verifier_env *env)
	return 0;
}

static int btf_parse_hdr(struct btf_verifier_env *env)
static const size_t btf_sec_info_offset[] = {
	offsetof(struct btf_header, type_off),
	offsetof(struct btf_header, str_off),
};

static int btf_sec_info_cmp(const void *a, const void *b)
{
	const struct btf_sec_info *x = a;
	const struct btf_sec_info *y = b;

	return (int)(x->off - y->off) ? : (int)(x->len - y->len);
}

static int btf_check_sec_info(struct btf_verifier_env *env,
			      u32 btf_data_size)
{
	const unsigned int nr_secs = ARRAY_SIZE(btf_sec_info_offset);
	struct btf_sec_info secs[nr_secs];
	u32 total, expected_total, i;
	const struct btf_header *hdr;
	const struct btf *btf;

	btf = env->btf;
	hdr = &btf->hdr;

	/* Populate the secs from hdr */
	for (i = 0; i < nr_secs; i++)
		secs[i] = *(struct btf_sec_info *)((void *)hdr +
						   btf_sec_info_offset[i]);

	sort(secs, nr_secs, sizeof(struct btf_sec_info),
	     btf_sec_info_cmp, NULL);

	/* Check for gaps and overlap among sections */
	total = 0;
	expected_total = btf_data_size - hdr->hdr_len;
	for (i = 0; i < nr_secs; i++) {
		if (expected_total < secs[i].off) {
			btf_verifier_log(env, "Invalid section offset");
			return -EINVAL;
		}
		if (total < secs[i].off) {
			/* gap */
			btf_verifier_log(env, "Unsupported section found");
			return -EINVAL;
		}
		if (total > secs[i].off) {
			btf_verifier_log(env, "Section overlap found");
			return -EINVAL;
		}
		if (expected_total - total < secs[i].len) {
			btf_verifier_log(env,
					 "Total section length too long");
			return -EINVAL;
		}
		total += secs[i].len;
	}

	/* There is data other than hdr and known sections */
	if (expected_total != total) {
		btf_verifier_log(env, "Unsupported section found");
		return -EINVAL;
	}

	return 0;
}

static int btf_parse_hdr(struct btf_verifier_env *env, void __user *btf_data,
			 u32 btf_data_size)
{
	const struct btf_header *hdr;
	struct btf *btf = env->btf;
	u32 meta_left;
	u32 hdr_len, hdr_copy;
	/*
	 * Minimal part of the "struct btf_header" that
	 * contains the hdr_len.
	 */
	struct btf_min_header {
		u16	magic;
		u8	version;
		u8	flags;
		u32	hdr_len;
	} __user *min_hdr;
	struct btf *btf;
	int err;

	btf = env->btf;
	min_hdr = btf_data;

	if (btf->data_size < sizeof(*hdr)) {
	if (btf_data_size < sizeof(*min_hdr)) {
		btf_verifier_log(env, "hdr_len not found");
		return -EINVAL;
	}

	if (get_user(hdr_len, &min_hdr->hdr_len))
		return -EFAULT;

	if (btf_data_size < hdr_len) {
		btf_verifier_log(env, "btf_header not found");
		return -EINVAL;
	}

	btf_verifier_log_hdr(env);
	err = bpf_check_uarg_tail_zero(btf_data, sizeof(btf->hdr), hdr_len);
	if (err) {
		if (err == -E2BIG)
			btf_verifier_log(env, "Unsupported btf_header");
		return err;
	}

	hdr_copy = min_t(u32, hdr_len, sizeof(btf->hdr));
	if (copy_from_user(&btf->hdr, btf_data, hdr_copy))
		return -EFAULT;

	hdr = &btf->hdr;

	btf_verifier_log_hdr(env, btf_data_size);

	hdr = btf->hdr;
	if (hdr->magic != BTF_MAGIC) {
		btf_verifier_log(env, "Invalid magic");
		return -EINVAL;
@@ -1925,26 +2096,14 @@ static int btf_parse_hdr(struct btf_verifier_env *env)
		return -ENOTSUPP;
	}

	meta_left = btf->data_size - sizeof(*hdr);
	if (!meta_left) {
	if (btf_data_size == hdr->hdr_len) {
		btf_verifier_log(env, "No data");
		return -EINVAL;
	}

	if (meta_left < hdr->type_off || hdr->str_off <= hdr->type_off ||
	    /* Type section must align to 4 bytes */
	    hdr->type_off & (sizeof(u32) - 1)) {
		btf_verifier_log(env, "Invalid type_off");
		return -EINVAL;
	}

	if (meta_left < hdr->str_off ||
	    meta_left - hdr->str_off < hdr->str_len) {
		btf_verifier_log(env, "Invalid str_off or str_len");
		return -EINVAL;
	}

	btf->nohdr_data = btf->hdr + 1;
	err = btf_check_sec_info(env, btf_data_size);
	if (err)
		return err;

	return 0;
}
@@ -1987,6 +2146,11 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
		err = -ENOMEM;
		goto errout;
	}
	env->btf = btf;

	err = btf_parse_hdr(env, btf_data, btf_data_size);
	if (err)
		goto errout;

	data = kvmalloc(btf_data_size, GFP_KERNEL | __GFP_NOWARN);
	if (!data) {
@@ -1996,18 +2160,13 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,

	btf->data = data;
	btf->data_size = btf_data_size;
	btf->nohdr_data = btf->data + btf->hdr.hdr_len;

	if (copy_from_user(data, btf_data, btf_data_size)) {
		err = -EFAULT;
		goto errout;
	}

	env->btf = btf;

	err = btf_parse_hdr(env);
	if (err)
		goto errout;

	err = btf_parse_str_sec(env);
	if (err)
		goto errout;
@@ -2016,16 +2175,14 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
	if (err)
		goto errout;

	if (!err && log->level && bpf_verifier_log_full(log)) {
	if (log->level && bpf_verifier_log_full(log)) {
		err = -ENOSPC;
		goto errout;
	}

	if (!err) {
	btf_verifier_env_free(env);
	refcount_set(&btf->refcnt, 1);
	return btf;
	}

errout:
	btf_verifier_env_free(env);
Loading