ntdll: Take stack guarantee into account when handling stack overflows.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
505be3a0a2
commit
87d9fef2ae
|
@ -177,7 +177,7 @@ extern NTSTATUS virtual_create_builtin_view( void *base ) DECLSPEC_HIDDEN;
|
|||
extern NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, SIZE_T reserve_size,
|
||||
SIZE_T commit_size, SIZE_T *pthread_size ) DECLSPEC_HIDDEN;
|
||||
extern void virtual_clear_thread_stack( void *stack_end ) DECLSPEC_HIDDEN;
|
||||
extern BOOL virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN;
|
||||
extern int virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN;
|
||||
extern BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) DECLSPEC_HIDDEN;
|
||||
extern unsigned int virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -721,18 +721,17 @@ static void segv_handler( int signal, siginfo_t *info, void *ucontext )
|
|||
ucontext_t *context = ucontext;
|
||||
|
||||
/* check for page fault inside the thread stack */
|
||||
if (get_trap_code(signal, context) == TRAP_ARM_PAGEFLT &&
|
||||
(char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
|
||||
(char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
|
||||
virtual_handle_stack_fault( info->si_addr ))
|
||||
if (get_trap_code(signal, context) == TRAP_ARM_PAGEFLT)
|
||||
{
|
||||
/* check if this was the last guard page */
|
||||
if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
|
||||
switch (virtual_handle_stack_fault( info->si_addr ))
|
||||
{
|
||||
case 1: /* handled */
|
||||
return;
|
||||
case -1: /* overflow */
|
||||
rec = setup_exception( context, raise_segv_exception );
|
||||
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
rec = setup_exception( context, raise_segv_exception );
|
||||
|
|
|
@ -669,18 +669,17 @@ static void segv_handler( int signal, siginfo_t *info, void *ucontext )
|
|||
ucontext_t *context = ucontext;
|
||||
|
||||
/* check for page fault inside the thread stack */
|
||||
if (signal == SIGSEGV &&
|
||||
(char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
|
||||
(char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
|
||||
virtual_handle_stack_fault( info->si_addr ))
|
||||
if (signal == SIGSEGV)
|
||||
{
|
||||
/* check if this was the last guard page */
|
||||
if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
|
||||
switch (virtual_handle_stack_fault( info->si_addr ))
|
||||
{
|
||||
case 1: /* handled */
|
||||
return;
|
||||
case -1: /* overflow */
|
||||
rec = setup_exception( context, raise_segv_exception );
|
||||
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
rec = setup_exception( context, raise_segv_exception );
|
||||
|
|
|
@ -1822,8 +1822,9 @@ static EXCEPTION_RECORD *setup_exception_record( ucontext_t *sigcontext, void *s
|
|||
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
|
||||
{
|
||||
/* stack access below stack limit, may be recoverable */
|
||||
if (virtual_handle_stack_fault( stack - 1 )) exception_code = EXCEPTION_STACK_OVERFLOW;
|
||||
else
|
||||
switch (virtual_handle_stack_fault( stack - 1 ))
|
||||
{
|
||||
case 0: /* not handled */
|
||||
{
|
||||
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
|
||||
WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n",
|
||||
|
@ -1832,6 +1833,10 @@ static EXCEPTION_RECORD *setup_exception_record( ucontext_t *sigcontext, void *s
|
|||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
case -1: /* overflow */
|
||||
exception_code = EXCEPTION_STACK_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stack--; /* push the stack_layout structure */
|
||||
|
@ -2051,18 +2056,17 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
|||
}
|
||||
|
||||
/* check for page fault inside the thread stack */
|
||||
if (get_trap_code(context) == TRAP_x86_PAGEFLT &&
|
||||
(char *)siginfo->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
|
||||
(char *)siginfo->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
|
||||
virtual_handle_stack_fault( siginfo->si_addr ))
|
||||
if (get_trap_code(context) == TRAP_x86_PAGEFLT)
|
||||
{
|
||||
/* check if this was the last guard page */
|
||||
if ((char *)siginfo->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
|
||||
switch (virtual_handle_stack_fault( siginfo->si_addr ))
|
||||
{
|
||||
case 1: /* handled */
|
||||
return;
|
||||
case -1: /* overflow */
|
||||
rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
|
||||
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
|
||||
|
|
|
@ -2413,8 +2413,9 @@ static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func fun
|
|||
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
|
||||
{
|
||||
/* stack access below stack limit, may be recoverable */
|
||||
if (virtual_handle_stack_fault( stack - 1 )) exception_code = EXCEPTION_STACK_OVERFLOW;
|
||||
else
|
||||
switch (virtual_handle_stack_fault( stack - 1 ))
|
||||
{
|
||||
case 0: /* not handled */
|
||||
{
|
||||
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
|
||||
ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n",
|
||||
|
@ -2423,6 +2424,10 @@ static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func fun
|
|||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||
abort_thread(1);
|
||||
}
|
||||
case -1: /* overflow */
|
||||
exception_code = EXCEPTION_STACK_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stack--; /* push the stack_layout structure */
|
||||
|
@ -2940,18 +2945,17 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
|||
ucontext_t *ucontext = sigcontext;
|
||||
|
||||
/* check for page fault inside the thread stack */
|
||||
if (TRAP_sig(ucontext) == TRAP_x86_PAGEFLT &&
|
||||
(char *)siginfo->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
|
||||
(char *)siginfo->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
|
||||
virtual_handle_stack_fault( siginfo->si_addr ))
|
||||
if (TRAP_sig(ucontext) == TRAP_x86_PAGEFLT)
|
||||
{
|
||||
/* check if this was the last guard page */
|
||||
if ((char *)siginfo->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
|
||||
switch (virtual_handle_stack_fault( siginfo->si_addr ))
|
||||
{
|
||||
case 1: /* handled */
|
||||
return;
|
||||
case -1: /* overflow */
|
||||
rec = setup_exception( sigcontext, raise_segv_exception );
|
||||
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
rec = setup_exception( sigcontext, raise_segv_exception );
|
||||
|
|
|
@ -2269,26 +2269,37 @@ BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size )
|
|||
* virtual_handle_stack_fault
|
||||
*
|
||||
* Handle an access fault inside the current thread stack.
|
||||
* Return 1 if safely handled, -1 if handled into the overflow space.
|
||||
* Called from inside a signal handler.
|
||||
*/
|
||||
BOOL virtual_handle_stack_fault( void *addr )
|
||||
int virtual_handle_stack_fault( void *addr )
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
int ret = 0;
|
||||
|
||||
if ((char *)addr < (char *)NtCurrentTeb()->DeallocationStack) return 0;
|
||||
if ((char *)addr >= (char *)NtCurrentTeb()->Tib.StackBase) return 0;
|
||||
|
||||
RtlEnterCriticalSection( &csVirtual ); /* no need for signal masking inside signal handler */
|
||||
if (get_page_vprot( addr ) & VPROT_GUARD)
|
||||
{
|
||||
size_t guaranteed = max( NtCurrentTeb()->GuaranteedStackBytes, page_size * (is_win64 ? 2 : 1) );
|
||||
char *page = ROUND_ADDR( addr, page_mask );
|
||||
set_page_vprot_bits( page, page_size, 0, VPROT_GUARD );
|
||||
mprotect_range( page, page_size, 0, 0 );
|
||||
NtCurrentTeb()->Tib.StackLimit = page;
|
||||
if (page >= (char *)NtCurrentTeb()->DeallocationStack + 2*page_size)
|
||||
if (page >= (char *)NtCurrentTeb()->DeallocationStack + page_size + guaranteed)
|
||||
{
|
||||
page -= page_size;
|
||||
set_page_vprot_bits( page, page_size, VPROT_COMMITTED | VPROT_GUARD, 0 );
|
||||
mprotect_range( page, page_size, 0, 0 );
|
||||
set_page_vprot_bits( page - page_size, page_size, VPROT_COMMITTED | VPROT_GUARD, 0 );
|
||||
mprotect_range( page - page_size, page_size, 0, 0 );
|
||||
ret = 1;
|
||||
}
|
||||
ret = TRUE;
|
||||
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 );
|
||||
ret = -1;
|
||||
}
|
||||
NtCurrentTeb()->Tib.StackLimit = page;
|
||||
}
|
||||
RtlLeaveCriticalSection( &csVirtual );
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue