diff options
| author | Alexei Starovoitov <ast@kernel.org> | 2026-10-20 23:19:39 +0000 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-10-21 17:50:51 +0000 |
| commit | 2e320ea9a883b307bed2a7a54af96ca0b902f902 (patch) | |
| tree | 8f9f1c1ade0e727bc1071c0f66e13ce791358813 /kernel | |
| parent | 60e1e9f03ba733285f4e39c0b6f7220b6fd52d80 (diff) | |
bpf: Make unwind_exit of an exception callback exit in JITs
For the verifier unwind_exit of an exception callback is exit. For JITs
the callback is a subprog, so they emit the lookup of the return address.
The idea was that the kernel calls the callback and the lookup finds
nothing.
But an exception callback has no frame of its own. It returns from
the frame of the main prog that threw, and the kernel isn't always
the caller of that one:
- An extension returns to the caller of the subprog that it replaced.
- After a tail call in a subprog the main prog returns to the caller of
that subprog.
When unwind_goto follows that call, the callback goes to the pad, and
the pad wasn't verified with it:
r6 = 1
call a // can unwind
unwind_goto pad
r6 = 2
call b // cannot unwind
unwind_goto pad // stays, since the pad is not dead code
exit
pad:
r0 = r6 // r6 is 1 for the verifier
An extension without unwind_exit can replace b(). When it throws and its
exception callback ends with unwind_exit, the pad runs with r6 = 2.
Both JITs ask bpf_prog_can_unwind(). Let it say no for an exception
callback.
An async callback has a frame of its own and the kernel is the caller.
Fixes: a2d274771321 ("bpf: Add unwind_goto and unwind_exit insns")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/5f24cbed1ec4a6a0ecd0b834d738c48dc9eb64362be4fa50dfb0eaddfad928b3@mail.kernel.org/
Link: https://patch.msgid.link/20261020231942.2568163-2-alexei.starovoitov@gmail.com
Closes: https://lore.kernel.org/bpf/sashiko-outbox-179498@kernel.org/
Diffstat (limited to 'kernel')
0 files changed, 0 insertions, 0 deletions
