Commit 53e80a39 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'bpf-core changes for preparation of HID-bpf'

Benjamin Tissoires says:

====================

Hi,

well, given that the HID changes haven't moved a lot in the past
revisions and that I am cc-ing a bunch of people, I have dropped them
while we focus on the last 2 requirements in bpf-core changes.

I'll submit a HID targeted series when we get these in tree, which
would make things a lore more independent.

For reference, the whole reasons for these 2 main changes are at
https://lore.kernel.org/bpf/20220902132938.2409206-1-benjamin.tissoires@redhat.com/



Compared to v10 (in addition of dropping the HID changes), I have
changed the selftests so we can test both light skeletons and libbbpf
calls.

Cheers,
Benjamin
====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 028a9642 22ed8d5a
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -1944,13 +1944,22 @@ int btf_distill_func_proto(struct bpf_verifier_log *log,
			   const char *func_name,
			   struct btf_func_model *m);

struct bpf_kfunc_arg_meta {
	u64 r0_size;
	bool r0_rdonly;
	int ref_obj_id;
	u32 flags;
};

struct bpf_reg_state;
int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
				struct bpf_reg_state *regs);
int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
			   struct bpf_reg_state *regs);
int btf_check_kfunc_arg_match(struct bpf_verifier_env *env,
			      const struct btf *btf, u32 func_id,
			      struct bpf_reg_state *regs,
			      u32 kfunc_flags);
			      struct bpf_kfunc_arg_meta *meta);
int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
			  struct bpf_reg_state *reg);
int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *prog,
+2 −0
Original line number Diff line number Diff line
@@ -598,6 +598,8 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
			    struct bpf_attach_target_info *tgt_info);
void bpf_free_kfunc_btf_tab(struct bpf_kfunc_btf_tab *tab);

int mark_chain_precision(struct bpf_verifier_env *env, int regno);

#define BPF_BASE_TYPE_MASK	GENMASK(BPF_BASE_TYPE_BITS - 1, 0)

/* extract base type from bpf_{arg, return, reg}_type. */
+10 −0
Original line number Diff line number Diff line
@@ -441,4 +441,14 @@ static inline int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dt
}
#endif

static inline bool btf_type_is_struct_ptr(struct btf *btf, const struct btf_type *t)
{
	if (!btf_type_is_ptr(t))
		return false;

	t = btf_type_skip_modifiers(btf, t->type, NULL);

	return btf_type_is_struct(t);
}

#endif
+127 −22
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ enum btf_kfunc_hook {
};

enum {
	BTF_KFUNC_SET_MAX_CNT = 32,
	BTF_KFUNC_SET_MAX_CNT = 256,
	BTF_DTOR_KFUNC_MAX_CNT = 256,
};

@@ -6199,11 +6199,37 @@ static bool is_kfunc_arg_mem_size(const struct btf *btf,
	return true;
}

static bool btf_is_kfunc_arg_mem_size(const struct btf *btf,
				      const struct btf_param *arg,
				      const struct bpf_reg_state *reg,
				      const char *name)
{
	int len, target_len = strlen(name);
	const struct btf_type *t;
	const char *param_name;

	t = btf_type_skip_modifiers(btf, arg->type, NULL);
	if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE)
		return false;

	param_name = btf_name_by_offset(btf, arg->name_off);
	if (str_is_empty(param_name))
		return false;
	len = strlen(param_name);
	if (len != target_len)
		return false;
	if (strcmp(param_name, name))
		return false;

	return true;
}

static int btf_check_func_arg_match(struct bpf_verifier_env *env,
				    const struct btf *btf, u32 func_id,
				    struct bpf_reg_state *regs,
				    bool ptr_to_mem_ok,
				    u32 kfunc_flags)
				    struct bpf_kfunc_arg_meta *kfunc_meta,
				    bool processing_call)
{
	enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
	bool rel = false, kptr_get = false, trusted_arg = false;
@@ -6240,12 +6266,12 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
		return -EINVAL;
	}

	if (is_kfunc) {
	if (is_kfunc && kfunc_meta) {
		/* Only kfunc can be release func */
		rel = kfunc_flags & KF_RELEASE;
		kptr_get = kfunc_flags & KF_KPTR_GET;
		trusted_arg = kfunc_flags & KF_TRUSTED_ARGS;
		sleepable = kfunc_flags & KF_SLEEPABLE;
		rel = kfunc_meta->flags & KF_RELEASE;
		kptr_get = kfunc_meta->flags & KF_KPTR_GET;
		trusted_arg = kfunc_meta->flags & KF_TRUSTED_ARGS;
		sleepable = kfunc_meta->flags & KF_SLEEPABLE;
	}

	/* check that BTF function arguments match actual types that the
@@ -6258,6 +6284,38 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,

		t = btf_type_skip_modifiers(btf, args[i].type, NULL);
		if (btf_type_is_scalar(t)) {
			if (is_kfunc && kfunc_meta) {
				bool is_buf_size = false;

				/* check for any const scalar parameter of name "rdonly_buf_size"
				 * or "rdwr_buf_size"
				 */
				if (btf_is_kfunc_arg_mem_size(btf, &args[i], reg,
							      "rdonly_buf_size")) {
					kfunc_meta->r0_rdonly = true;
					is_buf_size = true;
				} else if (btf_is_kfunc_arg_mem_size(btf, &args[i], reg,
								     "rdwr_buf_size"))
					is_buf_size = true;

				if (is_buf_size) {
					if (kfunc_meta->r0_size) {
						bpf_log(log, "2 or more rdonly/rdwr_buf_size parameters for kfunc");
						return -EINVAL;
					}

					if (!tnum_is_const(reg->var_off)) {
						bpf_log(log, "R%d is not a const\n", regno);
						return -EINVAL;
					}

					kfunc_meta->r0_size = reg->var_off.value;
					ret = mark_chain_precision(env, regno);
					if (ret)
						return ret;
				}
			}

			if (reg->type == SCALAR_VALUE)
				continue;
			bpf_log(log, "R%d is not a scalar\n", regno);
