Merge tag 'oprofile-removal-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / kernel / bpf / btf.c
index 84a36ee..2efeb5f 100644 (file)
@@ -458,7 +458,7 @@ static bool btf_type_is_datasec(const struct btf_type *t)
        return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC;
 }
 
-static u32 btf_nr_types_total(const struct btf *btf)
+u32 btf_nr_types(const struct btf *btf)
 {
        u32 total = 0;
 
@@ -476,7 +476,7 @@ s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind)
        const char *tname;
        u32 i, total;
 
-       total = btf_nr_types_total(btf);
+       total = btf_nr_types(btf);
        for (i = 1; i < total; i++) {
                t = btf_type_by_id(btf, i);
                if (BTF_INFO_KIND(t->info) != kind)
@@ -3540,11 +3540,6 @@ static s32 btf_datasec_check_meta(struct btf_verifier_env *env,
                return -EINVAL;
        }
 
-       if (!btf_type_vlen(t)) {
-               btf_verifier_log_type(env, t, "vlen == 0");
-               return -EINVAL;
-       }
-
        if (!t->size) {
                btf_verifier_log_type(env, t, "size == 0");
                return -EINVAL;
@@ -5296,15 +5291,16 @@ int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *pr
  * Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
  */
 int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
-                            struct bpf_reg_state *reg)
+                            struct bpf_reg_state *regs)
 {
        struct bpf_verifier_log *log = &env->log;
        struct bpf_prog *prog = env->prog;
        struct btf *btf = prog->aux->btf;
        const struct btf_param *args;
-       const struct btf_type *t;
-       u32 i, nargs, btf_id;
+       const struct btf_type *t, *ref_t;
+       u32 i, nargs, btf_id, type_size;
        const char *tname;
+       bool is_global;
 
        if (!prog->aux->func_info)
                return -EINVAL;
@@ -5338,38 +5334,57 @@ int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
                bpf_log(log, "Function %s has %d > 5 args\n", tname, nargs);
                goto out;
        }
