All of lore.kernel.org
 help / color / mirror / Atom feed
From: Brendan Jackman <jackmanb@google.com>
To: Martin KaFai Lau <kafai@fb.com>
Cc: bpf <bpf@vger.kernel.org>, Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii.nakryiko@gmail.com>,
	KP Singh <kpsingh@chromium.org>,
	Florent Revest <revest@chromium.org>,
	Ilya Leoshkevich <iii@linux.ibm.com>
Subject: Re: [PATCH v4 bpf-next] bpf: Explicitly zero-extend R0 after 32-bit cmpxchg
Date: Mon, 1 Mar 2021 17:48:35 +0100	[thread overview]
Message-ID: <CA+i-1C3ytZz6FjcPmUg5s4L51pMQDxWcZNvM86w4RHZ_o2khwg@mail.gmail.com> (raw)
In-Reply-To: <20210224221440.4ncxz7vyo7weygm3@kafai-mbp.dhcp.thefacebook.com>

On Wed, 24 Feb 2021 at 23:14, Martin KaFai Lau <kafai@fb.com> wrote:
>
> On Wed, Feb 24, 2021 at 10:32:28AM +0100, Brendan Jackman wrote:
> > On Wed, 24 Feb 2021 at 06:48, Martin KaFai Lau <kafai@fb.com> wrote:
> > >
> > > On Tue, Feb 23, 2021 at 03:08:45PM +0000, Brendan Jackman wrote:
> > > [ ... ]
> > >
> > > > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> > > > index 0ae015ad1e05..dcf18612841b 100644
> > > > --- a/kernel/bpf/core.c
> > > > +++ b/kernel/bpf/core.c
> > > > @@ -2342,6 +2342,10 @@ bool __weak bpf_helper_changes_pkt_data(void *func)
> > > >  /* Return TRUE if the JIT backend wants verifier to enable sub-register usage
> > > >   * analysis code and wants explicit zero extension inserted by verifier.
> > > >   * Otherwise, return FALSE.
> > > > + *
> > > > + * The verifier inserts an explicit zero extension after BPF_CMPXCHGs even if
> > > > + * you don't override this. JITs that don't want these extra insns can detect
> > > > + * them using insn_is_zext.
> > > >   */
> > > >  bool __weak bpf_jit_needs_zext(void)
> > > >  {
> > > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > > > index 3d34ba492d46..ec1cbd565140 100644
> > > > --- a/kernel/bpf/verifier.c
> > > > +++ b/kernel/bpf/verifier.c
> > > > @@ -11061,8 +11061,16 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
> > > >                        */
> > > >                       if (WARN_ON(!(insn.imm & BPF_FETCH)))
> > > >                               return -EINVAL;
> > > > -                     load_reg = insn.imm == BPF_CMPXCHG ? BPF_REG_0
> > > > -                                                        : insn.src_reg;
> > > > +                     /* There should already be a zero-extension inserted after BPF_CMPXCHG. */
> > > > +                     if (insn.imm == BPF_CMPXCHG) {
> > > > +                             struct bpf_insn *next = &insns[adj_idx + 1];
> > > > +
> > > > +                             if (WARN_ON(!insn_is_zext(next) || next->dst_reg != insn.src_reg))
> > > > +                                     return -EINVAL;
> > > > +                             continue;
> > > This is to avoid zext_patch again for the JITs with
> > > bpf_jit_needs_zext() == true.
> > >
> > > IIUC, at this point, aux[adj_idx].zext_dst == true which
> > > means that the check_atomic() has already marked the
> > > reg0->subreg_def properly.
> >
> > That's right... sorry I'm not sure if you're implying something here
> > or just checking understanding?
> >
> > > > +                     }
> > > > +
> > > > +                     load_reg = insn.src_reg;
> > > >               } else {
> > > >                       load_reg = insn.dst_reg;
> > > >               }
> > > > @@ -11666,6 +11674,27 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
> > > >                       continue;
> > > >               }
> > > >
> > > > +             /* BPF_CMPXCHG always loads a value into R0, therefore always
> > > > +              * zero-extends. However some archs' equivalent instruction only
> > > > +              * does this load when the comparison is successful. So here we
> > > > +              * add a BPF_ZEXT_REG after every 32-bit CMPXCHG, so that such
> > > > +              * archs' JITs don't need to deal with the issue. Archs that
> > > > +              * don't face this issue may use insn_is_zext to detect and skip
> > > > +              * the added instruction.
> > > > +              */
> > > > +             if (insn->code == (BPF_STX | BPF_W | BPF_ATOMIC) && insn->imm == BPF_CMPXCHG) {
> > > > +                     struct bpf_insn zext_patch[2] = { *insn, BPF_ZEXT_REG(BPF_REG_0) };
> > > Then should this zext_patch only be done for "!bpf_jit_needs_zext()"
> > > such that the above change in opt_subreg_zext_lo32_rnd_hi32()
> > > becomes unnecessary?
> >
> > Yep that would work but I IMO it would be a more fragile expression of
> > the logic: instead of directly checking whether something was done
> > we'd be looking at a proxy for another part of the system's behaviour.
> > I don't think it would win us anything in terms of clarity either?
> hmmm... I find it quite confusing to read.
>
> While the current opt_subreg_zext_lo32_rnd_hi32() has
> already been doing the actual zext patching work based
> on the zext_dst marking,
> this patch does zext patch for cmpxchg before opt_subreg_zext_lo32_rnd_hi32()
> even the zext_dst has already been marked.
>
> Then later in opt_subreg_zext_lo32_rnd_hi32(), code is
> added to avoid doing the zext patch again for the
> "!bpf_jit_needs_zext()" case.
>
> If there is other cases later, then changes have to be made
> in both places, one does zext patch and then another to
> avoid double patch for the "!bpf_jit_needs_zext()" case.
>
> Why not only patch it when there is no other places doing it?
>
> It may be better to do the zext patch for cmpxchg in
> opt_subreg_zext_lo32_rnd_hi32() also.  Then all zext patch
> is done in one place.  Something like:
>
> static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
>                                         const union bpf_attr *attr)
> {
>
>         for (i = 0; i < len; i++) {
>                 /* ... */
>
>                 if (!bpf_jit_needs_zext() && !is_cmpxchg_insn(insn))
>                         continue;
>
>                 /* do zext patch */
>         }
> }
>
> Would that work?

Yep - this is so much simpler and clearer. Thanks! Sending another spin.

  reply	other threads:[~2021-03-01 16:54 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-23 15:08 [PATCH v4 bpf-next] bpf: Explicitly zero-extend R0 after 32-bit cmpxchg Brendan Jackman
2021-02-24  5:47 ` Martin KaFai Lau
2021-02-24  9:32   ` Brendan Jackman
2021-02-24 22:14     ` Martin KaFai Lau
2021-03-01 16:48       ` Brendan Jackman [this message]
2021-02-24 12:02 ` Ilya Leoshkevich
2021-02-24 14:16 ` Ilya Leoshkevich
2021-02-24 22:34   ` Martin KaFai Lau
2021-02-24 23:07     ` Ilya Leoshkevich

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=CA+i-1C3ytZz6FjcPmUg5s4L51pMQDxWcZNvM86w4RHZ_o2khwg@mail.gmail.com \
    --to=jackmanb@google.com \
    --cc=andrii.nakryiko@gmail.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=iii@linux.ibm.com \
    --cc=kafai@fb.com \
    --cc=kpsingh@chromium.org \
    --cc=revest@chromium.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.