Re: [PATCH bpf-next] libbpf: support weak typed ksyms.
From: Hao Luo <hidden>
Date: 2021-08-07 00:49:03
Also in:
bpf
Thanks for taking a look. On Fri, Aug 6, 2021 at 3:40 PM Andrii Nakryiko [off-list ref] wrote:
On Mon, Aug 2, 2021 at 2:29 PM Hao Luo [off-list ref] wrote:quoted
Currently weak typeless ksyms have default value zero, when they don't exist in the kernel. However, weak typed ksyms are rejected by libbpf. This means that if a bpf object contains the declaration of a non-existing weak typed ksym, it will be rejected even if there is no program that references the symbol. In fact, we could let them to pass the checks in libbpf and leave the object to be rejected by the bpf verifier. More specifically, upon seeing a weak typed symbol, libbpf can assign it a zero btf_id, which is associated to the type 'void'. The verifier expects the symbol to be BTF_VAR_KIND instead, therefore will reject loading. In practice, we often add new kernel symbols and roll out the kernel changes to fleet. And we want to release a single bpf object that can be loaded on both the new and the old kernels. Passing weak typed ksyms in libbpf allows us to do so as long as the programs that reference the new symbols are disabled on the old kernel.How do you detect whether a given ksym is present or not? You check that from user-space and then use .rodata to turn off pieces of BPF logic? That's quite inconvenient. It would be great if these typed ksyms worked the same way as typeless ones:
It's not by detect. In my use case, I can add a flag to the application to disable/enable loading a BPF program. Because we know at which kernel version a new symbol was introduced, we can coordinate the application flag with the kernel version to avoid the faulting code being loaded on an old kernel.
extern const int bpf_link_fops3 __ksym __weak;
/* then in BPF program */
if (&bpf_link_fops3) {
/* use bpf_link_fops3 */
}
I haven't tried, but I suspect it could be made to work if libbpf
replaces corresponding ldimm64 instruction (with BTF ID) into a plain
ldimm64 instruction loading 0 directly. That would allow the above
check (and it would be known false to the verifier) to succeed without
the verifier rejecting the BPF program. If actual use of non-existing
typed symbol is not guarded properly, verifier would see that register
is not PTR_TO_BTF_ID and wouldn't allow to use it for direct memory
reads or passing it to BPF helpers.
Have you considered such an approach?I haven't thought about this approach. I just grabbed the quickest solution I can think of. Will follow your suggestion and see if it works.
Separately, please use ASSERT_XXX() macros for tests, not plain CHECK()s. Thanks.
ACK.
quoted
Signed-off-by: Hao Luo <redacted> --- tools/lib/bpf/libbpf.c | 17 +++++- .../selftests/bpf/prog_tests/ksyms_btf.c | 42 +++++++++++++ .../selftests/bpf/progs/test_ksyms_weak.c | 60 +++++++++++++++++++ 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/test_ksyms_weak.c[...]