Merge tag 'spi-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
[firefly-linux-kernel-4.4.55.git] / kernel / bpf / verifier.c
index b074b23000d6e95792e7fcefe0cd29e5a649a6ea..c6073056badf02293c7e9d1e35dce9bb88536c67 100644 (file)
@@ -199,6 +199,7 @@ struct verifier_env {
        struct verifier_state_list **explored_states; /* search pruning optimization */
        struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
        u32 used_map_cnt;               /* number of used maps */
+       bool allow_ptr_leaks;
 };
 
 /* verbose verifier prints what it's seeing
@@ -213,7 +214,7 @@ static DEFINE_MUTEX(bpf_verifier_lock);
  * verbose() is used to dump the verification trace to the log, so the user
  * can figure out what's wrong with the program
  */
-static void verbose(const char *fmt, ...)
+static __printf(1, 2) void verbose(const char *fmt, ...)
 {
        va_list args;
 
@@ -244,6 +245,7 @@ static const struct {
 } func_limit[] = {
        {BPF_MAP_TYPE_PROG_ARRAY, BPF_FUNC_tail_call},
        {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_read},
+       {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_output},
 };
 
 static void print_verifier_state(struct verifier_env *env)
@@ -538,6 +540,21 @@ static int bpf_size_to_bytes(int bpf_size)
                return -EINVAL;
 }
 
+static bool is_spillable_regtype(enum bpf_reg_type type)
+{
+       switch (type) {
+       case PTR_TO_MAP_VALUE:
+       case PTR_TO_MAP_VALUE_OR_NULL:
+       case PTR_TO_STACK:
+       case PTR_TO_CTX:
+       case FRAME_PTR:
+       case CONST_PTR_TO_MAP:
+               return true;
+       default:
+               return false;
+       }
+}
+
 /* check_stack_read/write functions track spill/fill of registers,
  * stack boundary and alignment are checked in check_mem_access()
  */
@@ -550,9 +567,7 @@ static int check_stack_write(struct verifier_state *state, int off, int size,
         */
 
        if (value_regno >= 0 &&
-           (state->regs[value_regno].type == PTR_TO_MAP_VALUE ||
-            state->regs[value_regno].type == PTR_TO_STACK ||
-            state->regs[value_regno].type == PTR_TO_CTX)) {
+           is_spillable_regtype(state->regs[value_regno].type)) {
 
                /* register containing pointer is being spilled into stack */
                if (size != BPF_REG_SIZE) {
@@ -643,6 +658,20 @@ static int check_ctx_access(struct verifier_env *env, int off, int size,
        return -EACCES;
 }
 
+static bool is_pointer_value(struct verifier_env *env, int regno)
+{
+       if (env->allow_ptr_leaks)
+               return false;
+
+       switch (env->cur_state.regs[regno].type) {
+       case UNKNOWN_VALUE:
+       case CONST_IMM:
+               return false;
+       default:
+               return true;
+       }
+}
+
 /* check whether memory at (regno + off) is accessible for t = (read | write)
  * if t==write, value_regno is a register which value is stored into memory
  * if t==read, value_regno is a register which will receive the value from memory
@@ -669,11 +698,21 @@ static int check_mem_access(struct verifier_env *env, u32 regno, int off,
        }
 
        if (state->regs[regno].type == PTR_TO_MAP_VALUE) {
+               if (t == BPF_WRITE && value_regno >= 0 &&
+                   is_pointer_value(env, value_regno)) {
+                       verbose("R%d leaks addr into map\n", value_regno);
+                       return -EACCES;
+               }
                err = check_map_access(env, regno, off, size);
                if (!err && t == BPF_READ && value_regno >= 0)
                        mark_reg_unknown_value(state->regs, value_regno);
 
        } else if (state->regs[regno].type == PTR_TO_CTX) {
+               if (t == BPF_WRITE && value_regno >= 0 &&
+                   is_pointer_value(env, value_regno)) {
+                       verbose("R%d leaks addr into ctx\n", value_regno);
+                       return -EACCES;
+               }
                err = check_ctx_access(env, off, size, t);
                if (!err && t == BPF_READ && value_regno >= 0)
                        mark_reg_unknown_value(state->regs, value_regno);
@@ -684,10 +723,17 @@ static int check_mem_access(struct verifier_env *env, u32 regno, int off,
                        verbose("invalid stack off=%d size=%d\n", off, size);
                        return -EACCES;
                }
-               if (t == BPF_WRITE)
+               if (t == BPF_WRITE) {
+                       if (!env->allow_ptr_leaks &&
+                           state->stack_slot_type[MAX_BPF_STACK + off] == STACK_SPILL &&
+                           size != BPF_REG_SIZE) {
+                               verbose("attempt to corrupt spilled pointer on stack\n");
+                               return -EACCES;
+                       }
                        err = check_stack_write(state, off, size, value_regno);
-               else
+               } else {
                        err = check_stack_read(state, off, size, value_regno);
+               }
        } else {
                verbose("R%d invalid mem access '%s'\n",
                        regno, reg_type_str[state->regs[regno].type]);
@@ -775,8 +821,13 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
                return -EACCES;
        }
 
-       if (arg_type == ARG_ANYTHING)
+       if (arg_type == ARG_ANYTHING) {
+               if (is_pointer_value(env, regno)) {
+                       verbose("R%d leaks addr into helper function\n", regno);
+                       return -EACCES;
+               }
                return 0;
+       }
 
        if (arg_type == ARG_PTR_TO_STACK || arg_type == ARG_PTR_TO_MAP_KEY ||
            arg_type == ARG_PTR_TO_MAP_VALUE) {
@@ -860,7 +911,7 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id)
                 * don't allow any other map type to be passed into
                 * the special func;
                 */
-               if (bool_map != bool_func)
+               if (bool_func && bool_map != bool_func)
                        return -EINVAL;
        }
 
@@ -950,8 +1001,9 @@ static int check_call(struct verifier_env *env, int func_id)
 }
 
 /* check validity of 32-bit and 64-bit arithmetic operations */
-static int check_alu_op(struct reg_state *regs, struct bpf_insn *insn)
+static int check_alu_op(struct verifier_env *env, struct bpf_insn *insn)
 {
+       struct reg_state *regs = env->cur_state.regs;
        u8 opcode = BPF_OP(insn->code);
        int err;
 
@@ -976,6 +1028,12 @@ static int check_alu_op(struct reg_state *regs, struct bpf_insn *insn)
                if (err)
                        return err;
 
+               if (is_pointer_value(env, insn->dst_reg)) {
+                       verbose("R%d pointer arithmetic prohibited\n",
+                               insn->dst_reg);
+                       return -EACCES;
+               }
+
                /* check dest operand */
                err = check_reg_arg(regs, insn->dst_reg, DST_OP);
                if (err)
@@ -1012,6 +1070,11 @@ static int check_alu_op(struct reg_state *regs, struct bpf_insn *insn)
                                 */
                                regs[insn->dst_reg] = regs[insn->src_reg];
                        } else {
+                               if (is_pointer_value(env, insn->src_reg)) {
+                                       verbose("R%d partial copy of pointer\n",
+                                               insn->src_reg);
+                                       return -EACCES;
+                               }
                                regs[insn->dst_reg].type = UNKNOWN_VALUE;
                                regs[insn->dst_reg].map_ptr = NULL;
                        }
@@ -1061,8 +1124,18 @@ static int check_alu_op(struct reg_state *regs, struct bpf_insn *insn)
                /* pattern match 'bpf_add Rx, imm' instruction */
                if (opcode == BPF_ADD && BPF_CLASS(insn->code) == BPF_ALU64 &&
                    regs[insn->dst_reg].type == FRAME_PTR &&
-                   BPF_SRC(insn->code) == BPF_K)
+                   BPF_SRC(insn->code) == BPF_K) {
                        stack_relative = true;
+               } else if (is_pointer_value(env, insn->dst_reg)) {
+                       verbose("R%d pointer arithmetic prohibited\n",
+                               insn->dst_reg);
+                       return -EACCES;
+               } else if (BPF_SRC(insn->code) == BPF_X &&
+                          is_pointer_value(env, insn->src_reg)) {
+                       verbose("R%d pointer arithmetic prohibited\n",
+                               insn->src_reg);
+                       return -EACCES;
+               }
 
                /* check dest operand */
                err = check_reg_arg(regs, insn->dst_reg, DST_OP);
