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