From: Stanislav Fomichev <sdf@google.com>
To: Ilya Leoshkevich <iii@linux.ibm.com>
Cc: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
bpf@vger.kernel.org, Heiko Carstens <hca@linux.ibm.com>,
Vasily Gorbik <gor@linux.ibm.com>,
Alexander Gordeev <agordeev@linux.ibm.com>,
Jiri Olsa <jolsa@kernel.org>
Subject: Re: [PATCH RFC bpf-next 1/1] bpf: Support 64-bit pointers to kfuncs
Date: Wed, 15 Feb 2023 09:43:25 -0800 [thread overview]
Message-ID: <Y+0Zve9/LTWaZ96a@google.com> (raw)
In-Reply-To: <7a2d61865e0fb1ef8db5bee8f7b95b3e983e59d4.camel@linux.ibm.com>
On 02/15, Ilya Leoshkevich wrote:
> On Tue, 2023-02-14 at 15:58 -0800, Stanislav Fomichev wrote:
> > On 02/14, Ilya Leoshkevich wrote:
> > > test_ksyms_module fails to emit a kfunc call targeting a module on
> > > s390x, because the verifier stores the difference between kfunc
> > > address and __bpf_call_base in bpf_insn.imm, which is s32, and
> > > modules
> > > are roughly (1 << 42) bytes away from the kernel on s390x.
> >
> > > Fix by keeping BTF id in bpf_insn.imm for BPF_PSEUDO_KFUNC_CALLs,
> > > and storing the absolute address in bpf_kfunc_desc, which JITs
> > > retrieve
> > > as usual by calling bpf_jit_get_func_addr().
> >
> > > This also fixes the problem with XDP metadata functions outlined in
> > > the description of commit 63d7b53ab59f ("s390/bpf: Implement
> > > bpf_jit_supports_kfunc_call()") by replacing address lookups with
> > > BTF
> > > id lookups. This eliminates the inconsistency between "abstract"
> > > XDP
> > > metadata functions' BTF ids and their concrete addresses.
> >
> > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> > > ---
> > > include/linux/bpf.h | 2 ++
> > > kernel/bpf/core.c | 23 ++++++++++---
> > > kernel/bpf/verifier.c | 79 +++++++++++++-------------------------
> > > -----
> > > 3 files changed, 45 insertions(+), 59 deletions(-)
> >
> > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > > index be34f7deb6c3..83ce94d11484 100644
> > > --- a/include/linux/bpf.h
> > > +++ b/include/linux/bpf.h
> > > @@ -2227,6 +2227,8 @@ bool bpf_prog_has_kfunc_call(const struct
> > > bpf_prog
> > > *prog);
> > > const struct btf_func_model *
> > > bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
> > > const struct bpf_insn *insn);
> > > +int bpf_get_kfunc_addr(const struct bpf_prog *prog, u32 func_id,
> > > u16
> > > offset,
> > > + u8 **func_addr);
> > > struct bpf_core_ctx {
> > > struct bpf_verifier_log *log;
> > > const struct btf *btf;
> > > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> > > index 3390961c4e10..a42382afe333 100644
> > > --- a/kernel/bpf/core.c
> > > +++ b/kernel/bpf/core.c
> > > @@ -1185,10 +1185,12 @@ int bpf_jit_get_func_addr(const struct
> > > bpf_prog
> > > *prog,
> > > {
> > > s16 off = insn->off;
> > > s32 imm = insn->imm;
> > > + bool fixed;
> > > u8 *addr;
> > > + int err;
> >
> > > - *func_addr_fixed = insn->src_reg != BPF_PSEUDO_CALL;
> > > - if (!*func_addr_fixed) {
> > > + switch (insn->src_reg) {
> > > + case BPF_PSEUDO_CALL:
> > > /* Place-holder address till the last pass has
> > > collected
> > > * all addresses for JITed subprograms in which
> > > case we
> > > * can pick them up from prog->aux.
> > > @@ -1200,16 +1202,29 @@ int bpf_jit_get_func_addr(const struct
> > > bpf_prog
> > > *prog,
> > > addr = (u8 *)prog->aux->func[off]-
> > > >bpf_func;
> > > else
> > > return -EINVAL;
> > > - } else {
> > > + fixed = false;
> > > + break;
> >
> > [..]
> >
> > > + case 0:
> >
> > nit: Should we define BPF_HELPER_CALL here for consistency?
> I think this would be good, the verifier currently uses 0 for this
> purpose; having a symbolic constant would surely improve readability.
> > > /* Address of a BPF helper call. Since part of the
> > > core
> > > * kernel, it's always at a fixed location.
> > > __bpf_call_base
> > > * and the helper with imm relative to it are both
> > > in core
> > > * kernel.
> > > */
> > > addr = (u8 *)__bpf_call_base + imm;
> > > + fixed = true;
> > > + break;
> > > + case BPF_PSEUDO_KFUNC_CALL:
> > > + err = bpf_get_kfunc_addr(prog, imm, off, &addr);
> > > + if (err)
> > > + return err;
> > > + fixed = true;
> > > + break;
> > > + default:
> > > + return -EINVAL;
> > > }
> >
> > > - *func_addr = (unsigned long)addr;
> > > + *func_addr_fixed = fixed;
> > > + *func_addr = addr;
> > > return 0;
> > > }
> >
> > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > > index 21e08c111702..aea59974f0d6 100644
> > > --- a/kernel/bpf/verifier.c
> > > +++ b/kernel/bpf/verifier.c
> > > @@ -2115,8 +2115,8 @@ static int add_subprog(struct
> > > bpf_verifier_env
> > > *env, int off)
> > > struct bpf_kfunc_desc {
> > > struct btf_func_model func_model;
> > > u32 func_id;
> > > - s32 imm;
> > > u16 offset;
> > > + unsigned long addr;
> > > };
> >
> > > struct bpf_kfunc_btf {
> > > @@ -2166,6 +2166,19 @@ find_kfunc_desc(const struct bpf_prog *prog,
> > > u32
> > > func_id, u16 offset)
> > > sizeof(tab->descs[0]),
> > > kfunc_desc_cmp_by_id_off);
> > > }
> >
> >
> > [..]
> >
> > > +int bpf_get_kfunc_addr(const struct bpf_prog *prog, u32 func_id,
> > > u16
> > > offset,
> > > + u8 **func_addr)
> > > +{
> > > + const struct bpf_kfunc_desc *desc;
> > > +
> > > + desc = find_kfunc_desc(prog, func_id, offset);
> > > + if (WARN_ON_ONCE(!desc))
> > > + return -EINVAL;
> > > +
> > > + *func_addr = (u8 *)desc->addr;
> > > + return 0;
> > > +}
> >
> > This function isn't doing much and has a single caller. Should we
> > just
> > export find_kfunc_desc?
> We would have to export struct bpf_kfunc_desc as well; I thought it's
> better to add an extra function so that we could keep hiding the
> struct.
Ah, good point. In this case seems ok to have this extra wrapper.
On that note: what's the purpose of WARN_ON_ONCE here?
> > > +
> > > static struct btf *__find_kfunc_desc_btf(struct bpf_verifier_env
> > > *env,
> > > s16 offset)
> > > {
> > > @@ -2261,8 +2274,8 @@ static int add_kfunc_call(struct
> > > bpf_verifier_env
> > > *env, u32 func_id, s16 offset)
> > > struct bpf_kfunc_desc *desc;
> > > const char *func_name;
> > > struct btf *desc_btf;
> > > - unsigned long call_imm;
> > > unsigned long addr;
> > > + void *xdp_kfunc;
> > > int err;
> >
> > > prog_aux = env->prog->aux;
> > > @@ -2346,24 +2359,21 @@ static int add_kfunc_call(struct
> > > bpf_verifier_env
> > > *env, u32 func_id, s16 offset)
> > > return -EINVAL;
> > > }
> >
> > > - call_imm = BPF_CALL_IMM(addr);
> > > - /* Check whether or not the relative offset overflows desc-
> > > >imm */
> > > - if ((unsigned long)(s32)call_imm != call_imm) {
> > > - verbose(env, "address of kernel function %s is out
> > > of range\n",
> > > - func_name);
> > > - return -EINVAL;
> > > - }
> > > -
> > > if (bpf_dev_bound_kfunc_id(func_id)) {
> > > err = bpf_dev_bound_kfunc_check(&env->log,
> > > prog_aux);
> > > if (err)
> > > return err;
> > > +
> > > + xdp_kfunc = bpf_dev_bound_resolve_kfunc(env->prog,
> > > func_id);
> > > + if (xdp_kfunc)
> > > + addr = (unsigned long)xdp_kfunc;
> > > + /* fallback to default kfunc when not supported by
> > > netdev */
> > > }
> >
> > > desc = &tab->descs[tab->nr_descs++];
> > > desc->func_id = func_id;
> > > - desc->imm = call_imm;
> > > desc->offset = offset;
> > > + desc->addr = addr;
> > > err = btf_distill_func_proto(&env->log, desc_btf,
> > > func_proto, func_name,
> > > &desc->func_model);
> > > @@ -2373,30 +2383,6 @@ static int add_kfunc_call(struct
> > > bpf_verifier_env
> > > *env, u32 func_id, s16 offset)
> > > return err;
> > > }
> >
> > > -static int kfunc_desc_cmp_by_imm(const void *a, const void *b)
> > > -{
> > > - const struct bpf_kfunc_desc *d0 = a;
> > > - const struct bpf_kfunc_desc *d1 = b;
> > > -
> > > - if (d0->imm > d1->imm)
> > > - return 1;
> > > - else if (d0->imm < d1->imm)
> > > - return -1;
> > > - return 0;
> > > -}
> > > -
> > > -static void sort_kfunc_descs_by_imm(struct bpf_prog *prog)
> > > -{
> > > - struct bpf_kfunc_desc_tab *tab;
> > > -
> > > - tab = prog->aux->kfunc_tab;
> > > - if (!tab)
> > > - return;
> > > -
> > > - sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]),
> > > - kfunc_desc_cmp_by_imm, NULL);
> > > -}
> > > -
> > > bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog)
> > > {
> > > return !!prog->aux->kfunc_tab;
> > > @@ -2407,14 +2393,15 @@ bpf_jit_find_kfunc_model(const struct
> > > bpf_prog
> > > *prog,
> > > const struct bpf_insn *insn)
> > > {
> > > const struct bpf_kfunc_desc desc = {
> > > - .imm = insn->imm,
> > > + .func_id = insn->imm,
> > > + .offset = insn->off,
> > > };
> > > const struct bpf_kfunc_desc *res;
> > > struct bpf_kfunc_desc_tab *tab;
> >
> > > tab = prog->aux->kfunc_tab;
> > > res = bsearch(&desc, tab->descs, tab->nr_descs,
> > > - sizeof(tab->descs[0]),
> > > kfunc_desc_cmp_by_imm);
> > > + sizeof(tab->descs[0]),
> > > kfunc_desc_cmp_by_id_off);
> >
> > > return res ? &res->func_model : NULL;
> > > }
> > > @@ -16251,7 +16238,6 @@ static int fixup_kfunc_call(struct
> > > bpf_verifier_env *env, struct bpf_insn *insn,
> > > struct bpf_insn *insn_buf, int
> > > insn_idx, int *cnt)
> > > {
> > > const struct bpf_kfunc_desc *desc;
> > > - void *xdp_kfunc;
> >
> > > if (!insn->imm) {
> > > verbose(env, "invalid kernel function call not
> > > eliminated in verifier
> > > pass\n");
> > > @@ -16259,20 +16245,6 @@ static int fixup_kfunc_call(struct
> > > bpf_verifier_env *env, struct bpf_insn *insn,
> > > }
> >
> > > *cnt = 0;
> > > -
> > > - if (bpf_dev_bound_kfunc_id(insn->imm)) {
> > > - xdp_kfunc = bpf_dev_bound_resolve_kfunc(env->prog,
> > > insn->imm);
> > > - if (xdp_kfunc) {
> > > - insn->imm = BPF_CALL_IMM(xdp_kfunc);
> > > - return 0;
> > > - }
> > > -
> > > - /* fallback to default kfunc when not supported by
> > > netdev */
> > > - }
> > > -
> > > - /* insn->imm has the btf func_id. Replace it with
> > > - * an address (relative to __bpf_call_base).
> > > - */
> > > desc = find_kfunc_desc(env->prog, insn->imm, insn->off);
> > > if (!desc) {
> > > verbose(env, "verifier internal error: kernel
> > > function descriptor not
> > > found for func_id %u\n",
> > > @@ -16280,7 +16252,6 @@ static int fixup_kfunc_call(struct
> > > bpf_verifier_env *env, struct bpf_insn *insn,
> > > return -EFAULT;
> > > }
> >
> > > - insn->imm = desc->imm;
> > > if (insn->off)
> > > return 0;
> > > if (desc->func_id ==
> > > special_kfunc_list[KF_bpf_obj_new_impl]) {
> > > @@ -16834,8 +16805,6 @@ static int do_misc_fixups(struct
> > > bpf_verifier_env
> > > *env)
> > > }
> > > }
> >
> >
> > [..]
> >
> > > - sort_kfunc_descs_by_imm(env->prog);
> >
> > If we are not doing sorting here, how does the bsearch work?
> add_kfunc_call() already makes sure that kfuncs are sorted in the
> kfunc_desc_cmp_by_id_off() order. fixup_kfunc_call() used to put
> addresses into imms and re-sort based on that, however, after this
> patch it's not needed anymore: the code (e.g.
> bpf_jit_find_kfunc_model()) continues to do lookups in
> the kfunc_desc_cmp_by_id_off() order.
Makes sense, thank you 👍
> > > -
> > > return 0;
> > > }
> >
> > > --
> > > 2.39.1
> >
next prev parent reply other threads:[~2023-02-15 17:43 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-02-14 21:28 [PATCH RFC bpf-next 0/1] bpf: Support 64-bit pointers to kfuncs Ilya Leoshkevich
2023-02-14 21:28 ` [PATCH RFC bpf-next 1/1] " Ilya Leoshkevich
2023-02-14 23:58 ` Stanislav Fomichev
2023-02-15 10:07 ` Ilya Leoshkevich
2023-02-15 17:43 ` Stanislav Fomichev [this message]
2023-02-15 17:49 ` Ilya Leoshkevich
2023-02-15 18:33 ` Stanislav Fomichev
2023-02-15 21:54 ` Ilya Leoshkevich
2023-02-15 21:59 ` Alexei Starovoitov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Y+0Zve9/LTWaZ96a@google.com \
--to=sdf@google.com \
--cc=agordeev@linux.ibm.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=gor@linux.ibm.com \
--cc=hca@linux.ibm.com \
--cc=iii@linux.ibm.com \
--cc=jolsa@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox