Merge tag 'xfs-5.9-merge-7' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-2.6-microblaze.git] / kernel / bpf / verifier.c
index 94cead5..b6ccfce 100644 (file)
@@ -409,7 +409,9 @@ static bool reg_type_may_be_null(enum bpf_reg_type type)
               type == PTR_TO_SOCK_COMMON_OR_NULL ||
               type == PTR_TO_TCP_SOCK_OR_NULL ||
               type == PTR_TO_BTF_ID_OR_NULL ||
-              type == PTR_TO_MEM_OR_NULL;
+              type == PTR_TO_MEM_OR_NULL ||
+              type == PTR_TO_RDONLY_BUF_OR_NULL ||
+              type == PTR_TO_RDWR_BUF_OR_NULL;
 }
 
 static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg)
@@ -503,6 +505,10 @@ static const char * const reg_type_str[] = {
        [PTR_TO_BTF_ID_OR_NULL] = "ptr_or_null_",
        [PTR_TO_MEM]            = "mem",
        [PTR_TO_MEM_OR_NULL]    = "mem_or_null",
+       [PTR_TO_RDONLY_BUF]     = "rdonly_buf",
+       [PTR_TO_RDONLY_BUF_OR_NULL] = "rdonly_buf_or_null",
+       [PTR_TO_RDWR_BUF]       = "rdwr_buf",
+       [PTR_TO_RDWR_BUF_OR_NULL] = "rdwr_buf_or_null",
 };
 
 static char slot_type_char[] = {
@@ -1350,6 +1356,19 @@ static void mark_reg_not_init(struct bpf_verifier_env *env,
        __mark_reg_not_init(env, regs + regno);
 }
 
+static void mark_btf_ld_reg(struct bpf_verifier_env *env,
+                           struct bpf_reg_state *regs, u32 regno,
+                           enum bpf_reg_type reg_type, u32 btf_id)
+{
+       if (reg_type == SCALAR_VALUE) {
+               mark_reg_unknown(env, regs, regno);
+               return;
+       }
+       mark_reg_known_zero(env, regs, regno);
+       regs[regno].type = PTR_TO_BTF_ID;
+       regs[regno].btf_id = btf_id;
+}
+
 #define DEF_NOT_SUBREG (0)
 static void init_reg_state(struct bpf_verifier_env *env,
                           struct bpf_func_state *state)
@@ -2160,6 +2179,10 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
        case PTR_TO_XDP_SOCK:
        case PTR_TO_BTF_ID:
        case PTR_TO_BTF_ID_OR_NULL:
+       case PTR_TO_RDONLY_BUF:
+       case PTR_TO_RDONLY_BUF_OR_NULL:
+       case PTR_TO_RDWR_BUF:
+       case PTR_TO_RDWR_BUF_OR_NULL:
                return true;
        default:
                return false;
@@ -3039,14 +3062,15 @@ int check_ctx_reg(struct bpf_verifier_env *env,
        return 0;
 }
 
-static int check_tp_buffer_access(struct bpf_verifier_env *env,
-                                 const struct bpf_reg_state *reg,
-                                 int regno, int off, int size)
+static int __check_buffer_access(struct bpf_verifier_env *env,
+                                const char *buf_info,
+                                const struct bpf_reg_state *reg,
+                                int regno, int off, int size)
 {
        if (off < 0) {
                verbose(env,
-                       "R%d invalid tracepoint buffer access: off=%d, size=%d",
-                       regno, off, size);
+                       "R%d invalid %s buffer access: off=%d, size=%d\n",
+                       regno, buf_info, off, size);
                return -EACCES;
        }
        if (!tnum_is_const(reg->var_off) || reg->var_off.value) {
@@ -3054,16 +3078,49 @@ static int check_tp_buffer_access(struct bpf_verifier_env *env,
 
                tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
                verbose(env,
-                       "R%d invalid variable buffer offset: off=%d, var_off=%s",
+                       "R%d invalid variable buffer offset: off=%d, var_off=%s\n",
                        regno, off, tn_buf);
                return -EACCES;
        }
+
+       return 0;
+}
+
+static int check_tp_buffer_access(struct bpf_verifier_env *env,
+                                 const struct bpf_reg_state *reg,
+                                 int regno, int off, int size)
+{
+       int err;
+
+       err = __check_buffer_access(env, "tracepoint", reg, regno, off, size);
+       if (err)
+               return err;
+
        if (off + size > env->prog->aux->max_tp_access)
                env->prog->aux->max_tp_access = off + size;
 
        return 0;
 }
 
+static int check_buffer_access(struct bpf_verifier_env *env,
+                              const struct bpf_reg_state *reg,
+                              int regno, int off, int size,
+                              bool zero_size_allowed,
+                              const char *buf_info,
+                              u32 *max_access)
+{
+       int err;
+
+       err = __check_buffer_access(env, buf_info, reg, regno, off, size);
+       if (err)
+               return err;
+
+       if (off + size > *max_access)
+               *max_access = off + size;
+
+       return 0;
+}
+
 /* BPF architecture zero extends alu32 ops into 64-bit registesr */
 static void zext_32_to_64(struct bpf_reg_state *reg)
 {
@@ -3181,19 +3238,68 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
        if (ret < 0)
                return ret;
 
-       if (atype == BPF_READ && value_regno >= 0) {
-               if (ret == SCALAR_VALUE) {
-                       mark_reg_unknown(env, regs, value_regno);
-                       return 0;
-               }
-               mark_reg_known_zero(env, regs, value_regno);
-               regs[value_regno].type = PTR_TO_BTF_ID;
-               regs[value_regno].btf_id = btf_id;
+       if (atype == BPF_READ && value_regno >= 0)
+               mark_btf_ld_reg(env, regs, value_regno, ret, btf_id);
+
+       return 0;
+}
+
+static int check_ptr_to_map_access(struct bpf_verifier_env *env,
+                                  struct bpf_reg_state *regs,
+                                  int regno, int off, int size,
+                                  enum bpf_access_type atype,
+                                  int value_regno)
+{
+       struct bpf_reg_state *reg = regs + regno;
+       struct bpf_map *map = reg->map_ptr;
+       const struct btf_type *t;
+       const char *tname;
+       u32 btf_id;
+       int ret;
+
+       if (!btf_vmlinux) {
+               verbose(env, "map_ptr access not supported without CONFIG_DEBUG_INFO_BTF\n");
+               return -ENOTSUPP;
+       }
+
+       if (!map->ops->map_btf_id || !*map->ops->map_btf_id) {
+               verbose(env, "map_ptr access not supported for map type %d\n",
+                       map->map_type);
+               return -ENOTSUPP;
+       }
+
+       t = btf_type_by_id(btf_vmlinux, *map->ops->map_btf_id);
+       tname = btf_name_by_offset(btf_vmlinux, t->name_off);
+
+       if (!env->allow_ptr_to_map_access) {
+               verbose(env,
+                       "%s access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN\n",
+                       tname);
+               return -EPERM;
+       }
+
+       if (off < 0) {
+               verbose(env, "R%d is %s invalid negative access: off=%d\n",
+                       regno, tname, off);
+               return -EACCES;
+       }
+
+       if (atype != BPF_READ) {
+               verbose(env, "only read from %s is supported\n", tname);
+               return -EACCES;
        }
 
+       ret = btf_struct_access(&env->log, t, off, size, atype, &btf_id);
+       if (ret < 0)
+               return ret;
+
+       if (value_regno >= 0)
+               mark_btf_ld_reg(env, regs, value_regno, ret, btf_id);
+
        return 0;
 }
 
+
 /* 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
@@ -3362,6 +3468,26 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
        } else if (reg->type == PTR_TO_BTF_ID) {
                err = check_ptr_to_btf_access(env, regs, regno, off, size, t,
                                              value_regno);
+       } else if (reg->type == CONST_PTR_TO_MAP) {
+               err = check_ptr_to_map_access(env, regs, regno, off, size, t,
+                                             value_regno);
+       } else if (reg->type == PTR_TO_RDONLY_BUF) {
+               if (t == BPF_WRITE) {
+                       verbose(env, "R%d cannot write into %s\n",
+                               regno, reg_type_str[reg->type]);
+                       return -EACCES;
+               }
+               err = check_buffer_access(env, reg, regno, off, size, false,
+                                         "rdonly",
+                                         &env->prog->aux->max_rdonly_access);
+               if (!err && value_regno >= 0)
+                       mark_reg_unknown(env, regs, value_regno);
+       } else if (reg->type == PTR_TO_RDWR_BUF) {
+               err = check_buffer_access(env, reg, regno, off, size, false,
+                                         "rdwr",
+                                         &env->prog->aux->max_rdwr_access);
+               if (!err && t == BPF_READ && value_regno >= 0)
+                       mark_reg_unknown(env, regs, value_regno);
        } else {
                verbose(env, "R%d invalid mem access '%s'\n", regno,
                        reg_type_str[reg->type]);
@@ -3603,6 +3729,18 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
                return check_mem_region_access(env, regno, reg->off,
                                               access_size, reg->mem_size,
                                               zero_size_allowed);
+       case PTR_TO_RDONLY_BUF:
+               if (meta && meta->raw_mode)
+                       return -EACCES;
+               return check_buffer_access(env, reg, regno, reg->off,
+                                          access_size, zero_size_allowed,
+                                          "rdonly",
+                                          &env->prog->aux->max_rdonly_access);
+       case PTR_TO_RDWR_BUF:
+               return check_buffer_access(env, reg, regno, reg->off,
+                                          access_size, zero_size_allowed,
+                                          "rdwr",
+                                          &env->prog->aux->max_rdwr_access);
        default: /* scalar_value|ptr_to_stack or invalid ptr */
                return check_stack_boundary(env, regno, access_size,
                                            zero_size_allowed, meta);
@@ -3734,12 +3872,14 @@ static int int_ptr_type_to_size(enum bpf_arg_type type)
        return -EINVAL;
 }
 
-static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
-                         enum bpf_arg_type arg_type,
-                         struct bpf_call_arg_meta *meta)
+static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
+                         struct bpf_call_arg_meta *meta,
+                         const struct bpf_func_proto *fn)
 {
+       u32 regno = BPF_REG_1 + arg;
        struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
        enum bpf_reg_type expected_type, type = reg->type;
+       enum bpf_arg_type arg_type = fn->arg_type[arg];
        int err = 0;
 
        if (arg_type == ARG_DONTCARE)
@@ -3811,17 +3951,28 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
                        }
                        meta->ref_obj_id = reg->ref_obj_id;
                }
