mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 12:21:37 +00:00
bpf: verifier: propagate liveness on all frames
Commit7640ead939
("bpf: verifier: make sure callees don't prune with caller differences") connected up parentage chains of all frames of the stack. It didn't, however, ensure propagate_liveness() propagates all liveness information along those chains. This means pruning happening in the callee may generate explored states with incomplete liveness for the chains in lower frames of the stack. The included selftest is similar to the prior one from commit7640ead939
("bpf: verifier: make sure callees don't prune with caller differences"), where callee would prune regardless of the difference in r8 state. Now we also initialize r9 to 0 or 1 based on a result from get_random(). r9 is never read so the walk with r9 = 0 gets pruned (correctly) after the walk with r9 = 1 completes. The selftest is so arranged that the pruning will happen in the callee. Since callee does not propagate read marks of r8, the explored state at the pruning point prior to the callee will now ignore r8. Propagate liveness on all frames of the stack when pruning. Fixes:f4d7e40a5b
("bpf: introduce function calls (verification)") Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
0803278b0b
commit
83d163124c
@ -6078,15 +6078,17 @@ static int propagate_liveness(struct bpf_verifier_env *env,
|
||||
}
|
||||
/* Propagate read liveness of registers... */
|
||||
BUILD_BUG_ON(BPF_REG_FP + 1 != MAX_BPF_REG);
|
||||
/* We don't need to worry about FP liveness because it's read-only */
|
||||
for (i = 0; i < BPF_REG_FP; i++) {
|
||||
if (vparent->frame[vparent->curframe]->regs[i].live & REG_LIVE_READ)
|
||||
continue;
|
||||
if (vstate->frame[vstate->curframe]->regs[i].live & REG_LIVE_READ) {
|
||||
err = mark_reg_read(env, &vstate->frame[vstate->curframe]->regs[i],
|
||||
&vparent->frame[vstate->curframe]->regs[i]);
|
||||
if (err)
|
||||
return err;
|
||||
for (frame = 0; frame <= vstate->curframe; frame++) {
|
||||
/* We don't need to worry about FP liveness, it's read-only */
|
||||
for (i = frame < vstate->curframe ? BPF_REG_6 : 0; i < BPF_REG_FP; i++) {
|
||||
if (vparent->frame[frame]->regs[i].live & REG_LIVE_READ)
|
||||
continue;
|
||||
if (vstate->frame[frame]->regs[i].live & REG_LIVE_READ) {
|
||||
err = mark_reg_read(env, &vstate->frame[frame]->regs[i],
|
||||
&vparent->frame[frame]->regs[i]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1940,3 +1940,28 @@
|
||||
.errstr = "!read_ok",
|
||||
.result = REJECT,
|
||||
},
|
||||
{
|
||||
"calls: cross frame pruning - liveness propagation",
|
||||
.insns = {
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32),
|
||||
BPF_MOV64_IMM(BPF_REG_8, 0),
|
||||
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
|
||||
BPF_MOV64_IMM(BPF_REG_8, 1),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32),
|
||||
BPF_MOV64_IMM(BPF_REG_9, 0),
|
||||
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
|
||||
BPF_MOV64_IMM(BPF_REG_9, 1),
|
||||
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 4),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 1, 1),
|
||||
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_2, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
},
|
||||
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
|
||||
.errstr_unpriv = "function calls to other bpf functions are allowed for root only",
|
||||
.errstr = "!read_ok",
|
||||
.result = REJECT,
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user