> Similar issue could be applied to lsm prog, when the
> prog->aux->attach_btf_id is in the LSM allowing list but the attach_btf is
> a malicious bpf prog's btf.

Can this LSM scenario actually occur? Looking at the code,
prog->aux->attach_btf appears to be validated to be kernel BTF at program
load time in bpf_prog_load():

kernel/bpf/syscall.c:2991
        attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd);
        ...
        if (!btf_is_kernel(attach_btf)) {
                /* attaching through specifying bpf_prog's BTF
                 * objects directly might be supported eventually
                 */
                btf_put(attach_btf);
                err = -ENOTSUPP;

The only other assignment is the bpf_get_btf_vmlinux() fallback at
syscall.c:3007, so attach_btf is never a bpf prog's BTF.

The other path for non-kernel BTF reaching btf_id_allow_sleepable() is
the tgt_prog branch in bpf_check_attach_target():

kernel/bpf/verifier.c:19149
        btf = tgt_prog ? tgt_prog->aux->btf : prog->aux->attach_btf;

But can an LSM program have a tgt_prog? bpf_prog_load_check_attach()
appears to reject it at load:

kernel/bpf/syscall.c:2752
        if (dst_prog && prog_type != BPF_PROG_TYPE_TRACING &&
            prog_type != BPF_PROG_TYPE_EXT)
                return -EINVAL;

And bpf_tracing_prog_attach() only accepts tgt_prog_fd for BPF_PROG_TYPE_EXT
(syscall.c:3673). So the BPF_PROG_TYPE_LSM arm of btf_id_allow_sleepable()
appears to be only ever reached with kernel BTF, making the 'malicious bpf
prog's btf' case unreachable.

> Fix it by disallowing sleepable tracing/lsm prog always when its target
> btf is not kernel's btf.
>
> Fixes: 16d9c5660692 ("bpf: Always allow sleepable programs on syscalls")
> Fixes: 1e6c62a88215 ("bpf: Introduce sleepable BPF programs")

Does the second Fixes: tag point at the commit that introduced the bug?
Looking at 1e6c62a88215 and up through 16d9c5660692, the tracing arm read:

        if (!check_non_sleepable_error_inject(btf_id) &&
            within_error_injection_list(addr))

On the tgt_prog path, addr is JIT text (tgt_prog->bpf_func /
aux->func[subprog]->bpf_func, verifier.c:19409-19412), which is never on
the error-injection list. With CONFIG_FUNCTION_ERROR_INJECTION=n,
within_error_injection_list() is a stub returning false
(include/linux/error-injection.h:16).

The fmodret fallback also does not help, because
btf_kfunc_is_modify_return() checks __btf_kfunc_is_allowed(), which returns
false when btf->kfunc_set_tab is NULL (kernel/bpf/btf.c:9021), and
kfunc_set_tab is only populated for vmlinux/module BTF
(__register_btf_kfunc_id_set() calls btf_get_module_btf(), btf.c:9160).

So a sleepable tracing prog attaching to another BPF program was already
rejected before 16d9c5660692. Only the has_arch_syscall_prefix(tname) path
added by 16d9c5660692 opened the hole. Keeping the 1e6c62a88215 tag could
direct AUTOSEL and stable at trees back to 5.10 that do not contain the
bug.

Would Fixes: 16d9c5660692 alone be more accurate?


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31020655174

Reply via email to