@@ -6288,6 +6346,17 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
		if (ret < 0)
			return ret;

		if (is_kfunc && reg->ref_obj_id) {
			/* Ensure only one argument is referenced PTR_TO_BTF_ID */
			if (ref_obj_id) {
				bpf_log(log, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n",
					regno, reg->ref_obj_id, ref_obj_id);
				return -EFAULT;
			}
			ref_regno = regno;
			ref_obj_id = reg->ref_obj_id;
		}

		/* kptr_get is only true for kfunc */
		if (i == 0 && kptr_get) {
			struct bpf_map_value_off_desc *off_desc;
@@ -6360,16 +6429,6 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
			if (reg->type == PTR_TO_BTF_ID) {
				reg_btf = reg->btf;
				reg_ref_id = reg->btf_id;
				/* Ensure only one argument is referenced PTR_TO_BTF_ID */
				if (reg->ref_obj_id) {
					if (ref_obj_id) {
						bpf_log(log, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n",
							regno, reg->ref_obj_id, ref_obj_id);
						return -EFAULT;
					}
					ref_regno = regno;
					ref_obj_id = reg->ref_obj_id;
				}
			} else {
				reg_btf = btf_vmlinux;
				reg_ref_id = *reg2btf_ids[base_type(reg->type)];
@@ -6389,7 +6448,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
					reg_ref_tname);
				return -EINVAL;
			}
		} else if (ptr_to_mem_ok) {
		} else if (ptr_to_mem_ok && processing_call) {
			const struct btf_type *resolve_ret;
			u32 type_size;

@@ -6460,11 +6519,14 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
		return -EINVAL;
	}

	if (kfunc_meta && ref_obj_id)
		kfunc_meta->ref_obj_id = ref_obj_id;

	/* returns argument register number > 0 in case of reference release kfunc */
	return rel ? ref_regno : 0;
}

/* Compare BTF of a function with given bpf_reg_state.
/* Compare BTF of a function declaration with given bpf_reg_state.
 * Returns:
 * EFAULT - there is a verifier bug. Abort verification.
 * EINVAL - there is a type mismatch or BTF is not available.
@@ -6491,7 +6553,50 @@ int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
		return -EINVAL;

	is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
	err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, 0);
	err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, NULL, false);

	/* Compiler optimizations can remove arguments from static functions
	 * or mismatched type can be passed into a global function.
	 * In such cases mark the function as unreliable from BTF point of view.
	 */
	if (err)
		prog->aux->func_info_aux[subprog].unreliable = true;
	return err;
}

/* Compare BTF of a function call with given bpf_reg_state.
 * Returns:
 * EFAULT - there is a verifier bug. Abort verification.
 * EINVAL - there is a type mismatch or BTF is not available.
 * 0 - BTF matches with what bpf_reg_state expects.
 * Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
 *
 * NOTE: the code is duplicated from btf_check_subprog_arg_match()
 * because btf_check_func_arg_match() is still doing both. Once that
 * function is split in 2, we can call from here btf_check_subprog_arg_match()
 * first, and then treat the calling part in a new code path.
 */
int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
			   struct bpf_reg_state *regs)
{
	struct bpf_prog *prog = env->prog;
	struct btf *btf = prog->aux->btf;
	bool is_global;
	u32 btf_id;
	int err;

	if (!prog->aux->func_info)
		return -EINVAL;

	btf_id = prog->aux->func_info[subprog].type_id;
	if (!btf_id)
		return -EFAULT;

	if (prog->aux->func_info_aux[subprog].unreliable)
		return -EINVAL;

