Skip to content

Commit dadb591

Browse files
luisgerhorstAlexei Starovoitov
authored andcommitted
bpf: Fix aux usage after do_check_insn()
We must terminate the speculative analysis if the just-analyzed insn had nospec_result set. Using cur_aux() here is wrong because insn_idx might have been incremented by do_check_insn(). Therefore, introduce and use insn_aux variable. Also change cur_aux(env)->nospec in case do_check_insn() ever manages to increment insn_idx but still fail. Change the warning to check the insn class (which prevents it from triggering for ldimm64, for which nospec_result would not be problematic) and use verifier_bug_if(). In line with Eduard's suggestion, do not introduce prev_aux() because that requires one to understand that after do_check_insn() call what was current became previous. This would at-least require a comment. Fixes: d6f1c85 ("bpf: Fall back to nospec for Spectre v1") Reported-by: Paul Chaignon <[email protected]> Reported-by: Eduard Zingerman <[email protected]> Reported-by: [email protected] Link: https://lore.kernel.org/bpf/[email protected]/ Link: https://lore.kernel.org/bpf/[email protected]/ Suggested-by: Eduard Zingerman <[email protected]> Signed-off-by: Luis Gerhorst <[email protected]> Acked-by: Eduard Zingerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 0f626c9 commit dadb591

File tree

1 file changed

+14
-5
lines changed

1 file changed

+14
-5
lines changed

kernel/bpf/verifier.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19953,6 +19953,7 @@ static int do_check(struct bpf_verifier_env *env)
1995319953

1995419954
for (;;) {
1995519955
struct bpf_insn *insn;
19956+
struct bpf_insn_aux_data *insn_aux;
1995619957
int err;
1995719958

1995819959
/* reset current history entry on each new instruction */
@@ -19966,6 +19967,7 @@ static int do_check(struct bpf_verifier_env *env)
1996619967
}
1996719968

1996819969
insn = &insns[env->insn_idx];
19970+
insn_aux = &env->insn_aux_data[env->insn_idx];
1996919971

1997019972
if (++env->insn_processed > BPF_COMPLEXITY_LIMIT_INSNS) {
1997119973
verbose(env,
@@ -20042,19 +20044,19 @@ static int do_check(struct bpf_verifier_env *env)
2004220044
/* Reduce verification complexity by stopping speculative path
2004320045
* verification when a nospec is encountered.
2004420046
*/
20045-
if (state->speculative && cur_aux(env)->nospec)
20047+
if (state->speculative && insn_aux->nospec)
2004620048
goto process_bpf_exit;
2004720049

2004820050
err = do_check_insn(env, &do_print_state);
2004920051
if (error_recoverable_with_nospec(err) && state->speculative) {
2005020052
/* Prevent this speculative path from ever reaching the
2005120053
* insn that would have been unsafe to execute.
2005220054
*/
20053-
cur_aux(env)->nospec = true;
20055+
insn_aux->nospec = true;
2005420056
/* If it was an ADD/SUB insn, potentially remove any
2005520057
* markings for alu sanitization.
2005620058
*/
20057-
cur_aux(env)->alu_state = 0;
20059+
insn_aux->alu_state = 0;
2005820060
goto process_bpf_exit;
2005920061
} else if (err < 0) {
2006020062
return err;
@@ -20063,7 +20065,7 @@ static int do_check(struct bpf_verifier_env *env)
2006320065
}
2006420066
WARN_ON_ONCE(err);
2006520067

20066-
if (state->speculative && cur_aux(env)->nospec_result) {
20068+
if (state->speculative && insn_aux->nospec_result) {
2006720069
/* If we are on a path that performed a jump-op, this
2006820070
* may skip a nospec patched-in after the jump. This can
2006920071
* currently never happen because nospec_result is only
@@ -20072,8 +20074,15 @@ static int do_check(struct bpf_verifier_env *env)
2007220074
* never skip the following insn. Still, add a warning
2007320075
* to document this in case nospec_result is used
2007420076
* elsewhere in the future.
20077+
*
20078+
* All non-branch instructions have a single
20079+
* fall-through edge. For these, nospec_result should
20080+
* already work.
2007520081
*/
20076-
WARN_ON_ONCE(env->insn_idx != prev_insn_idx + 1);
20082+
if (verifier_bug_if(BPF_CLASS(insn->code) == BPF_JMP ||
20083+
BPF_CLASS(insn->code) == BPF_JMP32, env,
20084+
"speculation barrier after jump instruction may not have the desired effect"))
20085+
return -EFAULT;
2007720086
process_bpf_exit:
2007820087
mark_verifier_state_scratched(env);
2007920088
err = update_branch_counts(env, env->cur_state);

0 commit comments

Comments
 (0)