push_async_cb() sets in_async_callback_fn and async_entry_cnt on the callback's own frame, which is frame 0 of the fresh state it starts, and setup_func_entry() copies neither, so a subprog called by the callback carries neither. Two places read them from the innermost frame instead. is_state_visited() skips the infinite loop check when two states differ in async_entry_cnt, because seeing the same state on a second entry into an async callback is not a loop. A callback which re-arms itself and calls a subprog therefore compares the two entries at a loop inside that subprog, where the innermost frame is the subprog's and has no flag set, and the state is rejected: infinite loop detected at insn 60 push_callback_call() numbers a new entry as the caller's count plus one. When the callback re-arms itself from a subprog, the caller is that subprog's frame with a count of 0, so every entry is numbered 1, the check above never sees a difference, and a loop anywhere in such a callback is rejected the same way. Read the flag and the count from frame 0 in both places. A loop within a single entry still has a matching count and is still caught, and frame 0 of a non-async state does not have the flag set, so nothing else changes. The two other readers are already correct: check_return_code() reads frame[0], and the one in do_check() is reached only after an early return for curframe != 0. Fixes: bfc6bb74e4f1 ("bpf: Implement verifier support for validation of async callbacks.") Signed-off-by: Puranjay Mohan --- kernel/bpf/states.c | 4 ++-- kernel/bpf/verifier.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c index 66fb11b6c6a76..32e141aa6a117 100644 --- a/kernel/bpf/states.c +++ b/kernel/bpf/states.c @@ -1273,10 +1273,10 @@ int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx) continue; if (sl->state.branches) { - struct bpf_func_state *frame = sl->state.frame[sl->state.curframe]; + struct bpf_func_state *frame = sl->state.frame[0]; if (frame->in_async_callback_fn && - frame->async_entry_cnt != cur->frame[cur->curframe]->async_entry_cnt) { + frame->async_entry_cnt != cur->frame[0]->async_entry_cnt) { /* Different async_entry_cnt means that the verifier is * processing another entry into async callback. * Seeing the same state is not an indication of infinite diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index fec5a1ae6a4da..957ce8692b1a2 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10936,7 +10936,7 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins if (IS_ERR(async_cb)) return PTR_ERR(async_cb); callee = async_cb->frame[0]; - callee->async_entry_cnt = caller->async_entry_cnt + 1; + callee->async_entry_cnt = state->frame[0]->async_entry_cnt + 1; /* Convert bpf_timer_set_callback() args into timer callback args */ err = set_callee_state_cb(env, caller, callee, insn_idx); -- 2.53.0-Meta