[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAEf4BzYX8Vg1YBHwGxj7cs+6FjsxnnYfxp1NKViZzO3nm=xudA@mail.gmail.com>
Date: Wed, 11 Aug 2021 16:41:47 -0700
From: Andrii Nakryiko <andrii.nakryiko@...il.com>
To: Hao Luo <haoluo@...gle.com>
Cc: Networking <netdev@...r.kernel.org>, bpf <bpf@...r.kernel.org>,
Alexei Starovoitov <ast@...nel.org>,
Andrii Nakryiko <andriin@...com>,
Daniel Borkmann <daniel@...earbox.net>,
Martin KaFai Lau <kafai@...com>,
Song Liu <songliubraving@...com>, Yonghong Song <yhs@...com>
Subject: Re: [PATCH bpf-next v2] libbpf: support weak typed ksyms.
On Wed, Aug 11, 2021 at 3:40 PM Hao Luo <haoluo@...gle.com> wrote:
>
> Currently weak typeless ksyms have default value zero, when they don't
> exist in the kernel. However, weak typed ksyms are rejected by libbpf
> if they can not be resolved. This means that if a bpf object contains
> the declaration of a nonexistent weak typed ksym, it will be rejected
> even if there is no program that references the symbol.
>
> Nonexistent weak typed ksyms can also default to zero just like
> typeless ones. This allows programs that access weak typed ksyms to be
> accepted by verifier, if the accesses are guarded. For example,
>
> extern const int bpf_link_fops3 __ksym __weak;
>
> /* then in BPF program */
>
> if (&bpf_link_fops3) {
> /* use bpf_link_fops3 */
> }
>
> If actual use of nonexistent typed ksym 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.
>
> Signed-off-by: Hao Luo <haoluo@...gle.com>
> ---
> Changes since v1:
> - Weak typed symbols default to zero, as suggested by Andrii.
> - Use ASSERT_XXX() for tests.
>
> tools/lib/bpf/libbpf.c | 17 ++++--
> .../selftests/bpf/prog_tests/ksyms_btf.c | 31 ++++++++++
> .../selftests/bpf/progs/test_ksyms_weak.c | 57 +++++++++++++++++++
> 3 files changed, 100 insertions(+), 5 deletions(-)
> create mode 100644 tools/testing/selftests/bpf/progs/test_ksyms_weak.c
>
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index cb106e8c42cb..e7547a2967cf 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -5277,11 +5277,11 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
> }
> insn[1].imm = ext->kcfg.data_off;
> } else /* EXT_KSYM */ {
> - if (ext->ksym.type_id) { /* typed ksyms */
> + if (ext->ksym.type_id && ext->is_set) { /* typed ksyms */
> insn[0].src_reg = BPF_PSEUDO_BTF_ID;
> insn[0].imm = ext->ksym.kernel_btf_id;
> insn[1].imm = ext->ksym.kernel_btf_obj_fd;
> - } else { /* typeless ksyms */
> + } else { /* typeless ksyms or unresolved typed ksyms */
> insn[0].imm = (__u32)ext->ksym.addr;
> insn[1].imm = ext->ksym.addr >> 32;
> }
> @@ -6584,7 +6584,7 @@ static int bpf_object__read_kallsyms_file(struct bpf_object *obj)
> }
>
> static int find_ksym_btf_id(struct bpf_object *obj, const char *ksym_name,
> - __u16 kind, struct btf **res_btf,
> + __u16 kind, bool is_weak, struct btf **res_btf,
instead of teaching find_ksym_btf_id() about weak symbol, just handle
-ESRCH in bpf_object__resolve_ksym_var_btf_id (you already are
special-handling it anyway). Just move the pr_warn from
find_ksym_btf_id into bpf_object__resolve_ksym_var_btf_id.
bpf_object__resolve_ksym_func_btf_id() already has a relevant pr_warn,
which duplicates the one in find_ksym_btf_id.
> int *res_btf_fd)
> {
> int i, id, btf_fd, err;
> @@ -6608,6 +6608,9 @@ static int find_ksym_btf_id(struct bpf_object *obj, const char *ksym_name,
> break;
> }
> }
> + if (is_weak && id == -ENOENT)
> + return 0;
> +
so this is not needed
> if (id <= 0) {
> pr_warn("extern (%s ksym) '%s': failed to find BTF ID in kernel BTF(s).\n",
> __btf_kind_str(kind), ksym_name);
and this will be moved out to not emit unnecessary warnings for weak symbols
> @@ -6627,11 +6630,15 @@ static int bpf_object__resolve_ksym_var_btf_id(struct bpf_object *obj,
> const char *targ_var_name;
> int id, btf_fd = 0, err;
> struct btf *btf = NULL;
> + bool is_weak = ext->is_weak;
>
> - id = find_ksym_btf_id(obj, ext->name, BTF_KIND_VAR, &btf, &btf_fd);
> + id = find_ksym_btf_id(obj, ext->name, BTF_KIND_VAR, is_weak, &btf, &btf_fd);
> if (id < 0)
> return id;
>
> + if (is_weak && id == 0)
> + return 0;
> +
and this will handle ESRCH + is_weak as a special case
> /* find local type_id */
> local_type_id = ext->ksym.type_id;
>
> @@ -6676,7 +6683,7 @@ static int bpf_object__resolve_ksym_func_btf_id(struct bpf_object *obj,
>
> local_func_proto_id = ext->ksym.type_id;
>
> - kfunc_id = find_ksym_btf_id(obj, ext->name, BTF_KIND_FUNC,
> + kfunc_id = find_ksym_btf_id(obj, ext->name, BTF_KIND_FUNC, false,
> &kern_btf, &kern_btf_fd);
> if (kfunc_id < 0) {
> pr_warn("extern (func ksym) '%s': not found in kernel BTF\n",
[...]
> +/* existing weak symbols */
> +
> +/* test existing weak symbols can be resolved. */
> +extern const struct rq runqueues __ksym __weak; /* typed */
> +extern const void bpf_prog_active __ksym __weak; /* typeless */
> +
> +
> +/* non-existent weak symbols. */
> +
> +/* typeless symbols, default to zero. */
> +extern const void bpf_link_fops1 __ksym __weak;
> +
> +/* typed symbols, default to zero. */
> +extern const int bpf_link_fops2 __ksym __weak;
> +
> +/* typed symbols, pass if not referenced. */
> +extern const int bpf_link_fops3 __ksym __weak;
> +
this will be compiled out by compiler, you are not really testing
anything with that (libbpf doesn't even know about bpf_link_fops3).
Just drop bpf_link_fops3, bpf_link_fops2 is testing everything anyway.
> +SEC("raw_tp/sys_enter")
> +int pass_handler(const void *ctx)
> +{
> + /* tests existing symbols. */
> + struct rq *rq = (struct rq *)bpf_per_cpu_ptr(&runqueues, 0);
empty line between variable declaration and statements (better declare
and initialize rq separately, with empty line between those two)
> + if (rq)
> + out__existing_typed = rq->cpu;
> + out__existing_typeless = (__u64)&bpf_prog_active;
> +
> + /* tests non-existent symbols. */
> + out__non_existent_typeless = (__u64)&bpf_link_fops1;
> +
> + /* tests non-existent symbols. */
> + out__non_existent_typed = (__u64)&bpf_link_fops2;
> +
> + if (&bpf_link_fops2) /* can't happen */
> + out__non_existent_typed = (__u64)bpf_per_cpu_ptr(&bpf_link_fops2, 0);
> +
> + return 0;
> +}
> +
> +char _license[] SEC("license") = "GPL";
> --
> 2.32.0.605.g8dce9f2422-goog
>
Powered by blists - more mailing lists