Unverified Commit b61a367a authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!13988 CVE-2024-49861

Merge Pull Request from: @ci-robot 
 
PR sync from: Xiaomeng Zhang <zhangxiaomeng13@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/MZQRUMGGHM267KXBCARYNNKBOH2OKSI5/ 
*** BLURB HERE ***

Daniel Borkmann (6):
  [Backport] bpf: Fix bpf_strtol and bpf_strtoul helpers for 32bit
  [Backport] bpf: Remove truncation test in bpf_strtol and bpf_strtoul
    helpers
  bpf: Fix helper writes to read-only maps
    types
  [Backport] selftests/bpf: Fix ARG_PTR_TO_LONG {half-,}uninitialized
    test
  [Backport] selftests/bpf: Rename ARG_PTR_TO_LONG test description

Joanne Koong (1):
  bpf: Add MEM_UNINIT as a bpf_type_flag

Maxim Mikityanskiy (1):
  bpf: Allow helpers to accept pointers with a fixed size

Xiaomeng Zhang (1):
  bpf: Fix kabi breakage in enum bpf_type_flag


-- 
2.34.1
 
https://gitee.com/src-openeuler/kernel/issues/IAYQOP 
 
Link:https://gitee.com/openeuler/kernel/pulls/13988

 

Reviewed-by: default avatarYe Weihua <yeweihua4@huawei.com>
Reviewed-by: default avatarXu Kuohai <xukuohai@huawei.com>
Reviewed-by: default avatarLi Nan <linan122@huawei.com>
Signed-off-by: default avatarLi Nan <linan122@huawei.com>
parents 21a6ff57 b32afb13
Loading
Loading
Loading
Loading
+29 −10
Original line number Diff line number Diff line
@@ -290,7 +290,19 @@ enum bpf_type_flag {
	 */
	MEM_ALLOC		= BIT(2 + BPF_BASE_TYPE_BITS),

	__BPF_TYPE_LAST_FLAG	= MEM_ALLOC,
	KABI_BROKEN_INSERT_ENUM(MEM_UNINIT = BIT(7 + BPF_BASE_TYPE_BITS))

	/* Size is known at compile time. */
	KABI_BROKEN_INSERT_ENUM(MEM_FIXED_SIZE = BIT(10 + BPF_BASE_TYPE_BITS))

	/* Memory must be aligned on some architectures, used in combination with
	 * MEM_FIXED_SIZE.
	 */
	KABI_BROKEN_INSERT_ENUM(MEM_ALIGNED = BIT(17 + BPF_BASE_TYPE_BITS))

	KABI_BROKEN_INSERT_ENUM(__BPF_TYPE_FLAG_MAX)
	KABI_BROKEN_REMOVE_ENUM(__BPF_TYPE_LAST_FLAG = MEM_ALLOC)
	KABI_BROKEN_INSERT_ENUM(__BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1)
};

