Signed-off-by: Paul Gofman pgofman@codeweavers.com --- So when the overrun happens we get a syscall error instead of smashing user stack.
dlls/ntdll/unix/signal_arm.c | 4 ++++ dlls/ntdll/unix/signal_arm64.c | 4 ++++ dlls/ntdll/unix/signal_i386.c | 4 ++++ dlls/ntdll/unix/signal_x86_64.c | 4 ++++ dlls/ntdll/unix/unix_private.h | 10 +++++++++- dlls/ntdll/unix/virtual.c | 5 +++++ 6 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index a1bcb0ddd32..02267e1c285 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -780,6 +780,10 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec ) (DWORD)IP_sig(context), (DWORD)SP_sig(context), (DWORD)LR_sig(context), (DWORD)PC_sig(context), (DWORD)CPSR_sig(context) );
+ if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION + && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] )) + ERR_(seh)( "Syscall stack overrun.\n "); + if (ntdll_get_thread_data()->jmp_buf) { TRACE( "returning to handler\n" ); diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 94f280e218a..7056adca171 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -834,6 +834,10 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec ) (DWORD64)REGn_sig(28, context), (DWORD64)FP_sig(context), (DWORD64)LR_sig(context), (DWORD64)SP_sig(context) );
+ if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION + && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] )) + ERR_(seh)( "Syscall stack overrun.\n "); + if (ntdll_get_thread_data()->jmp_buf) { TRACE( "returning to handler\n" ); diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 6bb5649e2b5..4bc4bd321ac 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1716,6 +1716,10 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, void *stack_ptr, context->Ebp, context->Esp, context->SegCs, context->SegDs, context->SegEs, context->SegFs, context->SegGs, context->EFlags );
+ if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION + && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] )) + ERR_(seh)( "Syscall stack overrun.\n "); + if (ntdll_get_thread_data()->jmp_buf) { TRACE( "returning to handler\n" ); diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 68855dccacf..7c39fe5f9bc 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2525,6 +2525,10 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, TRACE_(seh)( " r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n", context->R12, context->R13, context->R14, context->R15 );
+ if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION + && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] )) + ERR_(seh)( "Syscall stack overrun.\n "); + if (ntdll_get_thread_data()->jmp_buf) { TRACE_(seh)( "returning to handler\n" ); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index a79edabc37c..07c7bebba4d 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -85,7 +85,8 @@ static const SIZE_T teb_size = 0x3800; /* TEB64 + TEB32 + debug info */ static const SIZE_T signal_stack_mask = 0xffff; static const SIZE_T signal_stack_size = 0x10000 - 0x3800; static const SIZE_T kernel_stack_size = 0x20000; -static const SIZE_T min_kernel_stack = 0x2000; +static const SIZE_T kernel_stack_guard_size = 0x1000; +static const SIZE_T min_kernel_stack = 0x3000; static const LONG teb_offset = 0x2000;
#define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1) @@ -318,6 +319,13 @@ static inline BOOL is_inside_signal_stack( void *ptr ) (char *)ptr < (char *)get_signal_stack() + signal_stack_size); }
+static inline BOOL is_inside_syscall_stack_guard( const char *stack_ptr ) +{ + const char *kernel_stack = ntdll_get_thread_data()->kernel_stack; + + return (stack_ptr >= kernel_stack && stack_ptr < kernel_stack + kernel_stack_guard_size); +} + static inline void mutex_lock( pthread_mutex_t *mutex ) { if (!process_exiting) pthread_mutex_lock( mutex ); diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 94b300c5057..621e7be996d 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3100,6 +3100,7 @@ NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SI SIZE_T commit_size, SIZE_T extra_size ) { struct file_view *view; + char *kernel_stack; NTSTATUS status; sigset_t sigset; SIZE_T size; @@ -3143,6 +3144,10 @@ NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SI delete_view( view ); goto done; } + /* setup kernel stack no access guard page */ + kernel_stack = (char *)view->base + view->size; + set_page_vprot( kernel_stack, kernel_stack_guard_size, VPROT_COMMITTED ); + mprotect_range( kernel_stack, kernel_stack_guard_size, 0, 0 ); }
/* note: limit is lower than base since the stack grows down */
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- The observed problem is seen as semi-random crashes in Resident Evil Village reproducible on Nvidia. At least vkCreateComputePipelines() sometimes needs more stack space than currently available. Since winevulkan switch to wine_unix_call interface most of the native Vulkan calls go from syscall stack which size is quite small. This might also be a potential issue with the other native Unix libraries.
dlls/ntdll/unix/unix_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 07c7bebba4d..248a11479c1 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -84,7 +84,7 @@ static const SIZE_T page_size = 0x1000; static const SIZE_T teb_size = 0x3800; /* TEB64 + TEB32 + debug info */ static const SIZE_T signal_stack_mask = 0xffff; static const SIZE_T signal_stack_size = 0x10000 - 0x3800; -static const SIZE_T kernel_stack_size = 0x20000; +static const SIZE_T kernel_stack_size = 0x60000; static const SIZE_T kernel_stack_guard_size = 0x1000; static const SIZE_T min_kernel_stack = 0x3000; static const LONG teb_offset = 0x2000;