On Fri, Dec 8, 2023 at 6:15 PM Andrii Nakryiko <andrii.nakryiko@xxxxxxxxx> wrote: > > 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; small correction, with STACK_MISC conditional jump won't mark_precise, we'd need some other instruction to trigger precision, but hopefully the point is still clear > > 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!