]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: attribute __arg_untrusted for global function parameters
authorEduard Zingerman <eddyz87@gmail.com>
Fri, 4 Jul 2025 23:03:50 +0000 (16:03 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 7 Jul 2025 15:25:06 +0000 (08:25 -0700)
Add support for PTR_TO_BTF_ID | PTR_UNTRUSTED global function
parameters. Anything is allowed to pass to such parameters, as these
are read-only and probe read instructions would protect against
invalid memory access.

Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20250704230354.1323244-5-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/btf.c
kernel/bpf/verifier.c

index b3c8a95d38fb398b96cd92c1c141f074a6fabf35..e0414d9f5e294e404c3cfa7b19bb8c9bc56786a5 100644 (file)
@@ -7646,11 +7646,12 @@ cand_cache_unlock:
 }
 
 enum btf_arg_tag {
-       ARG_TAG_CTX      = BIT_ULL(0),
-       ARG_TAG_NONNULL  = BIT_ULL(1),
-       ARG_TAG_TRUSTED  = BIT_ULL(2),
-       ARG_TAG_NULLABLE = BIT_ULL(3),
-       ARG_TAG_ARENA    = BIT_ULL(4),
+       ARG_TAG_CTX       = BIT_ULL(0),
+       ARG_TAG_NONNULL   = BIT_ULL(1),
+       ARG_TAG_TRUSTED   = BIT_ULL(2),
+       ARG_TAG_UNTRUSTED = BIT_ULL(3),
+       ARG_TAG_NULLABLE  = BIT_ULL(4),
+       ARG_TAG_ARENA     = BIT_ULL(5),
 };
 
 /* Process BTF of a function to produce high-level expectation of function
@@ -7758,6 +7759,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
                                tags |= ARG_TAG_CTX;
                        } else if (strcmp(tag, "trusted") == 0) {
                                tags |= ARG_TAG_TRUSTED;
+                       } else if (strcmp(tag, "untrusted") == 0) {
+                               tags |= ARG_TAG_UNTRUSTED;
                        } else if (strcmp(tag, "nonnull") == 0) {
                                tags |= ARG_TAG_NONNULL;
                        } else if (strcmp(tag, "nullable") == 0) {
@@ -7818,6 +7821,31 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
                        sub->args[i].btf_id = kern_type_id;
                        continue;
                }
+               if (tags & ARG_TAG_UNTRUSTED) {
+                       struct btf *vmlinux_btf;
+                       int kern_type_id;
+
+                       if (tags & ~ARG_TAG_UNTRUSTED) {
+                               bpf_log(log, "arg#%d untrusted cannot be combined with any other tags\n", i);
+                               return -EINVAL;
+                       }
+
+                       kern_type_id = btf_get_ptr_to_btf_id(log, i, btf, t);
+                       if (kern_type_id < 0)
+                               return kern_type_id;
+
+                       vmlinux_btf = bpf_get_btf_vmlinux();
+                       ref_t = btf_type_by_id(vmlinux_btf, kern_type_id);
+                       if (!btf_type_is_struct(ref_t)) {
+                               tname = __btf_name_by_offset(vmlinux_btf, t->name_off);
+                               bpf_log(log, "arg#%d has type %s '%s', but only struct types are allowed\n",
+                                       i, btf_type_str(ref_t), tname);
+                               return -EINVAL;
+                       }
+                       sub->args[i].arg_type = ARG_PTR_TO_BTF_ID | PTR_UNTRUSTED;
+                       sub->args[i].btf_id = kern_type_id;
+                       continue;
+               }
                if (tags & ARG_TAG_ARENA) {
                        if (tags & ~ARG_TAG_ARENA) {
                                bpf_log(log, "arg#%d arena cannot be combined with any other tags\n", i);
index 87ab00b40d9f1d3ff57d95ea1047a74d3bb0e330..7af902c3ecc3f8c7a12a7947c5f7d9ff58d0c8a5 100644 (file)
@@ -10437,6 +10437,12 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
                                bpf_log(log, "R%d is not a scalar\n", regno);
                                return -EINVAL;
                        }
+               } else if (arg->arg_type & PTR_UNTRUSTED) {
+                       /*
+                        * Anything is allowed for untrusted arguments, as these are
+                        * read-only and probe read instructions would protect against
+                        * invalid memory access.
+                        */
                } else if (arg->arg_type == ARG_PTR_TO_CTX) {
                        ret = check_func_arg_reg_off(env, reg, regno, ARG_DONTCARE);
                        if (ret < 0)