When CONFIG_FUNCTION_ERROR_INJECTION is disabled, a sleepable tracing prog
is allowed to attach to '__x64_'-alike prefix symbols.

It is because the verifier does not verify whether the symbol is a kernel
function or a bpf prog. That said, a sleepable tracing prog is allowed to
attach to a bpf prog target whose name has '__x64_'-alike prefix.

For example, a sleepable fentry prog attaches to a '__x64_sys_nop' XDP
prog, and copies buffer from a user pointer with bpf_copy_from_user()
helper. After attaching the XDP prog to lo interface, the kernel BUG
could be triggered by 'ping -c 1 -W 1 127.0.0.1':

[    3.460756] BUG: sleeping function called from invalid context at 
kernel/bpf/trampoline.c:1324

Fix it by disallowing sleepable tracing prog always when its target is
bpf prog.

Fixes: 16d9c5660692 ("bpf: Always allow sleepable programs on syscalls")
Acked-by: Viktor Malik <[email protected]>
Signed-off-by: Leon Hwang <[email protected]>
---
 kernel/bpf/verifier.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 52be0a118cce..22ac47d9a553 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18935,13 +18935,16 @@ static bool is_tracing_multi_id(const struct bpf_prog 
*prog, u32 btf_id)
 }
 
 static int btf_id_allow_sleepable(u32 btf_id, unsigned long addr, const struct 
bpf_prog *prog,
-                                 const struct btf *btf)
+                                 const struct btf *btf, const struct bpf_prog 
*tgt_prog)
 {
        const struct btf_type *t;
        const char *tname;
 
        switch (prog->type) {
        case BPF_PROG_TYPE_TRACING:
+               if (tgt_prog)
+                       return -EINVAL;
+
                t = btf_type_by_id(btf, btf_id);
                if (!t)
                        return -EINVAL;
@@ -19324,7 +19327,7 @@ int bpf_check_attach_target(struct bpf_verifier_log 
*log,
                }
 
                if (prog->sleepable) {
-                       ret = btf_id_allow_sleepable(btf_id, addr, prog, btf);
+                       ret = btf_id_allow_sleepable(btf_id, addr, prog, btf, 
tgt_prog);
                        if (ret) {
                                module_put(mod);
                                bpf_log(log, "%s is not sleepable\n", tname);
@@ -19575,7 +19578,7 @@ int bpf_check_attach_btf_id_multi(struct btf *btf, 
struct bpf_prog *prog, u32 bt
 
        /* Check sleepable program attachment. */
        if (prog->sleepable) {
-               err = btf_id_allow_sleepable(btf_id, addr, prog, btf);
+               err = btf_id_allow_sleepable(btf_id, addr, prog, btf, NULL);
                if (err)
                        return err;
        }
-- 
2.55.0


Reply via email to