/* Max number of base types. */
@@ -309,16 +321,11 @@ enum bpf_arg_type {
	ARG_CONST_MAP_PTR,	/* const argument used as pointer to bpf_map */
	ARG_PTR_TO_MAP_KEY,	/* pointer to stack used as map key */
	ARG_PTR_TO_MAP_VALUE,	/* pointer to stack used as map value */
	ARG_PTR_TO_UNINIT_MAP_VALUE,	/* pointer to valid memory used to store a map value */

	/* the following constraints used to prototype bpf_memcmp() and other
	 * functions that access data on eBPF program stack
	/* Used to prototype bpf_memcmp() and other functions that access data
	 * on eBPF program stack
	 */
	ARG_PTR_TO_MEM,		/* pointer to valid memory (stack, packet, map value) */
	ARG_PTR_TO_UNINIT_MEM,	/* pointer to memory does not need to be initialized,
				 * helper function must fill all bytes or clear
				 * them in error case.
				 */

	ARG_CONST_SIZE,		/* number of bytes accessed from memory */
	ARG_CONST_SIZE_OR_ZERO,	/* number of bytes accessed from memory or 0 */
@@ -327,8 +334,6 @@ enum bpf_arg_type {
	ARG_ANYTHING,		/* any (initialized) argument is ok */
	ARG_PTR_TO_SPIN_LOCK,	/* pointer to bpf_spin_lock */
	ARG_PTR_TO_SOCK_COMMON,	/* pointer to sock_common */
	ARG_PTR_TO_INT,		/* pointer to int */
	ARG_PTR_TO_LONG,	/* pointer to long */
	ARG_PTR_TO_SOCKET,	/* pointer to bpf_sock (fullsock) */
	ARG_PTR_TO_BTF_ID,	/* pointer to in-kernel struct */
	ARG_PTR_TO_ALLOC_MEM,	/* pointer to dynamically allocated memory */
@@ -343,6 +348,12 @@ enum bpf_arg_type {
	ARG_PTR_TO_CTX_OR_NULL		= PTR_MAYBE_NULL | ARG_PTR_TO_CTX,
	ARG_PTR_TO_SOCKET_OR_NULL	= PTR_MAYBE_NULL | ARG_PTR_TO_SOCKET,
	ARG_PTR_TO_ALLOC_MEM_OR_NULL	= PTR_MAYBE_NULL | ARG_PTR_TO_ALLOC_MEM,
	/* pointer to memory does not need to be initialized, helper function must fill
	 * all bytes or clear them in error case.
	 */
	ARG_PTR_TO_UNINIT_MEM		= MEM_UNINIT | ARG_PTR_TO_MEM,
	/* Pointer to valid memory of size known at compile time. */
	ARG_PTR_TO_FIXED_SIZE_MEM	= MEM_FIXED_SIZE | ARG_PTR_TO_MEM,

	/* This must be the last entry. Its purpose is to ensure the enum is
	 * wide enough to hold the higher bits reserved for bpf_type_flag.
@@ -407,6 +418,14 @@ struct bpf_func_proto {
			u32 *arg5_btf_id;
		};
		u32 *arg_btf_id[5];
		struct {
			size_t arg1_size;
			size_t arg2_size;
			size_t arg3_size;
			size_t arg4_size;
			size_t arg5_size;
		};
		size_t arg_size[5];
	};
	int *ret_btf_id; /* return value btf_id */
	bool (*allowed)(const struct bpf_prog *prog);
+8 −10
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ const struct bpf_func_proto bpf_map_pop_elem_proto = {
	.gpl_only	= false,
	.ret_type	= RET_INTEGER,
	.arg1_type	= ARG_CONST_MAP_PTR,
	.arg2_type	= ARG_PTR_TO_UNINIT_MAP_VALUE,
	.arg2_type	= ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
};

BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
@@ -114,7 +114,7 @@ const struct bpf_func_proto bpf_map_peek_elem_proto = {
	.gpl_only	= false,
	.ret_type	= RET_INTEGER,
	.arg1_type	= ARG_CONST_MAP_PTR,
	.arg2_type	= ARG_PTR_TO_UNINIT_MAP_VALUE,
	.arg2_type	= ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
};

const struct bpf_func_proto bpf_get_prandom_u32_proto = {
@@ -484,7 +484,7 @@ static int __bpf_strtoll(const char *buf, size_t buf_len, u64 flags,
}

BPF_CALL_4(bpf_strtol, const char *, buf, size_t, buf_len, u64, flags,
	   long *, res)
	   s64 *, res)
{
	long long _res;
	int err;
@@ -493,8 +493,6 @@ BPF_CALL_4(bpf_strtol, const char *, buf, size_t, buf_len, u64, flags,
	err = __bpf_strtoll(buf, buf_len, flags, &_res);
	if (err < 0)
		return err;
	if (_res != (long)_res)
		return -ERANGE;
	*res = _res;
	return err;
}
@@ -506,11 +504,12 @@ const struct bpf_func_proto bpf_strtol_proto = {
	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
	.arg2_type	= ARG_CONST_SIZE,
	.arg3_type	= ARG_ANYTHING,
	.arg4_type	= ARG_PTR_TO_LONG,
	.arg4_type	= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
	.arg4_size	= sizeof(s64),
};

BPF_CALL_4(bpf_strtoul, const char *, buf, size_t, buf_len, u64, flags,
	   unsigned long *, res)
	   u64 *, res)
{
	unsigned long long _res;
	bool is_negative;
@@ -522,8 +521,6 @@ BPF_CALL_4(bpf_strtoul, const char *, buf, size_t, buf_len, u64, flags,
		return err;
	if (is_negative)
		return -EINVAL;
	if (_res != (unsigned long)_res)
		return -ERANGE;
	*res = _res;
	return err;
}
@@ -535,7 +532,8 @@ const struct bpf_func_proto bpf_strtoul_proto = {
	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
	.arg2_type	= ARG_CONST_SIZE,
	.arg3_type	= ARG_ANYTHING,
	.arg4_type	= ARG_PTR_TO_LONG,
	.arg4_type	= ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
	.arg4_size	= sizeof(u64),
};

BPF_CALL_4(bpf_get_ns_current_pid_tgid, u64, dev, u64, ino,
+49 −66
Original line number Diff line number Diff line
@@ -4700,37 +4700,21 @@ static int process_spin_lock(struct bpf_verifier_env *env, int regno,
	return 0;
}

static bool arg_type_is_mem_ptr(enum bpf_arg_type type)
{
	return base_type(type) == ARG_PTR_TO_MEM ||
	       base_type(type) == ARG_PTR_TO_UNINIT_MEM;
}

static bool arg_type_is_mem_size(enum bpf_arg_type type)
{
	return type == ARG_CONST_SIZE ||
	       type == ARG_CONST_SIZE_OR_ZERO;
}

static bool arg_type_is_alloc_size(enum bpf_arg_type type)
{
	return type == ARG_CONST_ALLOC_SIZE_OR_ZERO;
}

static bool arg_type_is_int_ptr(enum bpf_arg_type type)
static bool arg_type_is_raw_mem(enum bpf_arg_type type)
{
	return type == ARG_PTR_TO_INT ||
	       type == ARG_PTR_TO_LONG;
	return base_type(type) == ARG_PTR_TO_MEM &&
		type & MEM_UNINIT;
}

static int int_ptr_type_to_size(enum bpf_arg_type type)
static bool arg_type_is_alloc_size(enum bpf_arg_type type)
{
	if (type == ARG_PTR_TO_INT)
		return sizeof(u32);
	else if (type == ARG_PTR_TO_LONG)
		return sizeof(u64);

	return -EINVAL;
	return type == ARG_CONST_ALLOC_SIZE_OR_ZERO;
}

static int resolve_map_arg_type(struct bpf_verifier_env *env,
@@ -4808,15 +4792,6 @@ static const struct bpf_reg_types mem_types = {
	},
};

static const struct bpf_reg_types int_ptr_types = {
	.types = {
		PTR_TO_STACK,
		PTR_TO_PACKET,
		PTR_TO_PACKET_META,
		PTR_TO_MAP_VALUE,
	},
};

static const struct bpf_reg_types fullsock_types = { .types = { PTR_TO_SOCKET } };
static const struct bpf_reg_types scalar_types = { .types = { SCALAR_VALUE } };
static const struct bpf_reg_types context_types = { .types = { PTR_TO_CTX } };
@@ -4829,7 +4804,6 @@ static const struct bpf_reg_types percpu_btf_ptr_types = { .types = { PTR_TO_PER
static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
	[ARG_PTR_TO_MAP_KEY]		= &map_key_value_types,
	[ARG_PTR_TO_MAP_VALUE]		= &map_key_value_types,
	[ARG_PTR_TO_UNINIT_MAP_VALUE]	= &map_key_value_types,
	[ARG_CONST_SIZE]		= &scalar_types,
	[ARG_CONST_SIZE_OR_ZERO]	= &scalar_types,
	[ARG_CONST_ALLOC_SIZE_OR_ZERO]	= &scalar_types,
@@ -4843,10 +4817,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
	[ARG_PTR_TO_BTF_ID]		= &btf_ptr_types,
	[ARG_PTR_TO_SPIN_LOCK]		= &spin_lock_types,
	[ARG_PTR_TO_MEM]		= &mem_types,
	[ARG_PTR_TO_UNINIT_MEM]		= &mem_types,
	[ARG_PTR_TO_ALLOC_MEM]		= &alloc_mem_types,
	[ARG_PTR_TO_INT]		= &int_ptr_types,
	[ARG_PTR_TO_LONG]		= &int_ptr_types,
	[ARG_PTR_TO_PERCPU_BTF_ID]	= &percpu_btf_ptr_types,
};

@@ -4925,6 +4896,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
	struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
	enum bpf_arg_type arg_type = fn->arg_type[arg];
	enum bpf_reg_type type = reg->type;
	u32 *arg_btf_id = NULL;
	int err = 0;

	if (arg_type == ARG_DONTCARE)
@@ -4949,8 +4921,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
		return -EACCES;
	}

	if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE ||
	    base_type(arg_type) == ARG_PTR_TO_UNINIT_MAP_VALUE) {
	if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE) {
		err = resolve_map_arg_type(env, meta, &arg_type);
		if (err)
			return err;
@@ -4962,7 +4933,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
		 */
		goto skip_type_check;

	err = check_reg_type(env, regno, arg_type, fn->arg_btf_id[arg]);
	/* arg_btf_id and arg_size are in a union. */
	if (base_type(arg_type) == ARG_PTR_TO_BTF_ID)
		arg_btf_id = fn->arg_btf_id[arg];

	err = check_reg_type(env, regno, arg_type, arg_btf_id);
	if (err)
		return err;

@@ -5025,8 +5000,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
		err = check_helper_mem_access(env, regno,
					      meta->map_ptr->key_size, false,
					      NULL);
	} else if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE ||
		   base_type(arg_type) == ARG_PTR_TO_UNINIT_MAP_VALUE) {
	} else if (base_type(arg_type) == ARG_PTR_TO_MAP_VALUE) {
		if (type_may_be_null(arg_type) && register_is_null(reg))
			return 0;

@@ -5038,7 +5012,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
			verbose(env, "invalid map_ptr to access map->value\n");
			return -EACCES;
		}
		meta->raw_mode = (arg_type == ARG_PTR_TO_UNINIT_MAP_VALUE);
		meta->raw_mode = arg_type & MEM_UNINIT;
		err = check_helper_mem_access(env, regno,
					      meta->map_ptr->value_size, false,
					      meta);
@@ -5059,11 +5033,18 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
			verbose(env, "verifier internal error\n");
			return -EFAULT;
		}
	} else if (arg_type_is_mem_ptr(arg_type)) {
	} else if (base_type(arg_type) == ARG_PTR_TO_MEM) {
		/* The access to this pointer is only checked when we hit the
		 * next is_mem_size argument below.
		 */
		meta->raw_mode = (arg_type == ARG_PTR_TO_UNINIT_MEM);
		meta->raw_mode = arg_type & MEM_UNINIT;
		if (arg_type & MEM_FIXED_SIZE) {
			err = check_helper_mem_access(env, regno, fn->arg_size[arg], false, meta);
			if (err)
				return err;
			if (arg_type & MEM_ALIGNED)
				err = check_ptr_alignment(env, reg, 0, fn->arg_size[arg], true);
		}
	} else if (arg_type_is_mem_size(arg_type)) {
		bool zero_size_allowed = (arg_type == ARG_CONST_SIZE_OR_ZERO);

@@ -5119,13 +5100,6 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
			return -EACCES;
		}
		meta->mem_size = reg->var_off.value;
	} else if (arg_type_is_int_ptr(arg_type)) {
		int size = int_ptr_type_to_size(arg_type);

		err = check_helper_mem_access(env, regno, size, false, meta);
		if (err)
			return err;
		err = check_ptr_alignment(env, reg, 0, size, true);
	}

	return err;
