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,
|
extern NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, SIZE_T reserve_size,
|
||||||
SIZE_T commit_size, SIZE_T *pthread_size ) DECLSPEC_HIDDEN;
|
SIZE_T commit_size, SIZE_T *pthread_size ) DECLSPEC_HIDDEN;
|
||||||
extern void virtual_clear_thread_stack( void *stack_end ) 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 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 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;
|
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;
|
ucontext_t *context = ucontext;
|
||||||
|
|
||||||
/* check for page fault inside the thread stack */
|
/* check for page fault inside the thread stack */
|
||||||
if (get_trap_code(signal, context) == TRAP_ARM_PAGEFLT &&
|
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 ))
|
|
||||||
{
|
{
|
||||||
/* check if this was the last guard page */
|
switch (virtual_handle_stack_fault( info->si_addr ))
|
||||||
if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
|
|
||||||
{
|
{
|
||||||
|
case 1: /* handled */
|
||||||
|
return;
|
||||||
|
case -1: /* overflow */
|
||||||
rec = setup_exception( context, raise_segv_exception );
|
rec = setup_exception( context, raise_segv_exception );
|
||||||
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rec = setup_exception( context, raise_segv_exception );
|
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;
|
ucontext_t *context = ucontext;
|
||||||
|
|
||||||
/* check for page fault inside the thread stack */
|
/* check for page fault inside the thread stack */
|
||||||
if (signal == SIGSEGV &&
|
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 ))
|
|
||||||
{
|
{
|
||||||
/* check if this was the last guard page */
|
switch (virtual_handle_stack_fault( info->si_addr ))
|
||||||
if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
|
|
||||||
{
|
{
|
||||||
|
case 1: /* handled */
|
||||||
|
return;
|
||||||
|
case -1: /* overflow */
|
||||||
rec = setup_exception( context, raise_segv_exception );
|
rec = setup_exception( context, raise_segv_exception );
|
||||||
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rec = setup_exception( context, raise_segv_exception );
|
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)
|
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
|
||||||
{
|
{
|
||||||
/* stack access below stack limit, may be recoverable */
|
/* stack access below stack limit, may be recoverable */
|
||||||
if (virtual_handle_stack_fault( stack - 1 )) exception_code = EXCEPTION_STACK_OVERFLOW;
|
switch (virtual_handle_stack_fault( stack - 1 ))
|
||||||
else
|
{
|
||||||
|
case 0: /* not handled */
|
||||||
{
|
{
|
||||||
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
|
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",
|
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 );
|
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||||
abort_thread(1);
|
abort_thread(1);
|
||||||
}
|
}
|
||||||
|
case -1: /* overflow */
|
||||||
|
exception_code = EXCEPTION_STACK_OVERFLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stack--; /* push the stack_layout structure */
|
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 */
|
/* check for page fault inside the thread stack */
|
||||||
if (get_trap_code(context) == TRAP_x86_PAGEFLT &&
|
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 ))
|
|
||||||
{
|
{
|
||||||
/* check if this was the last guard page */
|
switch (virtual_handle_stack_fault( siginfo->si_addr ))
|
||||||
if ((char *)siginfo->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
|
|
||||||
{
|
{
|
||||||
|
case 1: /* handled */
|
||||||
|
return;
|
||||||
|
case -1: /* overflow */
|
||||||
rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
|
rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
|
||||||
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
|
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)
|
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
|
||||||
{
|
{
|
||||||
/* stack access below stack limit, may be recoverable */
|
/* stack access below stack limit, may be recoverable */
|
||||||
if (virtual_handle_stack_fault( stack - 1 )) exception_code = EXCEPTION_STACK_OVERFLOW;
|
switch (virtual_handle_stack_fault( stack - 1 ))
|
||||||
else
|
{
|
||||||
|
case 0: /* not handled */
|
||||||
{
|
{
|
||||||
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1);
|
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",
|
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 );
|
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||||
abort_thread(1);
|
abort_thread(1);
|
||||||
}
|
}
|
||||||
|
case -1: /* overflow */
|
||||||
|
exception_code = EXCEPTION_STACK_OVERFLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stack--; /* push the stack_layout structure */
|
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;
|
ucontext_t *ucontext = sigcontext;
|
||||||
|
|
||||||
/* check for page fault inside the thread stack */
|
/* check for page fault inside the thread stack */
|
||||||
if (TRAP_sig(ucontext) == TRAP_x86_PAGEFLT &&
|
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 ))
|
|
||||||
{
|
{
|
||||||
/* check if this was the last guard page */
|
switch (virtual_handle_stack_fault( siginfo->si_addr ))
|
||||||
if ((char *)siginfo->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
|
|
||||||
{
|
{
|
||||||
|
case 1: /* handled */
|
||||||
|
return;
|
||||||
|
case -1: /* overflow */
|
||||||
rec = setup_exception( sigcontext, raise_segv_exception );
|
rec = setup_exception( sigcontext, raise_segv_exception );
|
||||||
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rec = setup_exception( sigcontext, raise_segv_exception );
|
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
|
* virtual_handle_stack_fault
|
||||||
*
|
*
|
||||||
* Handle an access fault inside the current thread stack.
|
* 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.
|
* 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 */
|
RtlEnterCriticalSection( &csVirtual ); /* no need for signal masking inside signal handler */
|
||||||
if (get_page_vprot( addr ) & VPROT_GUARD)
|
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 );
|
char *page = ROUND_ADDR( addr, page_mask );
|
||||||
set_page_vprot_bits( page, page_size, 0, VPROT_GUARD );
|
set_page_vprot_bits( page, page_size, 0, VPROT_GUARD );
|
||||||
mprotect_range( page, page_size, 0, 0 );
|
mprotect_range( page, page_size, 0, 0 );
|
||||||
NtCurrentTeb()->Tib.StackLimit = page;
|
if (page >= (char *)NtCurrentTeb()->DeallocationStack + page_size + guaranteed)
|
||||||
if (page >= (char *)NtCurrentTeb()->DeallocationStack + 2*page_size)
|
|
||||||
{
|
{
|
||||||
page -= page_size;
|
set_page_vprot_bits( page - page_size, page_size, VPROT_COMMITTED | VPROT_GUARD, 0 );
|
||||||
set_page_vprot_bits( page, page_size, VPROT_COMMITTED | VPROT_GUARD, 0 );
|
mprotect_range( page - page_size, page_size, 0, 0 );
|
||||||
mprotect_range( page, 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 );
|
RtlLeaveCriticalSection( &csVirtual );
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue