Thread (3 messages) flat view 3 messages, 2 authors, 2021-08-07

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
[...]
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help