Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199/* * PROJECT: ReactOS api tests * LICENSE: GPL - See COPYING in the top level directory * PURPOSE: Test for stack overflow * PROGRAMMER: Jérôme Gardou */
#include "precomp.h"
#include <pseh/pseh2.h>
#ifdef _MSC_VER#pragma warning(disable : 4717) // disable warning about recursive function#endif
static int iteration = 0;static PVOID StackAllocationBase;static PVOID LastStackAllocation;static ULONG StackSize;
staticvoidinfinite_recursive(void){ MEMORY_BASIC_INFORMATION MemoryBasicInfo; NTSTATUS Status; char Buffer[0x500];
sprintf(Buffer, "Iteration %d.\n", iteration++);
Status = NtQueryVirtualMemory( NtCurrentProcess(), &Buffer[0], MemoryBasicInformation, &MemoryBasicInfo, sizeof(MemoryBasicInfo), NULL); ok_ntstatus(Status, STATUS_SUCCESS); /* This never changes */ ok_ptr(MemoryBasicInfo.AllocationBase, StackAllocationBase); /* Stack is committed one page at a time */ ok_ptr(MemoryBasicInfo.BaseAddress, (PVOID)PAGE_ROUND_DOWN(&Buffer[0])); /* This is the protection of the memory when it was reserved. */ ok_long(MemoryBasicInfo.AllocationProtect, PAGE_READWRITE); /* Windows commits the whole used stack at once, +2 pages. */#if 0 ok_long(MemoryBasicInfo.RegionSize, ((ULONG_PTR)StackAllocationBase + StackSize + 2* PAGE_SIZE) - PAGE_ROUND_DOWN(&Buffer[0]));#endif /* This is the state of the queried address */ ok_long(MemoryBasicInfo.State, MEM_COMMIT); /* This is the protection of the queried address */ ok_long(MemoryBasicInfo.Protect, PAGE_READWRITE); /* Of course this is private memory. */ ok_long(MemoryBasicInfo.Type, MEM_PRIVATE);
LastStackAllocation = &Buffer[-0x500];
infinite_recursive();}
START_TEST(StackOverflow){ NTSTATUS Status; MEMORY_BASIC_INFORMATION MemoryBasicInfo;
/* Get the base of the stack */ Status = NtQueryVirtualMemory( NtCurrentProcess(), &Status, MemoryBasicInformation, &MemoryBasicInfo, sizeof(MemoryBasicInfo), NULL); ok_ntstatus(Status, STATUS_SUCCESS); StackAllocationBase = MemoryBasicInfo.AllocationBase; trace("Stack allocation base is %p.\n", StackAllocationBase); StackSize = MemoryBasicInfo.RegionSize;
/* Check TEB attributes */ ok_ptr(NtCurrentTeb()->DeallocationStack, StackAllocationBase); ok_ptr(NtCurrentTeb()->NtTib.StackBase, (PVOID)((ULONG_PTR)MemoryBasicInfo.BaseAddress + MemoryBasicInfo.RegionSize));#ifdef _WIN64 ok_ptr(NtCurrentTeb()->NtTib.StackLimit, (PVOID)((ULONG_PTR)MemoryBasicInfo.BaseAddress - 2 * PAGE_SIZE));#else ok_ptr(NtCurrentTeb()->NtTib.StackLimit, (PVOID)((ULONG_PTR)MemoryBasicInfo.BaseAddress - PAGE_SIZE));#endif trace("Guaranteed stack size is %lu.\n", NtCurrentTeb()->GuaranteedStackBytes);
/* Get its size */ Status = NtQueryVirtualMemory( NtCurrentProcess(), StackAllocationBase, MemoryBasicInformation, &MemoryBasicInfo, sizeof(MemoryBasicInfo), NULL); ok_ntstatus(Status, STATUS_SUCCESS);
/* This is the complete stack size */ StackSize += MemoryBasicInfo.RegionSize; trace("Stack size is 0x%lx.\n", StackSize);
trace("Stack limit %p, stack base %p.\n", NtCurrentTeb()->NtTib.StackLimit, NtCurrentTeb()->NtTib.StackBase);
/* Take a look at what is beyond the stack limit */ Status = NtQueryVirtualMemory( NtCurrentProcess(), NtCurrentTeb()->NtTib.StackLimit, MemoryBasicInformation, &MemoryBasicInfo, sizeof(MemoryBasicInfo), NULL); ok_ntstatus(Status, STATUS_SUCCESS);
ok_ptr(MemoryBasicInfo.BaseAddress, NtCurrentTeb()->NtTib.StackLimit); ok_ptr(MemoryBasicInfo.AllocationBase, StackAllocationBase); ok_long(MemoryBasicInfo.AllocationProtect, PAGE_READWRITE);#ifdef _WIN64 ok_long(MemoryBasicInfo.RegionSize, 3 * PAGE_SIZE);#else ok_long(MemoryBasicInfo.RegionSize, 2 * PAGE_SIZE);#endif ok_long(MemoryBasicInfo.State, MEM_COMMIT); ok_long(MemoryBasicInfo.Protect, PAGE_READWRITE); ok_long(MemoryBasicInfo.Type, MEM_PRIVATE);
/* Accessing below stack limit is OK, as long as we don't starve the reserved space. */ _SEH2_TRY { volatile CHAR* Pointer = (PVOID)((ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit - PAGE_SIZE / 2); CHAR Value = *Pointer; (void)Value; Status = STATUS_SUCCESS; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; ok_ntstatus(Status, STATUS_SUCCESS);
_SEH2_TRY { infinite_recursive(); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { trace("Exception after %d iteration.\n", iteration); Status = _SEH2_GetExceptionCode(); } _SEH2_END;
ok_ntstatus(Status, STATUS_STACK_OVERFLOW);
/* Windows lets 2 pages between the reserved memory and the smallest possible stack address */ ok((ULONG_PTR)LastStackAllocation > (ULONG_PTR)StackAllocationBase, "\n");#ifdef _WIN64 ok_long(PAGE_ROUND_DOWN(LastStackAllocation), (ULONG_PTR)StackAllocationBase + 4 * PAGE_SIZE);#else ok_long(PAGE_ROUND_DOWN(LastStackAllocation), (ULONG_PTR)StackAllocationBase + 3 * PAGE_SIZE);#endif
/* And in fact, this is the true condition of the stack overflow */ ok_ptr(NtCurrentTeb()->NtTib.StackLimit, (PVOID)((ULONG_PTR)StackAllocationBase + PAGE_SIZE));
trace("Stack limit %p, stack base %p.\n", NtCurrentTeb()->NtTib.StackLimit, NtCurrentTeb()->NtTib.StackBase);
/* Of course, accessing above the stack limit is OK. */ _SEH2_TRY { volatile CHAR* Pointer = (PVOID)((ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit + PAGE_SIZE / 2); CHAR Value = *Pointer; (void)Value; Status = STATUS_SUCCESS; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; ok_ntstatus(Status, STATUS_SUCCESS);
/* But once stack is starved, it's starved. */ _SEH2_TRY { volatile CHAR* Pointer = (PVOID)((ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit - PAGE_SIZE / 2); CHAR Value = *Pointer; (void)Value; Status = STATUS_SUCCESS; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { trace("Exception after %d iteration.\n", iteration); Status = _SEH2_GetExceptionCode(); } _SEH2_END; ok_ntstatus(Status, STATUS_ACCESS_VIOLATION);}