@@ -5375,15 +5349,15 @@ static bool check_raw_mode_ok(const struct bpf_func_proto *fn)
{
	int count = 0;

	if (fn->arg1_type == ARG_PTR_TO_UNINIT_MEM)
	if (arg_type_is_raw_mem(fn->arg1_type))
		count++;
	if (fn->arg2_type == ARG_PTR_TO_UNINIT_MEM)
	if (arg_type_is_raw_mem(fn->arg2_type))
		count++;
	if (fn->arg3_type == ARG_PTR_TO_UNINIT_MEM)
	if (arg_type_is_raw_mem(fn->arg3_type))
		count++;
	if (fn->arg4_type == ARG_PTR_TO_UNINIT_MEM)
	if (arg_type_is_raw_mem(fn->arg4_type))
		count++;
	if (fn->arg5_type == ARG_PTR_TO_UNINIT_MEM)
	if (arg_type_is_raw_mem(fn->arg5_type))
		count++;

	/* We only support one arg being in raw mode at the moment,
@@ -5393,13 +5367,19 @@ static bool check_raw_mode_ok(const struct bpf_func_proto *fn)
	return count <= 1;
}

static bool check_args_pair_invalid(enum bpf_arg_type arg_curr,
				    enum bpf_arg_type arg_next)
static bool check_args_pair_invalid(const struct bpf_func_proto *fn, int arg)
{
	return (arg_type_is_mem_ptr(arg_curr) &&
	        !arg_type_is_mem_size(arg_next)) ||
	       (!arg_type_is_mem_ptr(arg_curr) &&
		arg_type_is_mem_size(arg_next));
	bool is_fixed = fn->arg_type[arg] & MEM_FIXED_SIZE;
	bool has_size = fn->arg_size[arg] != 0;
	bool is_next_size = false;

	if (arg + 1 < ARRAY_SIZE(fn->arg_type))
		is_next_size = arg_type_is_mem_size(fn->arg_type[arg + 1]);

	if (base_type(fn->arg_type[arg]) != ARG_PTR_TO_MEM)
		return is_next_size;

	return has_size == is_next_size || is_next_size == is_fixed;
}

static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
@@ -5410,11 +5390,11 @@ static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
	 * helper function specification.
	 */
	if (arg_type_is_mem_size(fn->arg1_type) ||
	    arg_type_is_mem_ptr(fn->arg5_type)  ||
	    check_args_pair_invalid(fn->arg1_type, fn->arg2_type) ||
	    check_args_pair_invalid(fn->arg2_type, fn->arg3_type) ||
	    check_args_pair_invalid(fn->arg3_type, fn->arg4_type) ||
	    check_args_pair_invalid(fn->arg4_type, fn->arg5_type))
	    check_args_pair_invalid(fn, 0) ||
	    check_args_pair_invalid(fn, 1) ||
	    check_args_pair_invalid(fn, 2) ||
	    check_args_pair_invalid(fn, 3) ||
	    check_args_pair_invalid(fn, 4))
		return false;

	return true;
