ntdll: Add support for handling page faults caused by guard pages on the thread stack.
This commit is contained in:
parent
600694546f
commit
061bfac076
|
@ -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 */
|
||||
|
||||
|
@ -1096,6 +1091,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
|
||||
*
|
||||
|
@ -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
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue