Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[linux-2.6-microblaze.git] / kernel / bpf / verifier.c
index 8c5a46d..dcf065e 100644 (file)
@@ -571,6 +571,8 @@ static const char *reg_type_str(struct bpf_verifier_env *env,
 
        if (type & MEM_RDONLY)
                strncpy(prefix, "rdonly_", 16);
+       if (type & MEM_ALLOC)
+               strncpy(prefix, "alloc_", 16);
 
        snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s%s",
                 prefix, str[base_type(type)], postfix);
@@ -617,7 +619,7 @@ static void mark_reg_scratched(struct bpf_verifier_env *env, u32 regno)
 
 static void mark_stack_slot_scratched(struct bpf_verifier_env *env, u32 spi)
 {
-       env->scratched_stack_slots |= 1UL << spi;
+       env->scratched_stack_slots |= 1ULL << spi;
 }
 
 static bool reg_scratched(const struct bpf_verifier_env *env, u32 regno)
@@ -638,14 +640,14 @@ static bool verifier_state_scratched(const struct bpf_verifier_env *env)
 static void mark_verifier_state_clean(struct bpf_verifier_env *env)
 {
        env->scratched_regs = 0U;
-       env->scratched_stack_slots = 0UL;
+       env->scratched_stack_slots = 0ULL;
 }
 
 /* Used for printing the entire verifier state. */
 static void mark_verifier_state_scratched(struct bpf_verifier_env *env)
 {
        env->scratched_regs = ~0U;
-       env->scratched_stack_slots = ~0UL;
+       env->scratched_stack_slots = ~0ULL;
 }
 
 /* The reg state of a pointer or a bounded scalar was saved when
@@ -3962,16 +3964,17 @@ static int get_callee_stack_depth(struct bpf_verifier_env *env,
 }
 #endif
 
-int check_ctx_reg(struct bpf_verifier_env *env,
-                 const struct bpf_reg_state *reg, int regno)
+static int __check_ptr_off_reg(struct bpf_verifier_env *env,
+                              const struct bpf_reg_state *reg, int regno,
+                              bool fixed_off_ok)
 {
-       /* Access to ctx or passing it to a helper is only allowed in
-        * its original, unmodified form.
+       /* Access to this pointer-typed register or passing it to a helper
+        * is only allowed in its original, unmodified form.
         */
 
-       if (reg->off) {
-               verbose(env, "dereference of modified ctx ptr R%d off=%d disallowed\n",
-                       regno, reg->off);
+       if (!fixed_off_ok && reg->off) {
+               verbose(env, "dereference of modified %s ptr R%d off=%d disallowed\n",
+                       reg_type_str(env, reg->type), regno, reg->off);
                return -EACCES;
        }
 
@@ -3979,13 +3982,20 @@ int check_ctx_reg(struct bpf_verifier_env *env,
                char tn_buf[48];
 
                tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
-               verbose(env, "variable ctx access var_off=%s disallowed\n", tn_buf);
+               verbose(env, "variable %s access var_off=%s disallowed\n",
+                       reg_type_str(env, reg->type), tn_buf);
                return -EACCES;
        }
 
        return 0;
 }
 
+int check_ptr_off_reg(struct bpf_verifier_env *env,
+                     const struct bpf_reg_state *reg, int regno)
+{
+       return __check_ptr_off_reg(env, reg, regno, false);
+}
+
 static int __check_buffer_access(struct bpf_verifier_env *env,
                                 const char *buf_info,
                                 const struct bpf_reg_state *reg,
@@ -4430,7 +4440,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
                        return -EACCES;
                }
 
-               err = check_ctx_reg(env, reg, regno);
+               err = check_ptr_off_reg(env, reg, regno);
                if (err < 0)
                        return err;
 
@@ -5198,6 +5208,7 @@ static const struct bpf_reg_types mem_types = {
                PTR_TO_MAP_KEY,
                PTR_TO_MAP_VALUE,
                PTR_TO_MEM,
+               PTR_TO_MEM | MEM_ALLOC,
                PTR_TO_BUF,
        },
 };
