bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andrii Nakryiko <andrii.nakryiko@gmail.com>
To: Eduard Zingerman <eddyz87@gmail.com>
Cc: bpf@vger.kernel.org, ast@kernel.org, andrii@kernel.org,
	 daniel@iogearbox.net, martin.lau@linux.dev, kernel-team@fb.com,
	 yonghong.song@linux.dev, sunhao.th@gmail.com
Subject: Re: [PATCH bpf-next 2/4] bpf: track find_equal_scalars history on per-instruction level
Date: Fri, 1 Mar 2024 09:34:32 -0800	[thread overview]
Message-ID: <CAEf4BzZjps4+teYzWw8=8Jg0M59bCVRaB_0zLNTmfveBQ63C3Q@mail.gmail.com> (raw)
In-Reply-To: <b1b259639635e9328bbbbc8e0683b14242f177e2.camel@gmail.com>

On Wed, Feb 28, 2024 at 3:29 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Wed, 2024-02-28 at 15:01 -0800, Andrii Nakryiko wrote:
> [...]
>
> > > @@ -3332,6 +3402,12 @@ static int push_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_st
> > >                           "verifier insn history bug: insn_idx %d cur flags %x new flags %x\n",
> > >                           env->insn_idx, cur_hist_ent->flags, insn_flags);
> > >                 cur_hist_ent->flags |= insn_flags;
> > > +               if (cur_hist_ent->equal_scalars != 0) {
> > > +                       verbose(env, "verifier bug: insn_idx %d equal_scalars != 0: %#llx\n",
> > > +                               env->insn_idx, cur_hist_ent->equal_scalars);
> > > +                       return -EFAULT;
> > > +               }
> >
> > let's do WARN_ONCE() just like we do for flags? why deviating?
>
> Ok
>
> [...]
>
> > >  /* For given verifier state backtrack_insn() is called from the last insn to
> > > @@ -3802,6 +3917,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
> > >                          */
> > >                         return 0;
> > >                 } else if (BPF_SRC(insn->code) == BPF_X) {
> > > +                       bt_set_equal_scalars(bt, hist);
> > >                         if (!bt_is_reg_set(bt, dreg) && !bt_is_reg_set(bt, sreg))
> > >                                 return 0;
> > >                         /* dreg <cond> sreg
> > > @@ -3812,6 +3928,9 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
> > >                          */
> > >                         bt_set_reg(bt, dreg);
> > >                         bt_set_reg(bt, sreg);
> > > +                       bt_set_equal_scalars(bt, hist);
> > > +               } else if (BPF_SRC(insn->code) == BPF_K) {
> > > +                       bt_set_equal_scalars(bt, hist);
> >
> > Can you please elaborate why we are doing bt_set_equal_scalars() in
> > these three places and not everywhere else? I'm trying to understand
> > whether we should do it more generically for any instruction either
> > before or after all the bt_set_xxx() calls...
>
> The before call for BPF_X is for situation when dreg/sreg are not yet
> tracked precise but one of the registers that gained range because of
> this 'if' is already tracked.
>
> The after call for BPF_X is for situation when say dreg is already
> tracked precise but sreg is not and there are some registers had same
> id as sreg, that gained range when this 'if' was processed.
> The equal_scalars_bpf_x_dst() test case covers this situation.
> Here it is for your convenience:
>
>     /* Registers r{0,1,2} share same ID when 'if r1 > r3' insn is processed,
>      * check that verifier marks r{0,1,2} as precise while backtracking
>      * 'if r1 > r3' with r3 already marked.
>      */
>     SEC("socket")
>     __success __log_level(2)
>     __flag(BPF_F_TEST_STATE_FREQ)
>     __msg("frame0: regs=r3 stack= before 5: (2d) if r1 > r3 goto pc+0")
>     __msg("frame0: parent state regs=r0,r1,r2,r3 stack=:")
>     __msg("frame0: regs=r0,r1,r2,r3 stack= before 4: (b7) r3 = 7")
>     __naked void equal_scalars_bpf_x_dst(void)
>     {
>         asm volatile (
>         /* r0 = random number up to 0xff */
>         "call %[bpf_ktime_get_ns];"
>         "r0 &= 0xff;"
>         /* tie r0.id == r1.id == r2.id */
>         "r1 = r0;"
>         "r2 = r0;"
>         "r3 = 7;"
>         "if r1 > r3 goto +0;"
>         /* force r0 to be precise, this eventually marks r1 and r2 as
>          * precise as well because of shared IDs
>          */
>         "r4 = r10;"
>         "r4 += r3;"
>         "r0 = 0;"
>         "exit;"
>         :
>         : __imm(bpf_ktime_get_ns)
>         : __clobber_all);
>     }
>
> The before call for BPF_K is the same as before call for BPF_X: for
> situation when dreg is not yet tracked precise, but one of the
> registers that gained range because of this 'if' is already tracked.
>
> The calls are placed at point where conditional jumps are processed
> because 'equal_scalars' are only recorded for conditional jumps.

As I mentioned in offline conversation, I wonder if it's better and
less error-prone to do linked register processing in backtrack_insn()
not just for conditional jumps, for all instructions? Whenever we
currently do bpf_set_reg(), we can first check if there are linked
registers and they contain a register we are about to set precise. If
that's the case, set all of them precise.

That would make it unnecessary to have this "before BPF_X|BPF_K"
checks, I think.

It might be sufficient to process just conditional jumps given today's
use of linked registers, but is there any downside to doing it across
all instructions? Are you worried about regression in number of states
due to precision? Or performance?

>
> >
> > >                          /* else dreg <cond> K
> > >                           * Only dreg still needs precision before
> > >                           * this insn, so for the K-based conditional
>
> [...]

  reply	other threads:[~2024-03-01 17:34 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-22  0:50 [PATCH bpf-next 0/4] bpf: track find_equal_scalars history on per-instruction level Eduard Zingerman
2024-02-22  0:50 ` [PATCH bpf-next 1/4] bpf: replace env->cur_hist_ent with a getter function Eduard Zingerman
2024-02-28 19:46   ` Andrii Nakryiko
2024-02-28 21:23     ` Eduard Zingerman
2024-02-22  0:50 ` [PATCH bpf-next 2/4] bpf: track find_equal_scalars history on per-instruction level Eduard Zingerman
2024-02-28 19:58   ` Andrii Nakryiko
2024-02-28 21:16     ` Eduard Zingerman
2024-02-28 21:36       ` Andrii Nakryiko
2024-02-28 22:39         ` Eduard Zingerman
2024-02-28 21:40       ` Andrii Nakryiko
2024-02-28 23:01   ` Andrii Nakryiko
2024-02-28 23:29     ` Eduard Zingerman
2024-03-01 17:34       ` Andrii Nakryiko [this message]
2024-03-01 17:44         ` Eduard Zingerman
2024-03-04 23:37           ` Andrii Nakryiko
2024-02-22  0:50 ` [PATCH bpf-next 3/4] bpf: remove mark_precise_scalar_ids() Eduard Zingerman
2024-02-22  0:50 ` [PATCH bpf-next 4/4] selftests/bpf: tests for per-insn find_equal_scalars() precision tracking Eduard Zingerman

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='CAEf4BzZjps4+teYzWw8=8Jg0M59bCVRaB_0zLNTmfveBQ63C3Q@mail.gmail.com' \
    --to=andrii.nakryiko@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=kernel-team@fb.com \
    --cc=martin.lau@linux.dev \
    --cc=sunhao.th@gmail.com \
    --cc=yonghong.song@linux.dev \
    /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;
as well as URLs for NNTP newsgroup(s).