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);
|
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;
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user