@@ -5215,7 +5226,7 @@ static const struct bpf_reg_types int_ptr_types = {
 static const struct bpf_reg_types fullsock_types = { .types = { PTR_TO_SOCKET } };
 static const struct bpf_reg_types scalar_types = { .types = { SCALAR_VALUE } };
 static const struct bpf_reg_types context_types = { .types = { PTR_TO_CTX } };
-static const struct bpf_reg_types alloc_mem_types = { .types = { PTR_TO_MEM } };
+static const struct bpf_reg_types alloc_mem_types = { .types = { PTR_TO_MEM | MEM_ALLOC } };
 static const struct bpf_reg_types const_map_ptr_types = { .types = { CONST_PTR_TO_MAP } };
 static const struct bpf_reg_types btf_ptr_types = { .types = { PTR_TO_BTF_ID } };
 static const struct bpf_reg_types spin_lock_types = { .types = { PTR_TO_MAP_VALUE } };
@@ -5315,12 +5326,6 @@ found:
                                kernel_type_name(btf_vmlinux, *arg_btf_id));
                        return -EACCES;
                }
-
-               if (!tnum_is_const(reg->var_off) || reg->var_off.value) {
-                       verbose(env, "R%d is a pointer to in-kernel struct with non-zero offset\n",
-                               regno);
-                       return -EACCES;
-               }
        }
 
        return 0;
@@ -5375,10 +5380,33 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
        if (err)
                return err;
 
-       if (type == PTR_TO_CTX) {
-               err = check_ctx_reg(env, reg, regno);
+       switch ((u32)type) {
+       case SCALAR_VALUE:
+       /* Pointer types where reg offset is explicitly allowed: */
+       case PTR_TO_PACKET:
+       case PTR_TO_PACKET_META:
+       case PTR_TO_MAP_KEY:
+       case PTR_TO_MAP_VALUE:
+       case PTR_TO_MEM:
+       case PTR_TO_MEM | MEM_RDONLY:
+       case PTR_TO_MEM | MEM_ALLOC:
+       case PTR_TO_BUF:
+       case PTR_TO_BUF | MEM_RDONLY:
+       case PTR_TO_STACK:
+               /* Some of the argument types nevertheless require a
+                * zero register offset.
+                */
+               if (arg_type == ARG_PTR_TO_ALLOC_MEM)
+                       goto force_off_check;
+               break;
+       /* All the rest must be rejected: */
+       default:
+force_off_check:
+               err = __check_ptr_off_reg(env, reg, regno,
+                                         type == PTR_TO_BTF_ID);
                if (err < 0)
                        return err;
+               break;
        }
 
 skip_type_check:
@@ -9569,9 +9597,13 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
                return 0;
        }
 
-       if (insn->src_reg == BPF_PSEUDO_BTF_ID) {
-               mark_reg_known_zero(env, regs, insn->dst_reg);
+       /* All special src_reg cases are listed below. From this point onwards
+        * we either succeed and assign a corresponding dst_reg->type after
+        * zeroing the offset, or fail and reject the program.
+        */
+       mark_reg_known_zero(env, regs, insn->dst_reg);
 
+       if (insn->src_reg == BPF_PSEUDO_BTF_ID) {
                dst_reg->type = aux->btf_var.reg_type;
                switch (base_type(dst_reg->type)) {
                case PTR_TO_MEM:
@@ -9609,7 +9641,6 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
        }
 
        map = env->used_maps[aux->map_index];
-       mark_reg_known_zero(env, regs, insn->dst_reg);
        dst_reg->map_ptr = map;
 
        if (insn->src_reg == BPF_PSEUDO_MAP_VALUE ||
@@ -9713,7 +9744,7 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
                        return err;
        }
 
-       err = check_ctx_reg(env, &regs[ctx_reg], ctx_reg);
+       err = check_ptr_off_reg(env, &regs[ctx_reg], ctx_reg);
        if (err < 0)
                return err;