@@ -5455,7 +5435,10 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn)
		if (base_type(fn->arg_type[i]) == ARG_PTR_TO_BTF_ID && !fn->arg_btf_id[i])
			return false;

		if (base_type(fn->arg_type[i]) != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i])
		if (base_type(fn->arg_type[i]) != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i] &&
		    /* arg_btf_id and arg_size are in a union. */
		    (base_type(fn->arg_type[i]) != ARG_PTR_TO_MEM ||
		     !(fn->arg_type[i] & MEM_FIXED_SIZE)))
			return false;
	}

+5 −10
Original line number Diff line number Diff line
{
	"ARG_PTR_TO_LONG uninitialized",
	"arg pointer to long uninitialized",
	.insns = {
		/* bpf_strtoul arg1 (buf) */
		BPF_MOV64_REG(BPF_REG_7, BPF_REG_10),
@@ -27,11 +27,9 @@
	},
	.result = ACCEPT,
	.retval = POINTER_VALUE,
	.errstr_unpriv = "invalid indirect read from stack R4 off -16+0 size 8",
	.result_unpriv = REJECT,
},
{
	"ARG_PTR_TO_LONG half-uninitialized",
	"arg pointer to long half-uninitialized",
	.insns = {
		/* bpf_strtoul arg1 (buf) */
		BPF_MOV64_REG(BPF_REG_7, BPF_REG_10),
@@ -58,13 +56,10 @@
		BPF_MOV64_IMM(BPF_REG_0, 0),
		BPF_EXIT_INSN(),
	},
	.result_unpriv = REJECT,
	.errstr_unpriv = "invalid indirect read from stack R4 off -16+4 size 8",
	/* in privileged mode reads from uninitialized stack locations are permitted */
	.result = ACCEPT,
},
{
	"ARG_PTR_TO_LONG misaligned",
	"arg pointer to long misaligned",
	.insns = {
		/* bpf_strtoul arg1 (buf) */
		BPF_MOV64_REG(BPF_REG_7, BPF_REG_10),
@@ -98,7 +93,7 @@
	.errstr = "misaligned stack access off (0x0; 0x0)+-20+0 size 8",
},
{
	"ARG_PTR_TO_LONG size < sizeof(long)",
	"arg pointer to long size < sizeof(long)",
	.insns = {
		/* bpf_strtoul arg1 (buf) */
		BPF_MOV64_REG(BPF_REG_7, BPF_REG_10),
@@ -130,7 +125,7 @@
	.errstr = "invalid indirect access to stack R4 off=-4 size=8",
},
{
	"ARG_PTR_TO_LONG initialized",
	"arg pointer to long initialized",
	.insns = {
		/* bpf_strtoul arg1 (buf) */
		BPF_MOV64_REG(BPF_REG_7, BPF_REG_10),