Re: [PATCH bpf-next 1/2] bpf: handle fake register spill to stack with BPF_ST_MEM instruction

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

 



On Fri, Dec 8, 2023 at 6:01 PM Eduard Zingerman <eddyz87@xxxxxxxxx> wrote:
>
> On Fri, 2023-12-08 at 17:09 -0800, Andrii Nakryiko wrote:
> > When verifier validates BPF_ST_MEM instruction that stores known
> > constant to stack (e.g., *(u64 *)(r10 - 8) = 123), it effectively spills
> > a fake register with a constant (but initially imprecise) value to
> > a stack slot. Because read-side logic treats it as a proper register
> > fill from stack slot, we need to mark such stack slot initialization as
> > INSN_F_STACK_ACCESS instruction to stop precision backtracking from
> > missing it.
> >
> > Fixes: 41f6f64e6999 ("bpf: support non-r10 register spill/fill to/from stack in precision tracking")
> > Signed-off-by: Andrii Nakryiko <andrii@xxxxxxxxxx>
> > ---
> >  kernel/bpf/verifier.c | 1 -
> >  1 file changed, 1 deletion(-)
> >
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index fb690539d5f6..727a59e4a647 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -4498,7 +4498,6 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
> >               __mark_reg_known(&fake_reg, insn->imm);
> >               fake_reg.type = SCALAR_VALUE;
> >               save_register_state(env, state, spi, &fake_reg, size);
> > -             insn_flags = 0; /* not a register spill */
> >       } else if (reg && is_spillable_regtype(reg->type)) {
> >               /* register containing pointer is being spilled into stack */
> >               if (size != BPF_REG_SIZE) {
>
> So, the problem is that for some 'r5 = r10; *(u64 *)(r5 - 8) = 123'
> backtracking won't reset precision mark for -8, right?

no, the problem is that we won't stop at the right instruction. Let's
say we have this sequence

1: *(u64 *)(r10 - 8) = 123;
2: r1 = *(u64 *)(r10 - 8);
3: if r1 == 123 goto +10;
...

At 3: we want to set r1 to precise. We go back, see that at 2: we set
r1 from fp-8 slot, so instead of looking for r1, we start looking for
what set fp-8 now. So we go to 1:, and because it actually is not
marked as INSN_F_STACK_ACCESS, we skip it, and keep looking further
for what set fp-8. At some point we can go to parent state that didn't
even have fp-8 stack slot allocated (or we can get out and then see
that we haven't cleared all stack slot bits in our masks). So this
patch makes it so that 1: is marked as setting fp-8 slot, and
precision propagation will clear fp-8 from the mask.

Now, the subtle thing here is that this doesn't happen with STACK_ZERO
or STACK_MISC. Let's look at STACK_MISC/STACK_INVALID case.

1: *(u8 *)(r10 -1) = 123; /* now fp-8=m??????? */
2: r1 = *(u64 *)(r10 - 8); /* STACK_MISC read, r1 is set to unknown scalar */
3: if r1 == 123 goto +10;

Let's do analysis again. At 3: we mark r1 as precise, go back to 2:.
Here 2: instruction is not marked as INSN_F_STACK_ACCESS because it
wasn't stack fill due to STACK_MISC (that's handled in
check_read_fixed_off logic). So mark_chain_precision() stops here
because that instruction is resetting r1, so we clear r1 from the
mask, but this instruction isn't STACK_ACCESS, so we don't look for
fp-8 here.

I think check_stack_write_fixed_off() can always set
INSN_F_STACK_ACCESS, actually, maybe that would be easier to follow.
Even when we write STACK_ZERO/STACK_MISC. It's only
check_stack_read_fixed_off() that has to be careful and drop
INSN_F_STACK_ACCESS if we didn't really fill the register state from
the stack slot.


> That's not a tragedy we just get more precision marks than needed,
> however, I think that same logic applies to the MISC/ZERO case below.

See above, MISC/ZERO is fine as is due to check_stack_read_fixed_off()
not setting STACK_ACCESS bit, but I can also send a version that
unconditionally sets INSNS_F_STACK_ACCESS in
check_stack_write_fixed_off().

> I'll look through the tests in the morning.

Thanks, no rush!





[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