Re: [PATCH bpf-next v4 1/2] bpf: fix verification of indirect var-off stack access

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

 



On Wed, Dec 6, 2023 at 1:56 PM Andrii Nakryiko
<andrii.nakryiko@xxxxxxxxx> wrote:
>
> On Wed, Dec 6, 2023 at 8:58 AM Andrei Matei <andreimatei1@xxxxxxxxx> wrote:
> >
> > This patch fixes a bug around the verification of possibly-zero-sized
> > stack accesses. When the access was done through a var-offset stack
> > pointer, check_stack_access_within_bounds was incorrectly computing the
> > maximum-offset of a zero-sized read to be the same as the register's min
> > offset. Instead, we have to take in account the register's maximum
> > possible value. The patch also simplifies how the max offset is checked;
> > the check is now simpler than for min offset.
> >
> > The bug was allowing accesses to erroneously pass the
> > check_stack_access_within_bounds() checks, only to later crash in
> > check_stack_range_initialized() when all the possibly-affected stack
> > slots are iterated (this time with a correct max offset).
> > check_stack_range_initialized() is relying on
> > check_stack_access_within_bounds() for its accesses to the
> > stack-tracking vector to be within bounds; in the case of zero-sized
> > accesses, we were essentially only verifying that the lowest possible
> > slot was within bounds. We would crash when the max-offset of the stack
> > pointer was >= 0 (which shouldn't pass verification, and hopefully is
> > not something anyone's code attempts to do in practice).
> >
> > Thanks Hao for reporting!
> >
> > Reported-by: Hao Sun <sunhao.th@xxxxxxxxx>
> > Fixes: 01f810ace9ed3 ("bpf: Allow variable-offset stack access")
> > Closes: https://lore.kernel.org/bpf/CACkBjsZGEUaRCHsmaX=h-efVogsRfK1FPxmkgb0Os_frnHiNdw@xxxxxxxxxxxxxx/
> > Signed-off-by: Andrei Matei <andreimatei1@xxxxxxxxx>
> > ---
> >  kernel/bpf/verifier.c                         | 14 +++------
> >  .../selftests/bpf/progs/verifier_var_off.c    | 29 +++++++++++++++++++
> >  2 files changed, 33 insertions(+), 10 deletions(-)
> >
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index e5ce530641ba..137240681fa9 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -6620,10 +6620,7 @@ static int check_stack_access_within_bounds(
> >
> >         if (tnum_is_const(reg->var_off)) {
> >                 min_off = reg->var_off.value + off;
> > -               if (access_size > 0)
> > -                       max_off = min_off + access_size - 1;
> > -               else
> > -                       max_off = min_off;
> > +               max_off = min_off + access_size;
> >         } else {
> >                 if (reg->smax_value >= BPF_MAX_VAR_OFF ||
> >                     reg->smin_value <= -BPF_MAX_VAR_OFF) {
> > @@ -6632,15 +6629,12 @@ static int check_stack_access_within_bounds(
> >                         return -EACCES;
> >                 }
> >                 min_off = reg->smin_value + off;
> > -               if (access_size > 0)
> > -                       max_off = reg->smax_value + off + access_size - 1;
> > -               else
> > -                       max_off = min_off;
> > +               max_off = reg->smax_value + off + access_size;
> >         }
> >
> >         err = check_stack_slot_within_bounds(min_off, state, type);
> > -       if (!err)
> > -               err = check_stack_slot_within_bounds(max_off, state, type);
> > +       if (!err && max_off > 0)
> > +               err = -EINVAL; /* out of stack access into non-negative offsets */
> >
>
> this part looks good to me, please add my ack on resubmission
>
> Acked-by: Andrii Nakryiko <andrii@xxxxxxxxxx>
>
>
> >         if (err) {
> >                 if (tnum_is_const(reg->var_off)) {
> > diff --git a/tools/testing/selftests/bpf/progs/verifier_var_off.c b/tools/testing/selftests/bpf/progs/verifier_var_off.c
> > index 83a90afba785..9fb32b292017 100644
> > --- a/tools/testing/selftests/bpf/progs/verifier_var_off.c
> > +++ b/tools/testing/selftests/bpf/progs/verifier_var_off.c
> > @@ -224,6 +224,35 @@ __naked void access_max_out_of_bound(void)
> >         : __clobber_all);
> >  }
> >
> > +/* Similar to the test above, but this time check the special case of a
> > + * zero-sized stack access. We used to have a bug causing crashes for zero-sized
> > + * out-of-bounds accesses.
> > + */
> > +SEC("socket")
> > +__description("indirect variable-offset stack access, zero-sized, max out of bound")
> > +__failure __msg("invalid variable-offset indirect access to stack R1")
> > +__naked void zero_sized_access_max_out_of_bound(void)
>
> as Eduard mentioned, please split off selftests from kernel-side changes
>
> > +{
> > +       asm volatile ("                     \
> > +       r0 = 0;                             \
> > +       /* Fill some stack */               \
> > +       *(u64*)(r10 - 16) = r0;             \
> > +       *(u64*)(r10 - 8) = r0;              \
> > +       /* Get an unknown value */          \
> > +       r1 = *(u32*)(r1 + 0);               \
> > +       r1 &= 64;                           \
>
> did you mean 63 here? and if yes, why does the test work? :)

I did mean 63, thanks. But the test worked either way, not much difference.
`r1 &= 64` gives you a positive value that's either 0 or 64 (i.e. all the bits
except one are known), so for the relevant verification code path, it's pretty
equivalent to [0, 64) -- all that matters are the bounds.


>
> > +       r1 += -16;                          \
> > +       /* r1 is now anywhere in [-16,48)*/ \
>
> nit: space before */ ?
>
> > +       r1 += r10;                          \
> > +       r2 = 0;                             \
> > +       r3 = 0;                             \
> > +       call %[bpf_probe_read_kernel];      \
> > +       exit;                               \
> > +"      :
> > +       : __imm(bpf_probe_read_kernel)
> > +       : __clobber_all);
> > +}
> > +
> >  SEC("lwt_in")
> >  __description("indirect variable-offset stack access, min out of bound")
> >  __failure __msg("invalid variable-offset indirect access to stack R2")
> > --
> > 2.39.2
> >





[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