Skip to content

Commit 22ad16c

Browse files
Alexei Starovoitovshiloong
authored andcommitted
bpf: fix callees pruning callers
commit eea1c22 upstream ANBZ: torvalds#200 The commit 7640ead partially resolved the issue of callees incorrectly pruning the callers. With introduction of bounded loops and jmps_processed heuristic single verifier state may contain multiple branches and calls. It's possible that new verifier state (for future pruning) will be allocated inside callee. Then callee will exit (still within the same verifier state). It will go back to the caller and there R6-R9 registers will be read and will trigger mark_reg_read. But the reg->live for all frames but the top frame is not set to LIVE_NONE. Hence mark_reg_read will fail to propagate liveness into parent and future walking will incorrectly conclude that the states are equivalent because LIVE_READ is not set. In other words the rule for parent/live should be: whenever register parentage chain is set the reg->live should be set to LIVE_NONE. is_state_visited logic already follows this rule for spilled registers. Fixes: 7640ead ("bpf: verifier: make sure callees don't prune with caller differences") Fixes: f4d7e40 ("bpf: introduce function calls (verification)") Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Signed-off-by: Qiao Ma <[email protected]> Acked-by: Tony Lu <[email protected]>
1 parent 425cfbc commit 22ad16c

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

kernel/bpf/verifier.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6345,17 +6345,18 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
63456345
* the state of the call instruction (with WRITTEN set), and r0 comes
63466346
* from callee with its full parentage chain, anyway.
63476347
*/
6348-
for (j = 0; j <= cur->curframe; j++)
6349-
for (i = j < cur->curframe ? BPF_REG_6 : 0; i < BPF_REG_FP; i++)
6350-
cur->frame[j]->regs[i].parent = &new->frame[j]->regs[i];
63516348
/* clear write marks in current state: the writes we did are not writes
63526349
* our child did, so they don't screen off its reads from us.
63536350
* (There are no read marks in current state, because reads always mark
63546351
* their parent and current state never has children yet. Only
63556352
* explored_states can get read marks.)
63566353
*/
6357-
for (i = 0; i < BPF_REG_FP; i++)
6358-
cur->frame[cur->curframe]->regs[i].live = REG_LIVE_NONE;
6354+
for (j = 0; j <= cur->curframe; j++) {
6355+
for (i = j < cur->curframe ? BPF_REG_6 : 0; i < BPF_REG_FP; i++)
6356+
cur->frame[j]->regs[i].parent = &new->frame[j]->regs[i];
6357+
for (i = 0; i < BPF_REG_FP; i++)
6358+
cur->frame[j]->regs[i].live = REG_LIVE_NONE;
6359+
}
63596360

63606361
/* all stack frames are accessible from callee, clear them all */
63616362
for (j = 0; j <= cur->curframe; j++) {

0 commit comments

Comments
 (0)