[PATCH 0/1] MR11737: ntdll: Infer the trap number in segv_handler() when the context lacks one.
An issue found while adding Apple Silicon macOS host support for building Proton (https://github.com/ValveSoftware/Proton/pull/10087). Proton's Wine version builds and then runs 64-bit and 32-bit versions of wine in order to create a base prefix as part of a redistributable package phase, all within a guest linux/amd64 container. 32-bit i386 processes translate with QEMU in this host context, while 64-bit x86_64 uses the host's Rosetta 2 translation system. It is likely but not confirmed that QEMU would similarly be used and 32-bit wine would fail to run when virtualizing linux/amd64 on linux/arm64 hardware. qemu-user synthesizes signal frames without filling in the trap number, leaving TRAP_sig() as -1. segv_handler() then falls through to the default case, logs "Got unexpected trap -1" and never services the fault, so page faults during 32-bit module loading surface as unhandled exceptions. Infer the trap from the delivered signal instead. Note that ERROR_sig() is unset for the same reason, so faults routed to TRAP_x86_PAGEFLT are classified as reads; that is sufficient to get through process startup but is not a complete emulation of the missing context. A different option to this hardening would be to work with the QEMU project to fill in its signal frames. This fix may be appropriate standalone hardening for Wine. Although discovered as a "build issue" it impacts many plausible layered and virtualized real uses of Wine. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11737
From: Nat Brown <natbro@gmail.com> qemu-user synthesizes signal frames without filling in the trap number, leaving TRAP_sig() as -1. segv_handler() then falls through to the default case, logs "Got unexpected trap -1" and never services the fault, so page faults during 32-bit module loading surface as unhandled exceptions. Infer the trap from the delivered signal instead. Note that ERROR_sig() is unset for the same reason, so faults routed to TRAP_x86_PAGEFLT are classified as reads; that is sufficient to get through process startup but is not a complete emulation of the missing context. Signed-off-by: Nat Brown <natbro@gmail.com> --- dlls/ntdll/unix/signal_i386.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index f8a0958bb95..de78fd6a468 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1956,9 +1956,21 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *_sigcontext ) struct xcontext xcontext; EXCEPTION_RECORD rec = { .ExceptionAddress = (void *)EIP_sig( sigcontext ) }; + int trap = TRAP_sig(sigcontext); + save_context( data, &xcontext.c, sigcontext ); - switch (TRAP_sig(sigcontext)) + /* qemu-user synthesizes signal frames without filling in the trap number, + * leaving it -1, so the dispatch below falls through to the default case and + * the fault is never serviced. Infer it from the signal instead. */ + if (trap < 0) switch (signal) + { + case SIGSEGV: trap = TRAP_x86_PAGEFLT; break; + case SIGBUS: trap = TRAP_x86_ALIGNFLT; break; + case SIGILL: trap = TRAP_x86_PRIVINFLT; break; + } + + switch (trap) { case TRAP_x86_OFLOW: /* Overflow exception */ rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11737
This should be fixed in QEMU. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11737#note_149625
participants (3)
-
Alexandre Julliard (@julliard) -
Nat Brown -
Nat Brown (@natbro)