Re: [PATCH v5 bpf-next 2/3] bpf: Relax precision marking in open coded iters and may_goto loop.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jun 6, 2024 at 4:39 PM Eduard Zingerman <eddyz87@xxxxxxxxx> wrote:
>
> On Thu, 2024-06-06 at 15:19 -0700, Eduard Zingerman wrote:
>
> [...]
>
> > For the following C code:
> >
> >     long arr1[1024];
> >
> >     SEC("socket")
> >     __success
> >     int test1(const void *ctx)
> >     {
> >         long i;
> >
> >         for (i = 0; i < 1024 && can_loop; i++)
> >                 arr1[i] = i;
> >         return 0;
> >     }
> >
> > clang generates the following BPF code:
> >
> > 0000000000000340 <test1>:
> >      104:       r1 = 0x0
> >      105:       r2 = 0x0 ll
> >
> > 0000000000000358 <LBB28_1>:
> >      107:       may_goto +0x4 <LBB28_3>
> >      108:       *(u64 *)(r2 + 0x0) = r1
> >      109:       r2 += 0x8
> >      110:       r1 += 0x1
> >      111:       if r1 != 0x400 goto -0x5 <LBB28_1>
> >
> > 0000000000000380 <LBB28_3>:
> >      112:       w0 = 0x0
> >      113:       exit
>
> [...]
>
> I've also took a look why the same program could be verified w/o
> can_loop, but fails with can_loop (with this series applied):
>
> 0000000000000358 <LBB28_1>:
>      107:       may_goto +0x4 <LBB28_3>
>      108:       *(u64 *)(r2 + 0x0) = r1
>      109:       r2 += 0x8
>      110:       r1 += 0x1
>      111:       if r1 != 0x400 goto -0x5 <LBB28_1>
>                    ^^
>     r1 is no longer marked precise,
>     thus maybe_widen_reg() forgets the range for it
>     when widen_imprecise_scalars() is called from
>     may_goto processing logic.
>
> As a result, verifier enumerates states
> {r2=0P,r1=scalar()}, {r2=8P,r1=scalar()}, {r2=16P,r1=scalar()}, ...
> eventually hitting the value of r2 that does not fit in 'arr1' bounds.

That's correct.
As I was arguing couple emails ago the existing
maybe_widen_reg() logic is just as damaging heuristic
as this new widen_reg() logic.

With this hack:
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 79e356ac02ab..23892759f05e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7928,7 +7928,7 @@ static void maybe_widen_reg(struct bpf_verifier_env *env,
                return;
        if (rold->precise || rcur->precise || regs_exact(rold, rcur, idmap))
                return;
-       __mark_reg_unknown(env, rcur);
+//     __mark_reg_unknown(env, rcur);
 }

the above test is passing.
Though widen_reg() widened the range the bounded loop logic still works.
The loop now looks like
r1=[1,999] r2=8
r1=[2,999] r2=16
..
and eventually the verifier goes to check all 1k iterations of the loop
and passes.

Should I disable old maybe_widen_reg() when new widen_reg() kicks in? ;)

My point is that we had good and bad heuristics. The new one
helps arena. Is it perfect? No. But based on this particular
test it's arguable which one is worse.

Anyway, I think I'm going to tighten it a bit more.

pw-bot: cr





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux