From de89ce1bfedeb386baddd047884dc73dfe6f70bf Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 17 Jun 2021 09:25:19 +0200 Subject: [PATCH] ntdll: Support growing both 32- and 64-bit stacks. Signed-off-by: Alexandre Julliard --- dlls/ntdll/unix/virtual.c | 90 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 0a4004d2db9..52af195aa56 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3131,29 +3131,67 @@ void virtual_map_user_shared_data(void) } +struct thread_stack_info +{ + char *start; + char *limit; + char *end; + SIZE_T guaranteed; + BOOL is_wow; +}; + +/*********************************************************************** + * is_inside_thread_stack + */ +static BOOL is_inside_thread_stack( void *ptr, struct thread_stack_info *stack ) +{ + TEB *teb = NtCurrentTeb(); + WOW_TEB *wow_teb = get_wow_teb( teb ); + + stack->start = teb->DeallocationStack; + stack->limit = teb->Tib.StackLimit; + stack->end = teb->Tib.StackBase; + stack->guaranteed = max( teb->GuaranteedStackBytes, page_size * (is_win64 ? 2 : 1) ); + stack->is_wow = FALSE; + if ((char *)ptr > stack->start && (char *)ptr <= stack->end) return TRUE; + + if (!wow_teb) return FALSE; + stack->start = ULongToPtr( wow_teb->DeallocationStack ); + stack->limit = ULongToPtr( wow_teb->Tib.StackLimit ); + stack->end = ULongToPtr( wow_teb->Tib.StackBase ); + stack->guaranteed = max( wow_teb->GuaranteedStackBytes, page_size * (is_win64 ? 1 : 2) ); + stack->is_wow = TRUE; + return ((char *)ptr > stack->start && (char *)ptr <= stack->end); +} + + /*********************************************************************** * grow_thread_stack */ -static NTSTATUS grow_thread_stack( char *page ) +static NTSTATUS grow_thread_stack( char *page, struct thread_stack_info *stack_info ) { NTSTATUS ret = 0; - size_t guaranteed = max( NtCurrentTeb()->GuaranteedStackBytes, page_size * (is_win64 ? 2 : 1) ); set_page_vprot_bits( page, page_size, 0, VPROT_GUARD ); mprotect_range( page, page_size, 0, 0 ); - if (page >= (char *)NtCurrentTeb()->DeallocationStack + page_size + guaranteed) + if (page >= stack_info->start + page_size + stack_info->guaranteed) { set_page_vprot_bits( page - page_size, page_size, VPROT_COMMITTED | VPROT_GUARD, 0 ); mprotect_range( page - page_size, page_size, 0, 0 ); } else /* inside guaranteed space -> overflow exception */ { - page = (char *)NtCurrentTeb()->DeallocationStack + page_size; - set_page_vprot_bits( page, guaranteed, VPROT_COMMITTED, VPROT_GUARD ); - mprotect_range( page, guaranteed, 0, 0 ); + page = stack_info->start + page_size; + set_page_vprot_bits( page, stack_info->guaranteed, VPROT_COMMITTED, VPROT_GUARD ); + mprotect_range( page, stack_info->guaranteed, 0, 0 ); ret = STATUS_STACK_OVERFLOW; } - NtCurrentTeb()->Tib.StackLimit = page; + if (stack_info->is_wow) + { + WOW_TEB *wow_teb = get_wow_teb( NtCurrentTeb() ); + wow_teb->Tib.StackLimit = PtrToUlong( page ); + } + else NtCurrentTeb()->Tib.StackLimit = page; return ret; } @@ -3171,14 +3209,14 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack ) vprot = get_page_vprot( page ); if (!is_inside_signal_stack( stack ) && (vprot & VPROT_GUARD)) { - if (page < (char *)NtCurrentTeb()->DeallocationStack || - page >= (char *)NtCurrentTeb()->Tib.StackBase) + struct thread_stack_info stack_info; + if (!is_inside_thread_stack( page, &stack_info )) { set_page_vprot_bits( page, page_size, 0, VPROT_GUARD ); mprotect_range( page, page_size, 0, 0 ); ret = STATUS_GUARD_PAGE_VIOLATION; } - else ret = grow_thread_stack( page ); + else ret = grow_thread_stack( page, &stack_info ); } else if (err & EXCEPTION_WRITE_FAULT) { @@ -3205,19 +3243,16 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack ) void *virtual_setup_exception( void *stack_ptr, size_t size, EXCEPTION_RECORD *rec ) { char *stack = stack_ptr; + struct thread_stack_info stack_info; - if (is_inside_signal_stack( stack )) - { - ERR( "nested exception on signal stack in thread %04x addr %p stack %p (%p-%p-%p)\n", - GetCurrentThreadId(), rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack, - NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); - abort_thread(1); - } - - if (stack - size > stack || /* check for overflow in subtraction */ - stack <= (char *)NtCurrentTeb()->DeallocationStack || - stack > (char *)NtCurrentTeb()->Tib.StackBase) + if (!is_inside_thread_stack( stack, &stack_info )) { + if (is_inside_signal_stack( stack )) + { + ERR( "nested exception on signal stack in thread %04x addr %p stack %p\n", + GetCurrentThreadId(), rec->ExceptionAddress, stack ); + abort_thread(1); + } WARN( "exception outside of stack limits in thread %04x addr %p stack %p (%p-%p-%p)\n", GetCurrentThreadId(), rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack, NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); @@ -3226,19 +3261,20 @@ void *virtual_setup_exception( void *stack_ptr, size_t size, EXCEPTION_RECORD *r stack -= size; - if (stack < (char *)NtCurrentTeb()->DeallocationStack + 4096) + if (stack < stack_info.start + 4096) { /* stack overflow on last page, unrecoverable */ - UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - stack; + UINT diff = stack_info.start + 4096 - stack; ERR( "stack overflow %u bytes in thread %04x addr %p stack %p (%p-%p-%p)\n", - diff, GetCurrentThreadId(), rec->ExceptionAddress, stack, NtCurrentTeb()->DeallocationStack, - NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); + diff, GetCurrentThreadId(), rec->ExceptionAddress, stack, stack_info.start, + stack_info.limit, stack_info.end ); abort_thread(1); } - else if (stack < (char *)NtCurrentTeb()->Tib.StackLimit) + else if (stack < stack_info.limit) { mutex_lock( &virtual_mutex ); /* no need for signal masking inside signal handler */ - if ((get_page_vprot( stack ) & VPROT_GUARD) && grow_thread_stack( ROUND_ADDR( stack, page_mask ))) + if ((get_page_vprot( stack ) & VPROT_GUARD) && + grow_thread_stack( ROUND_ADDR( stack, page_mask ), &stack_info )) { rec->ExceptionCode = STATUS_STACK_OVERFLOW; rec->NumberParameters = 0; -- 2.11.4.GIT