From: Hoshino Lina <lina@lina.yt> When rsp is outside the kernel stack, the SIGUSR1 handler considers the context "out of syscall" and reports the real register values to wineserver. rsp pointing into the syscall frame is used for iret returns. Commit 0a5f7a710365 moved this earlier in the return path, creating a window in the regular direct return path where rsp points neither to the kernel stack, nor to the expected user stack. When a thread is interrupted by SIGUSR1 within this window, this exposes a bogus stack pointer to GetThreadContext(), breaking the garbage collector in Unity applications. Fix the regression by first switching to the real user stack (needed so we don't break things by touching other registers), and only switching to the syscall frame pointer in the iret paths that require it. This fixes the regression introduced by 0a5f7a710365, since GetThreadContext() will now observe the proper stack pointer during regular syscall returns. Further work would be needed to solve other corner cases and ensure that the register context returned by GetThreadContext() behaves exactly as on Windows (with no kernel-mode context info ever returned), but that is a larger/more invasive change. Suggested by: Etaash Mathamsetty <etaash.mathamsetty@gmail.com> Fixes: 0a5f7a710365 ("ntdll: Switch to the user stack before restoring the %fs register.") Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59333 Signed-off-by: Hoshino Lina <lina@lina.yt> --- dlls/ntdll/unix/signal_x86_64.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 7e644a6dd9f..2a2414a2f94 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -3240,7 +3240,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, /* push rbp-based kernel stack cfi */ __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI_CFA_IS_AT2(rcx, 0xa8, 0x01) /* frame->syscall_cfa */ - "leaq 0x70(%rcx),%rsp\n\t" /* %rsp > frame means no longer inside syscall */ + /* switch to user stack */ + "movq 0x88(%rcx),%rsp\n\t" #ifdef __linux__ "movb $1,0x340(%r13)\n\t" /* amd64_thread_data()->syscall_dispatch */ "movw 0x338(%r13),%dx\n" /* amd64_thread_data()->fs */ @@ -3297,8 +3298,6 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "3:\ttestl $0x3,%edx\n\t" /* CONTEXT_CONTROL | CONTEXT_INTEGER */ "jnz 1f\n\t" - /* switch to user stack */ - "movq 0x88(%rcx),%rsp\n\t" /* push rcx-based kernel stack cfi */ __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI(".cfi_def_cfa %rsp, 0\n\t") @@ -3323,7 +3322,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, /* pop rcx-based kernel stack cfi */ __ASM_CFI(".cfi_restore_state\n") - "1:\ttestl $0x2,%edx\n\t" /* CONTEXT_INTEGER */ + "1:\tleaq 0x70(%rcx),%rsp\n\t" /* %rsp > frame means no longer inside syscall */ + "testl $0x2,%edx\n\t" /* CONTEXT_INTEGER */ "jnz 1f\n\t" /* CONTEXT_CONTROL */ "movq (%rsp),%rcx\n\t" /* frame->rip */ @@ -3349,6 +3349,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movq (%r10),%r10\n\t" "test %r10,%r10\n\t" "jz 3b\n\t" + "leaq 0x70(%rcx),%rsp\n\t" /* %rsp > frame means no longer inside syscall */ "testl $0x2,%edx\n\t" /* CONTEXT_INTEGER */ "jnz 1b\n\t" "xchgq %r10,(%rsp)\n\t" -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10232