Skip to content

Commit f46a5c4

Browse files
eddyz87Kernel Patches Daemon
authored andcommitted
bpf: dont report verifier bug for missing bpf_scc_visit on speculative path
Syzbot generated a program that triggers a verifier_bug() call in maybe_exit_scc(). maybe_exit_scc() assumes that, when called for a state with insn_idx in some SCC, there should be an instance of struct bpf_scc_visit allocated for that SCC. Turns out the assumption does not hold for speculative execution paths. See example in the next patch. maybe_scc_exit() is called from update_branch_counts() for states that reach branch count of zero, meaning that path exploration for a particular path is finished. Path exploration can finish in one of three ways: a. Verification error is found. In this case, update_branch_counts() is called only for non-speculative paths. b. Top level BPF_EXIT is reached. Such instructions are never a part of an SCC, so compute_scc_callchain() in maybe_scc_exit() will return false, and maybe_scc_exit() will return early. c. A checkpoint is reached and matched. Checkpoints are created by is_state_visited(), which calls maybe_enter_scc(), which allocates bpf_scc_visit instances for checkpoints within SCCs. Hence, for non-speculative symbolic execution paths, the assumption still holds: if maybe_scc_exit() is called for a state within an SCC, bpf_scc_visit instance must exist. This patch removes the verifier_bug() call for speculative paths. Fixes: c9e3190 ("bpf: propagate read/precision marks over state graph backedges") Reported-by: [email protected] Closes: https://lore.kernel.org/bpf/[email protected]/ Signed-off-by: Eduard Zingerman <[email protected]>
1 parent 2b3c471 commit f46a5c4

File tree

1 file changed

+18
-3
lines changed

1 file changed

+18
-3
lines changed

kernel/bpf/verifier.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,9 +1950,24 @@ static int maybe_exit_scc(struct bpf_verifier_env *env, struct bpf_verifier_stat
19501950
return 0;
19511951
visit = scc_visit_lookup(env, callchain);
19521952
if (!visit) {
1953-
verifier_bug(env, "scc exit: no visit info for call chain %s",
1954-
format_callchain(env, callchain));
1955-
return -EFAULT;
1953+
/*
1954+
* If path traversal stops inside an SCC, corresponding bpf_scc_visit
1955+
* must exist for non-speculative paths. For non-speculative paths
1956+
* traversal stops when:
1957+
* a. Verification error is found, maybe_exit_scc() is not called.
1958+
* b. Top level BPF_EXIT is reached. Top level BPF_EXIT is not a member
1959+
* of any SCC.
1960+
* c. A checkpoint is reached and matched. Checkpoints are created by
1961+
* is_state_visited(), which calls maybe_enter_scc(), which allocates
1962+
* bpf_scc_visit instances for checkpoints within SCCs.
1963+
* (c) is the only case that can reach this point.
1964+
*/
1965+
if (!st->speculative) {
1966+
verifier_bug(env, "scc exit: no visit info for call chain %s",
1967+
format_callchain(env, callchain));
1968+
return -EFAULT;
1969+
}
1970+
return 0;
19561971
}
19571972
if (visit->entry_state != st)
19581973
return 0;

0 commit comments

Comments
 (0)