Commit 6728aea7 authored by Kumar Kartikeya Dwivedi's avatar Kumar Kartikeya Dwivedi Committed by Alexei Starovoitov
Browse files

bpf: Refactor btf_struct_access



Instead of having to pass multiple arguments that describe the register,
pass the bpf_reg_state into the btf_struct_access callback. Currently,
all call sites simply reuse the btf and btf_id of the reg they want to
check the access of. The only exception to this pattern is the callsite
in check_ptr_to_map_access, hence for that case create a dummy reg to
simulate PTR_TO_BTF_ID access.

Signed-off-by: default avatarKumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20221114191547.1694267-8-memxor@gmail.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 894f2a8b
Loading
Loading
Loading
Loading
+8 −9
Original line number Diff line number Diff line
@@ -771,6 +771,7 @@ struct bpf_prog_ops {
			union bpf_attr __user *uattr);
};

struct bpf_reg_state;
struct bpf_verifier_ops {
	/* return eBPF function prototype for verification */
	const struct bpf_func_proto *
@@ -792,9 +793,8 @@ struct bpf_verifier_ops {
				  struct bpf_insn *dst,
				  struct bpf_prog *prog, u32 *target_size);
	int (*btf_struct_access)(struct bpf_verifier_log *log,
				 const struct btf *btf,
				 const struct btf_type *t, int off, int size,
				 enum bpf_access_type atype,
				 const struct bpf_reg_state *reg,
				 int off, int size, enum bpf_access_type atype,
				 u32 *next_btf_id, enum bpf_type_flag *flag);
};

@@ -2080,9 +2080,9 @@ static inline bool bpf_tracing_btf_ctx_access(int off, int size,
	return btf_ctx_access(off, size, type, prog, info);
}

int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf,
		      const struct btf_type *t, int off, int size,
		      enum bpf_access_type atype,
int btf_struct_access(struct bpf_verifier_log *log,
		      const struct bpf_reg_state *reg,
		      int off, int size, enum bpf_access_type atype,
		      u32 *next_btf_id, enum bpf_type_flag *flag);
bool btf_struct_ids_match(struct bpf_verifier_log *log,
			  const struct btf *btf, u32 id, int off,
@@ -2333,9 +2333,8 @@ static inline struct bpf_prog *bpf_prog_by_id(u32 id)
}

static inline int btf_struct_access(struct bpf_verifier_log *log,
				    const struct btf *btf,
				    const struct btf_type *t, int off, int size,
				    enum bpf_access_type atype,
				    const struct bpf_reg_state *reg,
				    int off, int size, enum bpf_access_type atype,
				    u32 *next_btf_id, enum bpf_type_flag *flag)
{
	return -EACCES;
+4 −4
Original line number Diff line number Diff line
@@ -568,10 +568,10 @@ struct sk_filter {
DECLARE_STATIC_KEY_FALSE(bpf_stats_enabled_key);

extern struct mutex nf_conn_btf_access_lock;
extern int (*nfct_btf_struct_access)(struct bpf_verifier_log *log, const struct btf *btf,
				     const struct btf_type *t, int off, int size,
				     enum bpf_access_type atype, u32 *next_btf_id,
				     enum bpf_type_flag *flag);
extern int (*nfct_btf_struct_access)(struct bpf_verifier_log *log,
				     const struct bpf_reg_state *reg,
				     int off, int size, enum bpf_access_type atype,
				     u32 *next_btf_id, enum bpf_type_flag *flag);

typedef unsigned int (*bpf_dispatcher_fn)(const void *ctx,
					  const struct bpf_insn *insnsi,
+7 −4
Original line number Diff line number Diff line
@@ -6017,15 +6017,18 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
	return -EINVAL;
}

int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf,
		      const struct btf_type *t, int off, int size,
		      enum bpf_access_type atype __maybe_unused,
int btf_struct_access(struct bpf_verifier_log *log,
		      const struct bpf_reg_state *reg,
		      int off, int size, enum bpf_access_type atype __maybe_unused,
		      u32 *next_btf_id, enum bpf_type_flag *flag)
{
	const struct btf *btf = reg->btf;
	enum bpf_type_flag tmp_flag = 0;
	const struct btf_type *t;
	u32 id = reg->btf_id;
	int err;
	u32 id;

	t = btf_type_by_id(btf, id);
	do {
		err = btf_struct_walk(log, btf, t, off, size, &id, &tmp_flag);

+7 −5
Original line number Diff line number Diff line
@@ -4688,16 +4688,14 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
	}

	if (env->ops->btf_struct_access) {
		ret = env->ops->btf_struct_access(&env->log, reg->btf, t,
						  off, size, atype, &btf_id, &flag);
		ret = env->ops->btf_struct_access(&env->log, reg, off, size, atype, &btf_id, &flag);
	} else {
		if (atype != BPF_READ) {
			verbose(env, "only read is supported\n");
			return -EACCES;
		}

		ret = btf_struct_access(&env->log, reg->btf, t, off, size,
					atype, &btf_id, &flag);
		ret = btf_struct_access(&env->log, reg, off, size, atype, &btf_id, &flag);
	}

	if (ret < 0)
@@ -4723,6 +4721,7 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env,
{
	struct bpf_reg_state *reg = regs + regno;
	struct bpf_map *map = reg->map_ptr;
	struct bpf_reg_state map_reg;
	enum bpf_type_flag flag = 0;
	const struct btf_type *t;
	const char *tname;
@@ -4761,7 +4760,10 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env,
		return -EACCES;
	}

	ret = btf_struct_access(&env->log, btf_vmlinux, t, off, size, atype, &btf_id, &flag);
	/* Simulate access to a PTR_TO_BTF_ID */
	memset(&map_reg, 0, sizeof(map_reg));
	mark_btf_ld_reg(env, &map_reg, 0, PTR_TO_BTF_ID, btf_vmlinux, *map->ops->map_btf_id, 0);
	ret = btf_struct_access(&env->log, &map_reg, off, size, atype, &btf_id, &flag);
	if (ret < 0)
		return ret;

+7 −7
Original line number Diff line number Diff line
@@ -156,29 +156,29 @@ static bool bpf_dummy_ops_is_valid_access(int off, int size,
}

static int bpf_dummy_ops_btf_struct_access(struct bpf_verifier_log *log,
					   const struct btf *btf,
					   const struct btf_type *t, int off,
					   int size, enum bpf_access_type atype,
					   const struct bpf_reg_state *reg,
					   int off, int size, enum bpf_access_type atype,
					   u32 *next_btf_id,
					   enum bpf_type_flag *flag)
{
	const struct btf_type *state;
	const struct btf_type *t;
	s32 type_id;
	int err;

	type_id = btf_find_by_name_kind(btf, "bpf_dummy_ops_state",
	type_id = btf_find_by_name_kind(reg->btf, "bpf_dummy_ops_state",
					BTF_KIND_STRUCT);
	if (type_id < 0)
		return -EINVAL;

	state = btf_type_by_id(btf, type_id);
	t = btf_type_by_id(reg->btf, reg->btf_id);
	state = btf_type_by_id(reg->btf, type_id);
	if (t != state) {
		bpf_log(log, "only access to bpf_dummy_ops_state is supported\n");
		return -EACCES;
	}

	err = btf_struct_access(log, btf, t, off, size, atype, next_btf_id,
				flag);
	err = btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
	if (err < 0)
		return err;

Loading