@@ -1101,6 +1174,12 @@ static int check_cond_jmp_op(struct verifier_env *env,
                err = check_reg_arg(regs, insn->src_reg, SRC_OP);
                if (err)
                        return err;
+
+               if (is_pointer_value(env, insn->src_reg)) {
+                       verbose("R%d pointer comparison prohibited\n",
+                               insn->src_reg);
+                       return -EACCES;
+               }
        } else {
                if (insn->src_reg != BPF_REG_0) {
                        verbose("BPF_JMP uses reserved fields\n");
@@ -1155,6 +1234,9 @@ static int check_cond_jmp_op(struct verifier_env *env,
                        regs[insn->dst_reg].type = CONST_IMM;
                        regs[insn->dst_reg].imm = 0;
                }
+       } else if (is_pointer_value(env, insn->dst_reg)) {
+               verbose("R%d pointer comparison prohibited\n", insn->dst_reg);
+               return -EACCES;
        } else if (BPF_SRC(insn->code) == BPF_K &&
                   (opcode == BPF_JEQ || opcode == BPF_JNE)) {
 
@@ -1658,7 +1740,7 @@ static int do_check(struct verifier_env *env)
                }
 
                if (class == BPF_ALU || class == BPF_ALU64) {
-                       err = check_alu_op(regs, insn);
+                       err = check_alu_op(env, insn);
                        if (err)
                                return err;
 
@@ -1816,6 +1898,11 @@ static int do_check(struct verifier_env *env)
                                if (err)
                                        return err;
 
+                               if (is_pointer_value(env, BPF_REG_0)) {
+                                       verbose("R0 leaks addr as return value\n");
+                                       return -EACCES;
+                               }
+
 process_bpf_exit:
                                insn_idx = pop_stack(env, &prev_insn_idx);
                                if (insn_idx < 0) {
@@ -1902,8 +1989,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env)
                        }
 
                        f = fdget(insn->imm);
-
-                       map = bpf_map_get(f);
+                       map = __bpf_map_get(f);
                        if (IS_ERR(map)) {
                                verbose("fd %d is not pointing to valid bpf_map\n",
                                        insn->imm);
@@ -2024,7 +2110,7 @@ static int convert_ctx_accesses(struct verifier_env *env)
 
                cnt = env->prog->aux->ops->
                        convert_ctx_access(type, insn->dst_reg, insn->src_reg,
-                                          insn->off, insn_buf);
+                                          insn->off, insn_buf, env->prog);
                if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf)) {
                        verbose("bpf verifier is misconfigured\n");
                        return -EINVAL;
@@ -2144,6 +2230,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
        if (ret < 0)
                goto skip_full_check;
 
+       env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);
+
        ret = do_check(env);
 
 skip_full_check: