Module: wine Branch: master Commit: cc33f6c8a5df21589efa7ce26f8b13715e698008 URL: http://source.winehq.org/git/wine.git/?a=commit;h=cc33f6c8a5df21589efa7ce26f...
Author: Alexandre Julliard julliard@winehq.org Date: Tue Apr 1 17:40:37 2008 +0200
ntdll: Add a guard page at the bottom of the stack and raise a stack overflow exception when hit.
---
dlls/ntdll/signal_i386.c | 46 ++++++++++++++++++++++++++++++++++++---------- dlls/ntdll/virtual.c | 4 +++- 2 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 7920d0a..d9c6aba 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -1026,6 +1026,7 @@ static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *s DWORD ebp; DWORD eip; } *stack = stack_ptr; + DWORD exception_code = 0;
/* stack sanity checks */
@@ -1040,22 +1041,37 @@ static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *s }
if (stack - 1 > stack || /* check for overflow in subtraction */ - (char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit || + (char *)stack <= (char *)NtCurrentTeb()->DeallocationStack || (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase) { - UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)stack; - if (diff < 4096) + WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n", + GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), + (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit, + NtCurrentTeb()->Tib.StackBase ); + } + else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096) + { + /* stack overflow on last page, unrecoverable */ + UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1); + WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n", + diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), + (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, + NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); + server_abort_thread(1); + } + 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 { - WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p\n", + 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", diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), - (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit, - NtCurrentTeb()->Tib.StackBase ); + (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, + NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); server_abort_thread(1); } - else WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n", - GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), - (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit, - NtCurrentTeb()->Tib.StackBase ); }
stack--; /* push the stack_layout structure */ @@ -1069,6 +1085,7 @@ static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *s stack->context_ptr = &stack->context;
stack->rec.ExceptionRecord = NULL; + stack->rec.ExceptionCode = exception_code; stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE; stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext); stack->rec.NumberParameters = 0; @@ -1280,9 +1297,18 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) (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 */ + if ((char *)siginfo->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096) + { + rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception ); + rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW; + } return; + }
rec = setup_exception_record( context, stack, fs, gs, raise_segv_exception ); + if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
switch(get_trap_code(context)) { diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 5e4327b..a5b299d 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -1303,11 +1303,13 @@ NTSTATUS virtual_alloc_thread_stack( void *base, SIZE_T size )
/* setup no access guard page */ VIRTUAL_SetProt( view, view->base, page_size, VPROT_COMMITTED ); + VIRTUAL_SetProt( view, (char *)view->base + page_size, page_size, + VPROT_READ | VPROT_WRITE | VPROT_COMMITTED | VPROT_GUARD );
/* note: limit is lower than base since the stack grows down */ NtCurrentTeb()->DeallocationStack = view->base; NtCurrentTeb()->Tib.StackBase = (char *)view->base + view->size; - NtCurrentTeb()->Tib.StackLimit = (char *)view->base + page_size; + NtCurrentTeb()->Tib.StackLimit = (char *)view->base + 2 * page_size;
done: server_leave_uninterrupted_section( &csVirtual, &sigset );