-       } else if (arg_type == ARG_PTR_TO_SOCKET) {
+       } else if (arg_type == ARG_PTR_TO_SOCKET ||
+                  arg_type == ARG_PTR_TO_SOCKET_OR_NULL) {
                expected_type = PTR_TO_SOCKET;
-               if (type != expected_type)
-                       goto err_type;
+               if (!(register_is_null(reg) &&
+                     arg_type == ARG_PTR_TO_SOCKET_OR_NULL)) {
+                       if (type != expected_type)
+                               goto err_type;
+               }
        } else if (arg_type == ARG_PTR_TO_BTF_ID) {
                expected_type = PTR_TO_BTF_ID;
                if (type != expected_type)
                        goto err_type;
-               if (reg->btf_id != meta->btf_id) {
-                       verbose(env, "Helper has type %s got %s in R%d\n",
-                               kernel_type_name(meta->btf_id),
+               if (!fn->check_btf_id) {
+                       if (reg->btf_id != meta->btf_id) {
+                               verbose(env, "Helper has type %s got %s in R%d\n",
+                                       kernel_type_name(meta->btf_id),
+                                       kernel_type_name(reg->btf_id), regno);
+
+                               return -EACCES;
+                       }
+               } else if (!fn->check_btf_id(reg->btf_id, arg)) {
+                       verbose(env, "Helper does not support %s in R%d\n",
                                kernel_type_name(reg->btf_id), regno);
 
                        return -EACCES;
@@ -3855,6 +4006,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
                else if (!type_is_pkt_pointer(type) &&
                         type != PTR_TO_MAP_VALUE &&
                         type != PTR_TO_MEM &&
+                        type != PTR_TO_RDONLY_BUF &&
+                        type != PTR_TO_RDWR_BUF &&
                         type != expected_type)
                        goto err_type;
                meta->raw_mode = arg_type == ARG_PTR_TO_UNINIT_MEM;
@@ -4643,10 +4796,12 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
        meta.func_id = func_id;
        /* check args */
        for (i = 0; i < 5; i++) {
-               err = btf_resolve_helper_id(&env->log, fn, i);
-               if (err > 0)
-                       meta.btf_id = err;
-               err = check_func_arg(env, BPF_REG_1 + i, fn->arg_type[i], &meta);
+               if (!fn->check_btf_id) {
+                       err = btf_resolve_helper_id(&env->log, fn, i);
+                       if (err > 0)
+                               meta.btf_id = err;
+               }
+               err = check_func_arg(env, i, &meta, fn);
                if (err)
                        return err;
        }
@@ -4749,6 +4904,18 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
                regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL;
                regs[BPF_REG_0].id = ++env->id_gen;
                regs[BPF_REG_0].mem_size = meta.mem_size;
+       } else if (fn->ret_type == RET_PTR_TO_BTF_ID_OR_NULL) {
+               int ret_btf_id;
+
+               mark_reg_known_zero(env, regs, BPF_REG_0);
+               regs[BPF_REG_0].type = PTR_TO_BTF_ID_OR_NULL;
+               ret_btf_id = *fn->ret_btf_id;
+               if (ret_btf_id == 0) {
+                       verbose(env, "invalid return type %d of func %s#%d\n",
+                               fn->ret_type, func_id_name(func_id), func_id);
+                       return -EINVAL;
+               }
+               regs[BPF_REG_0].btf_id = ret_btf_id;
        } else {
                verbose(env, "unknown return type %d of func %s#%d\n",
                        fn->ret_type, func_id_name(func_id), func_id);
@@ -4775,7 +4942,9 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
        if (err)
                return err;
 
-       if (func_id == BPF_FUNC_get_stack && !env->prog->has_callchain_buf) {
+       if ((func_id == BPF_FUNC_get_stack ||
+            func_id == BPF_FUNC_get_task_stack) &&
+           !env->prog->has_callchain_buf) {
                const char *err_str;
 
 #ifdef CONFIG_PERF_EVENTS
@@ -4793,6 +4962,9 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
                env->prog->has_callchain_buf = true;
        }
 
+       if (func_id == BPF_FUNC_get_stackid || func_id == BPF_FUNC_get_stack)
+               env->prog->call_get_stack = true;
+
        if (changes_data)
                clear_all_pkt_pointers(env);
        return 0;
@@ -5030,6 +5202,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 
        if (BPF_CLASS(insn->code) != BPF_ALU64) {
                /* 32-bit ALU ops on pointers produce (meaningless) scalars */
+               if (opcode == BPF_SUB && env->allow_ptr_leaks) {
+                       __mark_reg_unknown(env, dst_reg);
+                       return 0;
+               }
+
                verbose(env,
                        "R%d 32-bit pointer arithmetic prohibited\n",
                        dst);
@@ -6707,6 +6884,10 @@ static void mark_ptr_or_null_reg(struct bpf_func_state *state,
                        reg->type = PTR_TO_BTF_ID;
                } else if (reg->type == PTR_TO_MEM_OR_NULL) {
                        reg->type = PTR_TO_MEM;
+               } else if (reg->type == PTR_TO_RDONLY_BUF_OR_NULL) {
+                       reg->type = PTR_TO_RDONLY_BUF;
+               } else if (reg->type == PTR_TO_RDWR_BUF_OR_NULL) {
+                       reg->type = PTR_TO_RDWR_BUF;
                }
                if (is_null) {
                        /* We don't need id and ref_obj_id from this point
@@ -7259,6 +7440,9 @@ static int check_return_code(struct bpf_verifier_env *env)
                        return -ENOTSUPP;
                }
                break;
+       case BPF_PROG_TYPE_SK_LOOKUP:
+               range = tnum_range(SK_DROP, SK_PASS);
+               break;
        case BPF_PROG_TYPE_EXT:
                /* freplace program can return anything as its return value
                 * depends on the to-be-replaced kernel func or bpf program.
@@ -10953,6 +11137,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
                env->strict_alignment = false;
 
        env->allow_ptr_leaks = bpf_allow_ptr_leaks();
+       env->allow_ptr_to_map_access = bpf_allow_ptr_to_map_access();
        env->bypass_spec_v1 = bpf_bypass_spec_v1();
        env->bypass_spec_v4 = bpf_bypass_spec_v4();
        env->bpf_capable = bpf_capable();