While trying to run ntdll’s exception tests in 32-bit mode, I found that one test was causing Wine itself to segfault. It’s protection fault test #18, from dlls/ntdll/tests/exception.c:250:
/* test accessing a zero selector */ { { 0x0f, 0xa8, 0x31, 0xc0, 0x8e, 0xe8, 0x65, 0xa1, 0, 0, 0, 0, 0x0f, 0xa9, 0xc3 }, /* push %gs; xor %eax,%eax; mov %ax,%gs; mov %gs:(0),%ax; pop %gs; ret */ 6, 6, FALSE, STATUS_ACCESS_VIOLATION, 2, { 0, 0xffffffff } },
That test runs and triggers a segfault as expected, but another segfault is triggered in the prologue of segv_handler when it’s trying to copy the stack canary from TLS:
segv_handler: 0x7bcbb728: push %ebp 0x7bcbb729: mov %esp,%ebp 0x7bcbb72b: sub $0x48,%esp 0x7bcbb72e: mov 0xc(%ebp),%eax 0x7bcbb731: mov %eax,-0x3c(%ebp) 0x7bcbb734: mov 0x10(%ebp),%eax 0x7bcbb737: mov %eax,-0x40(%ebp) => 0x7bcbb73a: mov %gs:0x14,%eax 0x7bcbb740: mov %eax,-0xc(%ebp) 0x7bcbb743: xor %eax,%eax
Obviously %gs does not point to the TLS area and that causes the crash. More detail on how the stack protector works: https://www.elttam.com.au/blog/playing-with-canaries/
I’m using Gentoo, which builds gcc (8.2.0 in my case) with ‘—enable-default-ssp’, enabling '-fstack-protector-strong’ by default for all compiles. I believe Arch also builds gcc and clang with this flag (https://www.reddit.com/r/archlinux/comments/6n5tkp/arch_now_enables_pie_and_...).
After rebuilding Wine with CFLAGS="-fno-stack-protector", the test passes. I’m not sure what the best fix is: - always build Wine with “-fno-stack-protector” added to CFLAGS if the compiler supports it? - use pragmas to disable stack protection just for signal handlers that might get called with a trashed %gs? - if it’s possible, add an assembly wrapper for segv_handler to set the correct %gs? - or, is this test (and setting %gs) even representative of something 32-bit Windows apps do?
Thanks, Brendan