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: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20221114191547.1694267-8-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Kumar Kartikeya Dwivedi 2022-11-15 00:45:28 +05:30 committed by Alexei Starovoitov
parent 894f2a8b16
commit 6728aea721
8 changed files with 60 additions and 66 deletions

View File

@ -771,6 +771,7 @@ struct bpf_prog_ops {
union bpf_attr __user *uattr); union bpf_attr __user *uattr);
}; };
struct bpf_reg_state;
struct bpf_verifier_ops { struct bpf_verifier_ops {
/* return eBPF function prototype for verification */ /* return eBPF function prototype for verification */
const struct bpf_func_proto * const struct bpf_func_proto *
@ -792,9 +793,8 @@ struct bpf_verifier_ops {
struct bpf_insn *dst, struct bpf_insn *dst,
struct bpf_prog *prog, u32 *target_size); struct bpf_prog *prog, u32 *target_size);
int (*btf_struct_access)(struct bpf_verifier_log *log, int (*btf_struct_access)(struct bpf_verifier_log *log,
const struct btf *btf, const struct bpf_reg_state *reg,
const struct btf_type *t, int off, int size, int off, int size, enum bpf_access_type atype,
enum bpf_access_type atype,
u32 *next_btf_id, enum bpf_type_flag *flag); 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); return btf_ctx_access(off, size, type, prog, info);
} }
int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf, int btf_struct_access(struct bpf_verifier_log *log,
const struct btf_type *t, int off, int size, const struct bpf_reg_state *reg,
enum bpf_access_type atype, int off, int size, enum bpf_access_type atype,
u32 *next_btf_id, enum bpf_type_flag *flag); u32 *next_btf_id, enum bpf_type_flag *flag);
bool btf_struct_ids_match(struct bpf_verifier_log *log, bool btf_struct_ids_match(struct bpf_verifier_log *log,
const struct btf *btf, u32 id, int off, 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, static inline int btf_struct_access(struct bpf_verifier_log *log,
const struct btf *btf, const struct bpf_reg_state *reg,
const struct btf_type *t, int off, int size, int off, int size, enum bpf_access_type atype,
enum bpf_access_type atype,
u32 *next_btf_id, enum bpf_type_flag *flag) u32 *next_btf_id, enum bpf_type_flag *flag)
{ {
return -EACCES; return -EACCES;

View File

@ -568,10 +568,10 @@ struct sk_filter {
DECLARE_STATIC_KEY_FALSE(bpf_stats_enabled_key); DECLARE_STATIC_KEY_FALSE(bpf_stats_enabled_key);
extern struct mutex nf_conn_btf_access_lock; extern struct mutex nf_conn_btf_access_lock;
extern int (*nfct_btf_struct_access)(struct bpf_verifier_log *log, const struct btf *btf, extern int (*nfct_btf_struct_access)(struct bpf_verifier_log *log,
const struct btf_type *t, int off, int size, const struct bpf_reg_state *reg,
enum bpf_access_type atype, u32 *next_btf_id, int off, int size, enum bpf_access_type atype,
enum bpf_type_flag *flag); u32 *next_btf_id, enum bpf_type_flag *flag);
typedef unsigned int (*bpf_dispatcher_fn)(const void *ctx, typedef unsigned int (*bpf_dispatcher_fn)(const void *ctx,
const struct bpf_insn *insnsi, const struct bpf_insn *insnsi,

View File

@ -6017,15 +6017,18 @@ error:
return -EINVAL; return -EINVAL;
} }
int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf, int btf_struct_access(struct bpf_verifier_log *log,
const struct btf_type *t, int off, int size, const struct bpf_reg_state *reg,
enum bpf_access_type atype __maybe_unused, int off, int size, enum bpf_access_type atype __maybe_unused,
u32 *next_btf_id, enum bpf_type_flag *flag) u32 *next_btf_id, enum bpf_type_flag *flag)
{ {
const struct btf *btf = reg->btf;
enum bpf_type_flag tmp_flag = 0; enum bpf_type_flag tmp_flag = 0;
const struct btf_type *t;
u32 id = reg->btf_id;
int err; int err;
u32 id;
t = btf_type_by_id(btf, id);
do { do {
err = btf_struct_walk(log, btf, t, off, size, &id, &tmp_flag); err = btf_struct_walk(log, btf, t, off, size, &id, &tmp_flag);

View File

@ -4688,16 +4688,14 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
} }
if (env->ops->btf_struct_access) { if (env->ops->btf_struct_access) {
ret = env->ops->btf_struct_access(&env->log, reg->btf, t, ret = env->ops->btf_struct_access(&env->log, reg, off, size, atype, &btf_id, &flag);
off, size, atype, &btf_id, &flag);
} else { } else {
if (atype != BPF_READ) { if (atype != BPF_READ) {
verbose(env, "only read is supported\n"); verbose(env, "only read is supported\n");
return -EACCES; return -EACCES;
} }
ret = btf_struct_access(&env->log, reg->btf, t, off, size, ret = btf_struct_access(&env->log, reg, off, size, atype, &btf_id, &flag);
atype, &btf_id, &flag);
} }
if (ret < 0) 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_reg_state *reg = regs + regno;
struct bpf_map *map = reg->map_ptr; struct bpf_map *map = reg->map_ptr;
struct bpf_reg_state map_reg;
enum bpf_type_flag flag = 0; enum bpf_type_flag flag = 0;
const struct btf_type *t; const struct btf_type *t;
const char *tname; const char *tname;
@ -4761,7 +4760,10 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env,
return -EACCES; 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) if (ret < 0)
return ret; return ret;

View File

@ -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, static int bpf_dummy_ops_btf_struct_access(struct bpf_verifier_log *log,
const struct btf *btf, const struct bpf_reg_state *reg,
const struct btf_type *t, int off, int off, int size, enum bpf_access_type atype,
int size, enum bpf_access_type atype,
u32 *next_btf_id, u32 *next_btf_id,
enum bpf_type_flag *flag) enum bpf_type_flag *flag)
{ {
const struct btf_type *state; const struct btf_type *state;
const struct btf_type *t;
s32 type_id; s32 type_id;
int err; 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); BTF_KIND_STRUCT);
if (type_id < 0) if (type_id < 0)
return -EINVAL; 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) { if (t != state) {
bpf_log(log, "only access to bpf_dummy_ops_state is supported\n"); bpf_log(log, "only access to bpf_dummy_ops_state is supported\n");
return -EACCES; return -EACCES;
} }
err = btf_struct_access(log, btf, t, off, size, atype, next_btf_id, err = btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
flag);
if (err < 0) if (err < 0)
return err; return err;

View File

@ -8651,28 +8651,25 @@ static bool tc_cls_act_is_valid_access(int off, int size,
DEFINE_MUTEX(nf_conn_btf_access_lock); DEFINE_MUTEX(nf_conn_btf_access_lock);
EXPORT_SYMBOL_GPL(nf_conn_btf_access_lock); EXPORT_SYMBOL_GPL(nf_conn_btf_access_lock);
int (*nfct_btf_struct_access)(struct bpf_verifier_log *log, const struct btf *btf, int (*nfct_btf_struct_access)(struct bpf_verifier_log *log,
const struct btf_type *t, int off, int size, const struct bpf_reg_state *reg,
enum bpf_access_type atype, u32 *next_btf_id, int off, int size, enum bpf_access_type atype,
enum bpf_type_flag *flag); u32 *next_btf_id, enum bpf_type_flag *flag);
EXPORT_SYMBOL_GPL(nfct_btf_struct_access); EXPORT_SYMBOL_GPL(nfct_btf_struct_access);
static int tc_cls_act_btf_struct_access(struct bpf_verifier_log *log, static int tc_cls_act_btf_struct_access(struct bpf_verifier_log *log,
const struct btf *btf, const struct bpf_reg_state *reg,
const struct btf_type *t, int off, int off, int size, enum bpf_access_type atype,
int size, enum bpf_access_type atype, u32 *next_btf_id, enum bpf_type_flag *flag)
u32 *next_btf_id,
enum bpf_type_flag *flag)
{ {
int ret = -EACCES; int ret = -EACCES;
if (atype == BPF_READ) if (atype == BPF_READ)
return btf_struct_access(log, btf, t, off, size, atype, next_btf_id, return btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
flag);
mutex_lock(&nf_conn_btf_access_lock); mutex_lock(&nf_conn_btf_access_lock);
if (nfct_btf_struct_access) if (nfct_btf_struct_access)
ret = nfct_btf_struct_access(log, btf, t, off, size, atype, next_btf_id, flag); ret = nfct_btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
mutex_unlock(&nf_conn_btf_access_lock); mutex_unlock(&nf_conn_btf_access_lock);
return ret; return ret;
@ -8738,21 +8735,18 @@ void bpf_warn_invalid_xdp_action(struct net_device *dev, struct bpf_prog *prog,
EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action); EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action);
static int xdp_btf_struct_access(struct bpf_verifier_log *log, static int xdp_btf_struct_access(struct bpf_verifier_log *log,
const struct btf *btf, const struct bpf_reg_state *reg,
const struct btf_type *t, int off, int off, int size, enum bpf_access_type atype,
int size, enum bpf_access_type atype, u32 *next_btf_id, enum bpf_type_flag *flag)
u32 *next_btf_id,
enum bpf_type_flag *flag)
{ {
int ret = -EACCES; int ret = -EACCES;
if (atype == BPF_READ) if (atype == BPF_READ)
return btf_struct_access(log, btf, t, off, size, atype, next_btf_id, return btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
flag);
mutex_lock(&nf_conn_btf_access_lock); mutex_lock(&nf_conn_btf_access_lock);
if (nfct_btf_struct_access) if (nfct_btf_struct_access)
ret = nfct_btf_struct_access(log, btf, t, off, size, atype, next_btf_id, flag); ret = nfct_btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
mutex_unlock(&nf_conn_btf_access_lock); mutex_unlock(&nf_conn_btf_access_lock);
return ret; return ret;

View File

@ -69,18 +69,17 @@ static bool bpf_tcp_ca_is_valid_access(int off, int size,
} }
static int bpf_tcp_ca_btf_struct_access(struct bpf_verifier_log *log, static int bpf_tcp_ca_btf_struct_access(struct bpf_verifier_log *log,
const struct btf *btf, const struct bpf_reg_state *reg,
const struct btf_type *t, int off, int off, int size, enum bpf_access_type atype,
int size, enum bpf_access_type atype, u32 *next_btf_id, enum bpf_type_flag *flag)
u32 *next_btf_id,
enum bpf_type_flag *flag)
{ {
const struct btf_type *t;
size_t end; size_t end;
if (atype == BPF_READ) if (atype == BPF_READ)
return btf_struct_access(log, btf, t, off, size, atype, next_btf_id, return btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
flag);
t = btf_type_by_id(reg->btf, reg->btf_id);
if (t != tcp_sock_type) { if (t != tcp_sock_type) {
bpf_log(log, "only read is supported\n"); bpf_log(log, "only read is supported\n");
return -EACCES; return -EACCES;

View File

@ -191,19 +191,16 @@ BTF_ID(struct, nf_conn___init)
/* Check writes into `struct nf_conn` */ /* Check writes into `struct nf_conn` */
static int _nf_conntrack_btf_struct_access(struct bpf_verifier_log *log, static int _nf_conntrack_btf_struct_access(struct bpf_verifier_log *log,
const struct btf *btf, const struct bpf_reg_state *reg,
const struct btf_type *t, int off, int off, int size, enum bpf_access_type atype,
int size, enum bpf_access_type atype, u32 *next_btf_id, enum bpf_type_flag *flag)
u32 *next_btf_id,
enum bpf_type_flag *flag)
{ {
const struct btf_type *ncit; const struct btf_type *ncit, *nct, *t;
const struct btf_type *nct;
size_t end; size_t end;
ncit = btf_type_by_id(btf, btf_nf_conn_ids[1]); ncit = btf_type_by_id(reg->btf, btf_nf_conn_ids[1]);
nct = btf_type_by_id(btf, btf_nf_conn_ids[0]); nct = btf_type_by_id(reg->btf, btf_nf_conn_ids[0]);
t = btf_type_by_id(reg->btf, reg->btf_id);
if (t != nct && t != ncit) { if (t != nct && t != ncit) {
bpf_log(log, "only read is supported\n"); bpf_log(log, "only read is supported\n");
return -EACCES; return -EACCES;