Skip to content

Commit 3909637

Browse files
teckiKernel Patches Daemon
authored andcommitted
bpf: properly verify tail call behavior
A successful ebpf tail call does not return to the caller, but to the caller-of-the-caller, often just finishing the ebpf program altogether. Any restrictions that the verifier needs to take into account - notably the fact that the tail call might have modified packet pointers - are to be checked on the caller-of-the-caller. Checking it on the caller made the verifier refuse perfectly fine programs that would use the packet pointers after a tail call, which is no problem as this code is only executed if the tail call was unsuccessful, i.e. nothing happened. This patch simulates the behavior of a tail call in the verifier. A conditional jump to the code after the tail call is added for the case of an unsucessful tail call, and a return to the caller is simulated for a successful tail call. For the successful case we assume that the tail call returns an int, as tail calls are currently only allowed in functions that return and int. We always assume that the tail call modified the packet pointers, as we do not know what the tail call did. For the unsuccessful case we know nothing happened, so we do not need to add new constraints. Fixes: 1a4607f ("bpf: consider that tail calls invalidate packet pointers") Link: https://lore.kernel.org/bpf/[email protected]/ Signed-off-by: Martin Teichmann <[email protected]>
1 parent c95b89c commit 3909637

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

kernel/bpf/verifier.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11005,6 +11005,10 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
1100511005
bool in_callback_fn;
1100611006
int err;
1100711007

11008+
err = bpf_update_live_stack(env);
11009+
if (err)
11010+
return err;
11011+
1100811012
callee = state->frame[state->curframe];
1100911013
r0 = &callee->regs[BPF_REG_0];
1101011014
if (r0->type == PTR_TO_STACK) {
@@ -11911,6 +11915,25 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
1191111915
env->prog->call_get_func_ip = true;
1191211916
}
1191311917

11918+
if (func_id == BPF_FUNC_tail_call) {
11919+
if (env->cur_state->curframe) {
11920+
struct bpf_verifier_state *branch;
11921+
11922+
mark_reg_scratched(env, BPF_REG_0);
11923+
branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false);
11924+
if (IS_ERR(branch))
11925+
return PTR_ERR(branch);
11926+
clear_all_pkt_pointers(env);
11927+
mark_reg_unknown(env, regs, BPF_REG_0);
11928+
err = prepare_func_exit(env, &env->insn_idx);
11929+
if (err)
11930+
return err;
11931+
env->insn_idx--;
11932+
} else {
11933+
changes_data = false;
11934+
}
11935+
}
11936+
1191411937
if (changes_data)
1191511938
clear_all_pkt_pointers(env);
1191611939
return 0;
@@ -19876,9 +19899,6 @@ static int process_bpf_exit_full(struct bpf_verifier_env *env,
1987619899
return PROCESS_BPF_EXIT;
1987719900

1987819901
if (env->cur_state->curframe) {
19879-
err = bpf_update_live_stack(env);
19880-
if (err)
19881-
return err;
1988219902
/* exit from nested function */
1988319903
err = prepare_func_exit(env, &env->insn_idx);
1988419904
if (err)

0 commit comments

Comments
 (0)