+
+       is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
        /* check that BTF function arguments match actual types that the
         * verifier sees.
         */
        for (i = 0; i < nargs; i++) {
+               struct bpf_reg_state *reg = &regs[i + 1];
+
                t = btf_type_by_id(btf, args[i].type);
                while (btf_type_is_modifier(t))
                        t = btf_type_by_id(btf, t->type);
                if (btf_type_is_int(t) || btf_type_is_enum(t)) {
-                       if (reg[i + 1].type == SCALAR_VALUE)
+                       if (reg->type == SCALAR_VALUE)
                                continue;
                        bpf_log(log, "R%d is not a scalar\n", i + 1);
                        goto out;
                }
                if (btf_type_is_ptr(t)) {
-                       if (reg[i + 1].type == SCALAR_VALUE) {
-                               bpf_log(log, "R%d is not a pointer\n", i + 1);
-                               goto out;
-                       }
                        /* If function expects ctx type in BTF check that caller
                         * is passing PTR_TO_CTX.
                         */
                        if (btf_get_prog_ctx_type(log, btf, t, prog->type, i)) {
-                               if (reg[i + 1].type != PTR_TO_CTX) {
+                               if (reg->type != PTR_TO_CTX) {
                                        bpf_log(log,
                                                "arg#%d expected pointer to ctx, but got %s\n",
                                                i, btf_kind_str[BTF_INFO_KIND(t->info)]);
                                        goto out;
                                }
-                               if (check_ctx_reg(env, &reg[i + 1], i + 1))
+                               if (check_ctx_reg(env, reg, i + 1))
                                        goto out;
                                continue;
                        }
+
+                       if (!is_global)
+                               goto out;
+
+                       t = btf_type_skip_modifiers(btf, t->type, NULL);
+
+                       ref_t = btf_resolve_size(btf, t, &type_size);
+                       if (IS_ERR(ref_t)) {
+                               bpf_log(log,
+                                   "arg#%d reference type('%s %s') size cannot be determined: %ld\n",
+                                   i, btf_type_str(t), btf_name_by_offset(btf, t->name_off),
+                                       PTR_ERR(ref_t));
+                               goto out;
+                       }
+
+                       if (check_mem_reg(env, reg, i + 1, type_size))
+                               goto out;
+
+                       continue;
                }
                bpf_log(log, "Unrecognized arg#%d type %s\n",
                        i, btf_kind_str[BTF_INFO_KIND(t->info)]);
@@ -5393,14 +5408,14 @@ out:
  * (either PTR_TO_CTX or SCALAR_VALUE).
  */
 int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
-                         struct bpf_reg_state *reg)
+                         struct bpf_reg_state *regs)
 {
        struct bpf_verifier_log *log = &env->log;
        struct bpf_prog *prog = env->prog;
        enum bpf_prog_type prog_type = prog->type;
        struct btf *btf = prog->aux->btf;
        const struct btf_param *args;
-       const struct btf_type *t;
+       const struct btf_type *t, *ref_t;
        u32 i, nargs, btf_id;
        const char *tname;
 
@@ -5464,16 +5479,35 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
         * Only PTR_TO_CTX and SCALAR are supported atm.
         */
        for (i = 0; i < nargs; i++) {
+               struct bpf_reg_state *reg = &regs[i + 1];
+
                t = btf_type_by_id(btf, args[i].type);
                while (btf_type_is_modifier(t))
                        t = btf_type_by_id(btf, t->type);
                if (btf_type_is_int(t) || btf_type_is_enum(t)) {
-                       reg[i + 1].type = SCALAR_VALUE;
+                       reg->type = SCALAR_VALUE;
                        continue;
                }
-               if (btf_type_is_ptr(t) &&
-                   btf_get_prog_ctx_type(log, btf, t, prog_type, i)) {
-                       reg[i + 1].type = PTR_TO_CTX;
+               if (btf_type_is_ptr(t)) {
+                       if (btf_get_prog_ctx_type(log, btf, t, prog_type, i)) {
+                               reg->type = PTR_TO_CTX;
+                               continue;
+                       }
+
+                       t = btf_type_skip_modifiers(btf, t->type, NULL);
+
+                       ref_t = btf_resolve_size(btf, t, &reg->mem_size);
+                       if (IS_ERR(ref_t)) {
+                               bpf_log(log,
+                                   "arg#%d reference type('%s %s') size cannot be determined: %ld\n",
+                                   i, btf_type_str(t), btf_name_by_offset(btf, t->name_off),
+                                       PTR_ERR(ref_t));
+                               return -EINVAL;
+                       }
+
+                       reg->type = PTR_TO_MEM_OR_NULL;
+                       reg->id = ++env->id_gen;
+
                        continue;
                }
                bpf_log(log, "Arg#%d type %s in %s() is not supported yet.\n",
@@ -5743,6 +5777,11 @@ bool btf_is_kernel(const struct btf *btf)
        return btf->kernel_btf;
 }
 
+bool btf_is_module(const struct btf *btf)
+{
+       return btf->kernel_btf && strcmp(btf->name, "vmlinux") != 0;
+}
+
 static int btf_id_cmp_func(const void *a, const void *b)
 {
        const int *pa = a, *pb = b;
@@ -5877,3 +5916,25 @@ static int __init btf_module_init(void)
 
 fs_initcall(btf_module_init);
 #endif /* CONFIG_DEBUG_INFO_BTF_MODULES */
+
+struct module *btf_try_get_module(const struct btf *btf)
+{
+       struct module *res = NULL;
+#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+       struct btf_module *btf_mod, *tmp;
+
+       mutex_lock(&btf_module_mutex);
+       list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+               if (btf_mod->btf != btf)
+                       continue;
+
+               if (try_module_get(btf_mod->module))
+                       res = btf_mod->module;
+
+               break;
+       }
+       mutex_unlock(&btf_module_mutex);
+#endif
+
+       return res;
+}