bpf: Refactor btf_struct_access
authorKumar Kartikeya Dwivedi <memxor@gmail.com>
Mon, 14 Nov 2022 19:15:28 +0000 (00:45 +0530)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 15 Nov 2022 05:52:45 +0000 (21:52 -0800)
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>
include/linux/bpf.h
include/linux/filter.h
kernel/bpf/btf.c
kernel/bpf/verifier.c
net/bpf/bpf_dummy_struct_ops.c
net/core/filter.c
net/ipv4/bpf_tcp_ca.c
net/netfilter/nf_conntrack_bpf.c

index afc1c51b59ffbacada52c26729329afb5da5cd83..49f9d2bec4017deb84a6dbcaaa62f58c02c0027d 100644 (file)
@@ -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;
index efc42a6e3aed0f6605827c5b879e1207fa616608..787d35dbf5b022363d075902a309894b4aecf5b7 100644 (file)
@@ -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,
index c0d73d71c5394e68d037d7f85d89de5886eb3edf..875355ff371816c65b15663fe5c1304957182d36 100644 (file)
@@ -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);
 
index c588e54835408fc6606498a8d19561c17e02a6f3..5e74f460dfd02e1829dee67da00e843990add2b1 100644 (file)
@@ -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;
 
index e78dadfc58290a1f19841ebb412ddc41a6142323..2d434c1f46176662dcabc896c5d15fb7141df472 100644 (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,
-                                          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;
 
index 6dd2baf5eeb2f83e6216ed774e5ca0d4c3dde41f..37fad5a9b7525bf5dff8701b83014c1ef71bf241 100644 (file)
@@ -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;
index 6da16ae6a96243b363889c690d76d28a3897669b..d15c91de995fcd3e879c2bfc99e57905ab2739b0 100644 (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,
-                                       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;
index 8639e7efd0e22e5c4afd837f5191421b7be69629..24002bc61e07ef332887742d9af906027bc59805 100644 (file)
@@ -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;