On 2/25/26 12:02 AM, Florian Hofhammer wrote:
On 24/02/2026 22:05, Pierrick Bouvier wrote:
On 2/24/26 7:50 AM, Florian Hofhammer wrote:
The syscall emulation code previously wasn't interruptible via
cpu_loop_exit(), as this construct relies on a longjmp target that is not
live anymore in the syscall handling code. Consequently, longjmp() would
operate on a (potentially overwritten) stale jump buffer. This patch adds an
additional
setjmp and the necessary handling around it to make longjmp() (and by
proxy cpu_loop_exit() safe to call even within a syscall context.
Signed-off-by: Florian Hofhammer <[email protected]>
---
linux-user/aarch64/cpu_loop.c | 2 +-
linux-user/alpha/cpu_loop.c | 2 +-
linux-user/arm/cpu_loop.c | 2 +-
linux-user/hexagon/cpu_loop.c | 2 +-
linux-user/hppa/cpu_loop.c | 4 ++++
linux-user/i386/cpu_loop.c | 8 +++++---
linux-user/include/special-errno.h | 8 ++++++++
linux-user/loongarch64/cpu_loop.c | 5 +++--
linux-user/m68k/cpu_loop.c | 2 +-
linux-user/microblaze/cpu_loop.c | 2 +-
linux-user/mips/cpu_loop.c | 5 +++--
linux-user/or1k/cpu_loop.c | 2 +-
linux-user/ppc/cpu_loop.c | 6 ++++--
linux-user/riscv/cpu_loop.c | 2 +-
linux-user/s390x/cpu_loop.c | 2 +-
linux-user/sh4/cpu_loop.c | 2 +-
linux-user/sparc/cpu_loop.c | 4 +++-
linux-user/syscall.c | 16 ++++++++++++++++
linux-user/xtensa/cpu_loop.c | 3 +++
19 files changed, 59 insertions(+), 20 deletions(-)
diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c
index 7391e2add8..f054316dce 100644
--- a/linux-user/sparc/cpu_loop.c
+++ b/linux-user/sparc/cpu_loop.c
@@ -229,7 +229,9 @@ void cpu_loop (CPUSPARCState *env)
env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5],
0, 0);
- if (ret == -QEMU_ERESTARTSYS || ret == -QEMU_ESIGRETURN) {
+ if (ret == -QEMU_ERESTARTSYS
+ || ret == -QEMU_ESIGRETURN
+ || ret == -QEMU_ESETPC) {
break;
}
Just a style nit:
if (ret == -QEMU_ERESTARTSYS ||
ret == -QEMU_ESIGRETURN ||
ret == -QEMU_ESETPC) {
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d466d0e32f..99e1ed97d9 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -43,6 +43,7 @@
#include <linux/capability.h>
#include <sched.h>
#include <sys/timex.h>
+#include <setjmp.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <sys/un.h>
@@ -600,6 +601,9 @@ const char *target_strerror(int err)
if (err == QEMU_ESIGRETURN) {
return "Successful exit from sigreturn";
}
+ if (err == QEMU_ESETPC) {
+ return "Successfully redirected control flow";
+ }
return strerror(target_to_host_errno(err));
}
@@ -14410,6 +14414,18 @@ abi_long do_syscall(CPUArchState *cpu_env, int num,
abi_long arg1,
return -QEMU_ESIGRETURN;
}
+ /*
+ * Set up a longjmp target here so that we can call cpu_loop_exit to
+ * redirect control flow back to the main loop even from within
+ * syscall-related plugin callbacks.
+ * For other types of callbacks or longjmp call sites, the longjmp target
+ * is set up in the cpu loop itself but in syscalls the target is not live
+ * anymore.
+ */
+ if (unlikely(sigsetjmp(cpu->jmp_env, 0) != 0)) {
+ return -QEMU_ESETPC;
+ }
+
Makes sense, and I guess you found that when running the series test.
Do you need all the new QEMU_FALLTHROUGH introduced here? Is it for removing
warnings?
I think they're not strictly necessary, but if I recall correctly, I had
warnings otherwise.
I can remove them if you prefer but I think making the fallthrough
explicit encodes the intent better.
If that compiles warning-free without it, you can remove it. Else, leave
it as it is.
Fallthrough attribute is precisely used to silence warning compiler, and
not to document code, even though it can help with that.
Thanks,
Pierrick