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. It reads that from the innermost frame, but push_async_cb() sets in_async_callback_fn and async_entry_cnt on the callback's own frame, and setup_func_entry() copies neither, so a subprog called by the callback carries neither. 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 the state is rejected: infinite loop detected at insn 60 Read the flag and the count from frame 0, which push_async_cb() makes the callback's frame. 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. Fixes: bfc6bb74e4f1 ("bpf: Implement verifier support for validation of async callbacks.") Signed-off-by: Puranjay Mohan --- kernel/bpf/states.c | 4 ++-- 1 file changed, 2 insertions(+), 2 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 -- 2.53.0-Meta