-
Notifications
You must be signed in to change notification settings - Fork 130
bpf: Warn with bpf_unreachable() kfunc maybe due to uninitialized variable #8967
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Upstream branch: b615ce5 |
7b56de2
to
49174bd
Compare
Upstream branch: b615ce5 |
c973ac8
to
e74d80a
Compare
49174bd
to
f3a4188
Compare
Upstream branch: 25b6d5d |
e74d80a
to
095dc32
Compare
Upstream branch: 25b6d5d |
095dc32
to
10f29e2
Compare
f3a4188
to
f10d83e
Compare
Upstream branch: 4e2e684 |
10f29e2
to
c517315
Compare
f10d83e
to
9857a0f
Compare
Upstream branch: d90f0bc |
Currently, the verifier has both special_kfunc_set and special_kfunc_list. When adding a new kfunc usage to the verifier, it is often confusing about whether special_kfunc_set or special_kfunc_list or both should add that kfunc. For example, some kfuncs, e.g., bpf_dynptr_from_skb, bpf_dynptr_clone, bpf_wq_set_callback_impl, does not need to be in special_kfunc_set. To avoid potential future confusion, special_kfunc_set is deleted and btf_id_set_contains(&special_kfunc_set, ...) is removed. The code is refactored with a new func check_special_kfunc(), which contains all codes covered by original branch meta.btf == btf_vmlinux && btf_id_set_contains(&special_kfunc_set, meta.func_id) There is no functionality change. Signed-off-by: Yonghong Song <[email protected]>
…iable Marc Suñé (Isovalent, part of Cisco) reported an issue where an uninitialized variable caused generating bpf prog binary code not working as expected. The reproducer is in [1] where the flags “-Wall -Werror” are enabled, but there is no warning as the compiler takes advantage of uninitialized variable to do aggressive optimization. The optimized code looks like below: ; { 0: bf 16 00 00 00 00 00 00 r6 = r1 ; bpf_printk("Start"); 1: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0x0 ll 0000000000000008: R_BPF_64_64 .rodata 3: b4 02 00 00 06 00 00 00 w2 = 0x6 4: 85 00 00 00 06 00 00 00 call 0x6 ; DEFINE_FUNC_CTX_POINTER(data) 5: 61 61 4c 00 00 00 00 00 w1 = *(u32 *)(r6 + 0x4c) ; bpf_printk("pre ipv6_hdrlen_offset"); 6: 18 01 00 00 06 00 00 00 00 00 00 00 00 00 00 00 r1 = 0x6 ll 0000000000000030: R_BPF_64_64 .rodata 8: b4 02 00 00 17 00 00 00 w2 = 0x17 9: 85 00 00 00 06 00 00 00 call 0x6 <END> The verifier will report the following failure: 9: (85) call bpf_trace_printk#6 last insn is not an exit or jmp The above verifier log does not give a clear hint about how to fix the problem and user may take quite some time to figure out that the issue is due to compiler taking advantage of uninitialized variable. In llvm internals, uninitialized variable usage may generate 'unreachable' IR insn and these 'unreachable' IR insns may indicate uninitialized variable impact on code optimization. So far, llvm BPF backend ignores 'unreachable' IR hence the above code is generated. With clang21 patch [2], those 'unreachable' IR insn are converted to func bpf_unreachable(). In order to maintain proper control flow graph for bpf progs, [2] also adds an 'exit' insn after bpf_unreachable() if bpf_unreachable() is the last insn in the function. The new code looks like: ; { 0: bf 16 00 00 00 00 00 00 r6 = r1 ; bpf_printk("Start"); 1: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0x0 ll 0000000000000008: R_BPF_64_64 .rodata 3: b4 02 00 00 06 00 00 00 w2 = 0x6 4: 85 00 00 00 06 00 00 00 call 0x6 ; DEFINE_FUNC_CTX_POINTER(data) 5: 61 61 4c 00 00 00 00 00 w1 = *(u32 *)(r6 + 0x4c) ; bpf_printk("pre ipv6_hdrlen_offset"); 6: 18 01 00 00 06 00 00 00 00 00 00 00 00 00 00 00 r1 = 0x6 ll 0000000000000030: R_BPF_64_64 .rodata 8: b4 02 00 00 17 00 00 00 w2 = 0x17 9: 85 00 00 00 06 00 00 00 call 0x6 10: 85 10 00 00 ff ff ff ff call -0x1 0000000000000050: R_BPF_64_32 bpf_unreachable 11: 95 00 00 00 00 00 00 00 exit <END> In kernel, a new kfunc bpf_unreachable() is added. During insn verification, any hit with bpf_unreachable() will result in verification failure. The kernel is able to provide better log message for debugging. With llvm patch [2] and without this patch (no bpf_unreachable() kfunc for existing kernel), e.g., for old kernels, the verifier outputs 10: <invalid kfunc call> kfunc 'bpf_unreachable' is referenced but wasn't resolved Basically, kernel does not support bpf_unreachable() kfunc. This still didn't give clear signals about possible reason. With llvm patch [2] and with this patch, the verifier outputs 10: (85) call bpf_unreachable#74479 unexpected bpf_unreachable() due to uninitialized variable? It gives much better hints for verification failure. [1] https://github.com/msune/clang_bpf/blob/main/Makefile#L3 [2] llvm/llvm-project#131731 Signed-off-by: Yonghong Song <[email protected]>
The compiler support for bpf_unreachable() ([1]) will be in llvm21, but the current kernel will have a build failure with llvm21 ([2]). So all unit tests have explicit references to bpf_unreachable(). The test where bpf_unreachable() is generated by compiler will be provided later. [1] llvm/llvm-project#131731 [2] https://patchew.org/linux/[email protected]/ Signed-off-by: Yonghong Song <[email protected]>
c517315
to
3452eaa
Compare
At least one diff in series https://patchwork.kernel.org/project/netdevbpf/list/?series=964811 expired. Closing PR. |
Pull request for series with
subject: bpf: Warn with bpf_unreachable() kfunc maybe due to uninitialized variable
version: 3
url: https://patchwork.kernel.org/project/netdevbpf/list/?series=964330