On 10/24/26 15:41, TAKANO Mitsuhiro wrote:
restore_sigcontext() handed cs/ss straight to cpu_x86_load_seg(). In
protected mode that ends in helper_load_seg(), which raises #GP for an
invalid selector and calls cpu_loop_exit_restore() -- a longjmp out of
the syscall handler. Landing in cpu_exec() that way trips
g_assert(cpu == current_cpu)
in cpu_exec_longjmp_cleanup() and aborts the whole emulator.
A guest that builds its own signal frame and executes rt_sigreturn
(SROP) leaves cs/ss zeroed, so this is easy to hit:
$ qemu-x86_64 ./hello_srop < payload # frame with cs=0, ss=0
Is this "hello_srop" program from some specific testcase, where people
could test themselves? E.g. can it be found in some repository?
If so, please explain where it comes from....
ERROR:accel/tcg/cpu-exec.c:515:cpu_exec_longjmp_cleanup:
assertion failed: (cpu == current_cpu)
Aborted
x86 Linux does not validate the selectors either: restore_sigcontext()
only does
regs->cs = sc.cs | 0x03;
regs->ss = sc.ss | 0x03;
and a bogus value matters only on the way back to user mode, where it
costs the task and not the kernel. QEMU cannot be that casual, because
the selector goes through cpu_x86_load_seg() while the syscall handler
is still running. So take the existing badframe path instead: accept
the selectors the CPU is already running with and return false for
anything else, which makes do_rt_sigreturn() raise SIGSEGV in the guest.
Tested with an x86_64 guest on an aarch64 host, against qemu master plus
this patch: a frame with cs=0x33, ss=0x2b restores and exits with the
requested code; a frame with cs=0, ss=0 now raises SIGSEGV in the guest
instead of aborting qemu (unpatched qemu 10.2.1 aborts with the
assertion above).
Signed-off-by: TAKANO Mitsuhiro <[email protected]>
---
v2:
- author and Signed-off-by now carry my real name (TAKANO Mitsuhiro)
Thanks for fixing!
Helge