Commit 061bfac0 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Add support for handling page faults caused by guard pages on the thread stack.

parent 60069454
......@@ -134,6 +134,7 @@ extern unsigned int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES]
/* virtual memory */
extern NTSTATUS virtual_alloc_thread_stack( void *base, SIZE_T stack_size );
extern BOOL virtual_handle_stack_fault( void *addr );
extern NTSTATUS VIRTUAL_HandleFault(LPCVOID addr);
extern void VIRTUAL_SetForceExec( BOOL enable );
extern void VIRTUAL_UseLargeAddressSpace(void);
......
......@@ -1009,13 +1009,12 @@ static BOOL check_atl_thunk( EXCEPTION_RECORD *rec, CONTEXT *context )
/***********************************************************************
* setup_exception
* setup_exception_record
*
* Setup a proper stack frame for the raise function, and modify the
* sigcontext so that the return from the signal handler will call
* the raise function.
* Setup the exception record and context on the thread stack.
*/
static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func )
static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *stack_ptr,
WORD fs, WORD gs, raise_func func )
{
struct stack_layout
{
......@@ -1026,11 +1025,7 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun
EXCEPTION_RECORD rec;
DWORD ebp;
DWORD eip;
} *stack;
WORD fs, gs;
stack = init_handler( sigcontext, &fs, &gs );
} *stack = stack_ptr;
/* stack sanity checks */
......@@ -1097,6 +1092,22 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun
/***********************************************************************
* setup_exception
*
* Setup a proper stack frame for the raise function, and modify the
* sigcontext so that the return from the signal handler will call
* the raise function.
*/
static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func )
{
WORD fs, gs;
void *stack = init_handler( sigcontext, &fs, &gs );
return setup_exception_record( sigcontext, stack, fs, gs, func );
}
/***********************************************************************
* get_exception_context
*
* Get a pointer to the context built by setup_exception.
......@@ -1259,8 +1270,19 @@ static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/
static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
WORD fs, gs;
EXCEPTION_RECORD *rec;
SIGCONTEXT *context = sigcontext;
EXCEPTION_RECORD *rec = setup_exception( context, raise_segv_exception );
void *stack = init_handler( sigcontext, &fs, &gs );
/* 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 ))
return;
rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception );
switch(get_trap_code(context))
{
......
......@@ -571,6 +571,19 @@ static BOOL VIRTUAL_SetProt( FILE_VIEW *view, /* [in] Pointer to view */
TRACE("%p-%p %s\n",
base, (char *)base + size - 1, VIRTUAL_GetProtStr( vprot ) );
/* if setting stack guard pages, store the permissions first, as the guard may be
* triggered at any point after mprotect and change the permissions again */
if ((vprot & VPROT_GUARD) &&
((char *)base >= (char *)NtCurrentTeb()->DeallocationStack) &&
((char *)base < (char *)NtCurrentTeb()->Tib.StackBase))
{
memset( view->prot + (((char *)base - (char *)view->base) >> page_shift),
vprot, size >> page_shift );
mprotect( base, size, unix_prot );
VIRTUAL_DEBUG_DUMP_VIEW( view );
return TRUE;
}
if (force_exec_prot && (unix_prot & PROT_READ) && !(unix_prot & PROT_EXEC))
{
TRACE( "forcing exec permission on %p-%p\n", base, (char *)base + size - 1 );
......@@ -1327,6 +1340,36 @@ NTSTATUS VIRTUAL_HandleFault( LPCVOID addr )
}
/***********************************************************************
* virtual_handle_stack_fault
*
* Handle an access fault inside the current thread stack.
* Called from inside a signal handler.
*/
BOOL virtual_handle_stack_fault( void *addr )
{
FILE_VIEW *view;
BOOL ret = FALSE;
RtlEnterCriticalSection( &csVirtual ); /* no need for signal masking inside signal handler */
if ((view = VIRTUAL_FindView( addr )))
{
void *page = ROUND_ADDR( addr, page_mask );
BYTE vprot = view->prot[((const char *)page - (const char *)view->base) >> page_shift];
if (vprot & VPROT_GUARD)
{
VIRTUAL_SetProt( view, page, page_size, vprot & ~VPROT_GUARD );
if ((char *)page + page_size == NtCurrentTeb()->Tib.StackLimit)
NtCurrentTeb()->Tib.StackLimit = page;
ret = TRUE;
}
}
RtlLeaveCriticalSection( &csVirtual );
return ret;
}
/***********************************************************************
* VIRTUAL_SetForceExec
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment