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:
parent
894f2a8b16
commit
6728aea721
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -6017,15 +6017,18 @@ error:
|
||||
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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -8651,28 +8651,25 @@ static bool tc_cls_act_is_valid_access(int off, int size,
|
||||
DEFINE_MUTEX(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,
|
||||
const struct btf_type *t, int off, int size,
|
||||
enum bpf_access_type atype, u32 *next_btf_id,
|
||||
enum bpf_type_flag *flag);
|
||||
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);
|
||||
EXPORT_SYMBOL_GPL(nfct_btf_struct_access);
|
||||
|
||||
static int tc_cls_act_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)
|
||||
const struct bpf_reg_state *reg,
|
||||
int off, int size, enum bpf_access_type atype,
|
||||
u32 *next_btf_id, enum bpf_type_flag *flag)
|
||||
{
|
||||
int ret = -EACCES;
|
||||
|
||||
if (atype == BPF_READ)
|
||||
return btf_struct_access(log, btf, t, off, size, atype, next_btf_id,
|
||||
flag);
|
||||
return btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
|
||||
|
||||
mutex_lock(&nf_conn_btf_access_lock);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
static int xdp_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)
|
||||
const struct bpf_reg_state *reg,
|
||||
int off, int size, enum bpf_access_type atype,
|
||||
u32 *next_btf_id, enum bpf_type_flag *flag)
|
||||
{
|
||||
int ret = -EACCES;
|
||||
|
||||
if (atype == BPF_READ)
|
||||
return btf_struct_access(log, btf, t, off, size, atype, next_btf_id,
|
||||
flag);
|
||||
return btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
|
||||
|
||||
mutex_lock(&nf_conn_btf_access_lock);
|
||||
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);
|
||||
|
||||
return ret;
|
||||
|
@ -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,
|
||||
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)
|
||||
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 *t;
|
||||
size_t end;
|
||||
|
||||
if (atype == BPF_READ)
|
||||
return btf_struct_access(log, btf, t, off, size, atype, next_btf_id,
|
||||
flag);
|
||||
return btf_struct_access(log, reg, off, size, atype, next_btf_id, flag);
|
||||
|
||||
t = btf_type_by_id(reg->btf, reg->btf_id);
|
||||
if (t != tcp_sock_type) {
|
||||
bpf_log(log, "only read is supported\n");
|
||||
return -EACCES;
|
||||
|
@ -191,19 +191,16 @@ BTF_ID(struct, nf_conn___init)
|
||||
|
||||
/* Check writes into `struct nf_conn` */
|
||||
static int _nf_conntrack_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)
|
||||
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 *ncit;
|
||||
const struct btf_type *nct;
|
||||
const struct btf_type *ncit, *nct, *t;
|
||||
size_t end;
|
||||
|
||||
ncit = btf_type_by_id(btf, btf_nf_conn_ids[1]);
|
||||
nct = btf_type_by_id(btf, btf_nf_conn_ids[0]);
|
||||
|
||||
ncit = btf_type_by_id(reg->btf, btf_nf_conn_ids[1]);
|
||||
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) {
|
||||
bpf_log(log, "only read is supported\n");
|
||||
return -EACCES;
|
||||
|
Loading…
Reference in New Issue
Block a user