	is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
	err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global, NULL, true);

	/* Compiler optimizations can remove arguments from static functions
	 * or mismatched type can be passed into a global function.
@@ -6505,9 +6610,9 @@ int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
int btf_check_kfunc_arg_match(struct bpf_verifier_env *env,
			      const struct btf *btf, u32 func_id,
			      struct bpf_reg_state *regs,
			      u32 kfunc_flags)
			      struct bpf_kfunc_arg_meta *meta)
{
	return btf_check_func_arg_match(env, btf, func_id, regs, true, kfunc_flags);
	return btf_check_func_arg_match(env, btf, func_id, regs, true, meta, true);
}

/* Convert BTF of a function into bpf_reg_state if possible
+52 −14
Original line number Diff line number Diff line
@@ -2908,7 +2908,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno,
	return 0;
}

static int mark_chain_precision(struct bpf_verifier_env *env, int regno)
int mark_chain_precision(struct bpf_verifier_env *env, int regno)
{
	return __mark_chain_precision(env, regno, -1);
}
@@ -5233,6 +5233,25 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
				env,
				regno, reg->off, access_size,
				zero_size_allowed, ACCESS_HELPER, meta);
	case PTR_TO_CTX:
		/* in case the function doesn't know how to access the context,
		 * (because we are in a program of type SYSCALL for example), we
		 * can not statically check its size.
		 * Dynamically check it now.
		 */
		if (!env->ops->convert_ctx_access) {
			enum bpf_access_type atype = meta && meta->raw_mode ? BPF_WRITE : BPF_READ;
			int offset = access_size - 1;

			/* Allow zero-byte read from PTR_TO_CTX */
			if (access_size == 0)
				return zero_size_allowed ? 0 : -EACCES;

			return check_mem_access(env, env->insn_idx, regno, offset, BPF_B,
						atype, -1, false);
		}

		fallthrough;
	default: /* scalar_value or invalid ptr */
		/* Allow zero-byte read from NULL, regardless of pointer type */
		if (zero_size_allowed && access_size == 0 &&
@@ -6629,7 +6648,7 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn
	func_info_aux = env->prog->aux->func_info_aux;
	if (func_info_aux)
		is_global = func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
	err = btf_check_subprog_arg_match(env, subprog, caller->regs);
	err = btf_check_subprog_call(env, subprog, caller->regs);
	if (err == -EFAULT)
		return err;
	if (is_global) {
@@ -7576,6 +7595,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
{
	const struct btf_type *t, *func, *func_proto, *ptr_type;
	struct bpf_reg_state *regs = cur_regs(env);
	struct bpf_kfunc_arg_meta meta = { 0 };
	const char *func_name, *ptr_type_name;
	u32 i, nargs, func_id, ptr_type_id;
	int err, insn_idx = *insn_idx_p;
@@ -7610,8 +7630,10 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,

	acq = *kfunc_flags & KF_ACQUIRE;

	meta.flags = *kfunc_flags;

	/* Check the arguments */
	err = btf_check_kfunc_arg_match(env, desc_btf, func_id, regs, *kfunc_flags);
	err = btf_check_kfunc_arg_match(env, desc_btf, func_id, regs, &meta);
	if (err < 0)
		return err;
	/* In case of release function, we get register number of refcounted
@@ -7632,7 +7654,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
	/* Check return type */
	t = btf_type_skip_modifiers(desc_btf, func_proto->type, NULL);

	if (acq && !btf_type_is_ptr(t)) {
	if (acq && !btf_type_is_struct_ptr(desc_btf, t)) {
		verbose(env, "acquire kernel function does not return PTR_TO_BTF_ID\n");
		return -EINVAL;
	}
@@ -7644,17 +7666,33 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
		ptr_type = btf_type_skip_modifiers(desc_btf, t->type,
						   &ptr_type_id);
		if (!btf_type_is_struct(ptr_type)) {
			if (!meta.r0_size) {
				ptr_type_name = btf_name_by_offset(desc_btf,
								   ptr_type->name_off);
			verbose(env, "kernel function %s returns pointer type %s %s is not supported\n",
				func_name, btf_type_str(ptr_type),
				verbose(env,
					"kernel function %s returns pointer type %s %s is not supported\n",
					func_name,
					btf_type_str(ptr_type),
					ptr_type_name);
				return -EINVAL;
			}

			mark_reg_known_zero(env, regs, BPF_REG_0);
			regs[BPF_REG_0].type = PTR_TO_MEM;
			regs[BPF_REG_0].mem_size = meta.r0_size;

			if (meta.r0_rdonly)
				regs[BPF_REG_0].type |= MEM_RDONLY;

			/* Ensures we don't access the memory after a release_reference() */
			if (meta.ref_obj_id)
				regs[BPF_REG_0].ref_obj_id = meta.ref_obj_id;
		} else {
			mark_reg_known_zero(env, regs, BPF_REG_0);
			regs[BPF_REG_0].btf = desc_btf;
			regs[BPF_REG_0].type = PTR_TO_BTF_ID;
			regs[BPF_REG_0].btf_id = ptr_type_id;
		}
		if (*kfunc_flags & KF_RET_NULL) {
			regs[BPF_REG_0].type |= PTR_MAYBE_NULL;
			/* For mark_ptr_or_null_reg, see 93c230e3f5bd6 */
Loading