bpf: Tighten ptr_to_btf_id checks.
authorAlexei Starovoitov <ast@kernel.org>
Fri, 25 Nov 2022 22:06:17 +0000 (14:06 -0800)
committerAndrii Nakryiko <andrii@kernel.org>
Wed, 30 Nov 2022 23:33:48 +0000 (15:33 -0800)
The networking programs typically don't require CAP_PERFMON, but through kfuncs
like bpf_cast_to_kern_ctx() they can access memory through PTR_TO_BTF_ID. In
such case enforce CAP_PERFMON.
Also make sure that only GPL programs can access kernel data structures.
All kfuncs require GPL already.

Also remove allow_ptr_to_map_access. It's the same as allow_ptr_leaks and
different name for the same check only causes confusion.

Fixes: fd264ca02094 ("bpf: Add a kfunc to type cast from bpf uapi ctx to kernel ctx")
Fixes: 50c6b8a9aea2 ("selftests/bpf: Add a test for btf_type_tag "percpu"")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20221125220617.26846-1-alexei.starovoitov@gmail.com
include/linux/bpf.h
include/linux/bpf_verifier.h
kernel/bpf/verifier.c
tools/testing/selftests/bpf/progs/btf_type_tag_percpu.c
tools/testing/selftests/bpf/verifier/map_ptr.c

index 6745210..4920ac2 100644 (file)
@@ -1909,11 +1909,6 @@ static inline bool bpf_allow_uninit_stack(void)
        return perfmon_capable();
 }
 
-static inline bool bpf_allow_ptr_to_map_access(void)
-{
-       return perfmon_capable();
-}
-
 static inline bool bpf_bypass_spec_v1(void)
 {
        return perfmon_capable();
index c05aa6e..b5090e8 100644 (file)
@@ -531,7 +531,6 @@ struct bpf_verifier_env {
        bool explore_alu_limits;
        bool allow_ptr_leaks;
        bool allow_uninit_stack;
-       bool allow_ptr_to_map_access;
        bool bpf_capable;
        bool bypass_spec_v1;
        bool bypass_spec_v4;
index 4e7f1d0..d0ecc0b 100644 (file)
@@ -4703,6 +4703,18 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
        u32 btf_id;
        int ret;
 
+       if (!env->allow_ptr_leaks) {
+               verbose(env,
+                       "'struct %s' access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN\n",
+                       tname);
+               return -EPERM;
+       }
+       if (!env->prog->gpl_compatible && btf_is_kernel(reg->btf)) {
+               verbose(env,
+                       "Cannot access kernel 'struct %s' from non-GPL compatible program\n",
+                       tname);
+               return -EINVAL;
+       }
        if (off < 0) {
                verbose(env,
                        "R%d is ptr_%s invalid negative access: off=%d\n",
@@ -4823,9 +4835,9 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env,
        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) {
+       if (!env->allow_ptr_leaks) {
                verbose(env,
-                       "%s access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN\n",
+                       "'struct %s' access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN\n",
                        tname);
                return -EPERM;
        }
@@ -16679,7 +16691,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr)
 
        env->allow_ptr_leaks = bpf_allow_ptr_leaks();
        env->allow_uninit_stack = bpf_allow_uninit_stack();
-       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();
index 8feddb8..38f78d9 100644 (file)
@@ -64,3 +64,4 @@ int BPF_PROG(test_percpu_helper, struct cgroup *cgrp, const char *path)
 
        return 0;
 }
+char _license[] SEC("license") = "GPL";
index 1f82021..17ee84d 100644 (file)
@@ -9,7 +9,7 @@
        },
        .fixup_map_array_48b = { 1 },
        .result_unpriv = REJECT,
-       .errstr_unpriv = "bpf_array access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN",
+       .errstr_unpriv = "access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN",
        .result = REJECT,
        .errstr = "R1 is bpf_array invalid negative access: off=-8",
 },
@@ -26,7 +26,7 @@
        },
        .fixup_map_array_48b = { 3 },
        .result_unpriv = REJECT,
-       .errstr_unpriv = "bpf_array access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN",
+       .errstr_unpriv = "access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN",
        .result = REJECT,
        .errstr = "only read from bpf_array is supported",
 },
@@ -41,7 +41,7 @@
        },
        .fixup_map_array_48b = { 1 },
        .result_unpriv = REJECT,
-       .errstr_unpriv = "bpf_array access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN",
+       .errstr_unpriv = "access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN",
        .result = REJECT,
        .errstr = "cannot access ptr member ops with moff 0 in struct bpf_map with off 1 size 4",
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
@@ -57,7 +57,7 @@
        },
        .fixup_map_array_48b = { 1 },
        .result_unpriv = REJECT,
-       .errstr_unpriv = "bpf_array access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN",
+       .errstr_unpriv = "access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN",
        .result = ACCEPT,
        .retval = 1,
 },