From 2b17fa159dd69215a14365bc308aec343fa54938 Mon Sep 17 00:00:00 2001 From: Thomas Faber Date: Sun, 11 Sep 2011 11:22:00 +0000 Subject: [PATCH] [KMTESTS] - Add support for guarded allocations, that can be used to detect buffer overruns - Add GuardedMemory example test - Add MmSection test with some basic parameter checks for MmCreateSection - Fix some x64 build problems - Update readme svn path=/trunk/; revision=53687 --- rostests/kmtests/CMakeLists.txt | 2 + rostests/kmtests/example/GuardedMemory.c | 63 ++++++++++++++ rostests/kmtests/include/kmt_test.h | 40 +++++++++ rostests/kmtests/kmtest.rbuild | 1 + rostests/kmtests/kmtest_drv.rbuild | 4 + rostests/kmtests/kmtest_drv/testlist.c | 2 + rostests/kmtests/ntos_ex/ExDoubleList.c | 2 + rostests/kmtests/ntos_ex/ExSequencedList.c | 5 +- rostests/kmtests/ntos_ex/ExSingleList.c | 2 + rostests/kmtests/ntos_ke/KeIrql.c | 4 + rostests/kmtests/ntos_mm/MmSection.c | 98 ++++++++++++++++++++++ rostests/kmtests/readme.txt | 2 +- 12 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 rostests/kmtests/example/GuardedMemory.c create mode 100644 rostests/kmtests/ntos_mm/MmSection.c diff --git a/rostests/kmtests/CMakeLists.txt b/rostests/kmtests/CMakeLists.txt index b5056976694..310d3425b60 100644 --- a/rostests/kmtests/CMakeLists.txt +++ b/rostests/kmtests/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(example) add_subdirectory(ntos_io) list(APPEND COMMON_SOURCE + example/GuardedMemory.c rtl/RtlAvlTree.c rtl/RtlMemory.c rtl/RtlSplayTree.c) @@ -42,6 +43,7 @@ list(APPEND KMTEST_DRV_SOURCE ntos_ke/KeIrql.c ntos_ke/KeProcessor.c ntos_ke/KeSpinLock.c + ntos_mm/MmSection.c ntos_ob/ObReference.c ntos_ob/ObType.c ${COMMON_SOURCE} diff --git a/rostests/kmtests/example/GuardedMemory.c b/rostests/kmtests/example/GuardedMemory.c new file mode 100644 index 00000000000..766b5686f7d --- /dev/null +++ b/rostests/kmtests/example/GuardedMemory.c @@ -0,0 +1,63 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Kernel-Mode Test Suite Guarded Memory example test + * PROGRAMMER: Thomas Faber + */ + +#include + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wnonnull" +#endif /* defined __GNUC__ */ + +START_TEST(GuardedMemory) +{ + NTSTATUS Status; + SIZE_T Size = 123; + PCHAR *Buffer; + + /* access some invalid memory to test SEH */ + Status = STATUS_SUCCESS; + _SEH2_TRY + { + RtlFillMemory(NULL, 1, 0); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } _SEH2_END; + ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); + + /* get guarded mem */ + Buffer = KmtAllocateGuarded(Size); + + if (skip(Buffer != NULL, "Failed to allocate guarded memory\n")) + return; + + /* access to guarded mem should be fine */ + Status = STATUS_SUCCESS; + _SEH2_TRY + { + RtlFillMemory(Buffer, Size, 0); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } _SEH2_END; + ok_eq_hex(Status, STATUS_SUCCESS); + + /* access one byte behind guarded mem must cause an access violation! */ + Status = STATUS_SUCCESS; + _SEH2_TRY + { + RtlFillMemory(Buffer + Size, 1, 0); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } _SEH2_END; + ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); + + KmtFreeGuarded(Buffer); +} diff --git a/rostests/kmtests/include/kmt_test.h b/rostests/kmtests/include/kmt_test.h index 73ea9592f85..e187e05efe8 100644 --- a/rostests/kmtests/include/kmt_test.h +++ b/rostests/kmtests/include/kmt_test.h @@ -129,6 +129,8 @@ VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments) VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 2, 3); BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0); BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4); +PVOID KmtAllocateGuarded(SIZE_T SizeRequested); +VOID KmtFreeGuarded(PVOID Pointer); #ifdef KMT_KERNEL_MODE #define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql) @@ -411,6 +413,44 @@ BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) return Ret; } +PVOID KmtAllocateGuarded(SIZE_T SizeRequested) +{ + NTSTATUS Status; + SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE); + PVOID VirtualMemory = NULL; + PCHAR StartOfBuffer; + + Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS); + + if (!NT_SUCCESS(Status)) + return NULL; + + Size -= PAGE_SIZE; + Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + Size = 0; + Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE); + ok_eq_hex(Status, STATUS_SUCCESS); + return NULL; + } + + StartOfBuffer = VirtualMemory; + StartOfBuffer += Size - SizeRequested; + + return StartOfBuffer; +} + +VOID KmtFreeGuarded(PVOID Pointer) +{ + NTSTATUS Status; + PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer); + SIZE_T Size = 0; + + Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE); + ok_eq_hex(Status, STATUS_SUCCESS); +} + #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */ #endif /* !defined _KMTEST_TEST_H_ */ diff --git a/rostests/kmtests/kmtest.rbuild b/rostests/kmtests/kmtest.rbuild index 67c3f0b5101..62849808d59 100644 --- a/rostests/kmtests/kmtest.rbuild +++ b/rostests/kmtests/kmtest.rbuild @@ -12,6 +12,7 @@ Example_user.c + GuardedMemory.c IoDeviceObject_user.c diff --git a/rostests/kmtests/kmtest_drv.rbuild b/rostests/kmtests/kmtest_drv.rbuild index 3adc67b3cad..d9789a23c64 100644 --- a/rostests/kmtests/kmtest_drv.rbuild +++ b/rostests/kmtests/kmtest_drv.rbuild @@ -12,6 +12,7 @@ Example.c + GuardedMemory.c KernelType.c @@ -43,6 +44,9 @@ KeProcessor.c KeSpinLock.c + + MmSection.c + ObReference.c ObType.c diff --git a/rostests/kmtests/kmtest_drv/testlist.c b/rostests/kmtests/kmtest_drv/testlist.c index b17ad797585..4fffe48ec55 100644 --- a/rostests/kmtests/kmtest_drv/testlist.c +++ b/rostests/kmtests/kmtest_drv/testlist.c @@ -30,6 +30,7 @@ KMT_TESTFUNC Test_KeGuardedMutex; KMT_TESTFUNC Test_KeIrql; KMT_TESTFUNC Test_KeProcessor; KMT_TESTFUNC Test_KernelType; +KMT_TESTFUNC Test_MmSection; KMT_TESTFUNC Test_ObReference; KMT_TESTFUNC Test_ObType; KMT_TESTFUNC Test_ObTypeClean; @@ -63,6 +64,7 @@ const KMT_TEST TestList[] = { "KeIrql", Test_KeIrql }, { "-KeProcessor", Test_KeProcessor }, { "-KernelType", Test_KernelType }, + { "MmSection", Test_MmSection }, { "ObReference", Test_ObReference }, { "ObType", Test_ObType }, { "-ObTypeClean", Test_ObTypeClean }, diff --git a/rostests/kmtests/ntos_ex/ExDoubleList.c b/rostests/kmtests/ntos_ex/ExDoubleList.c index d27993f7de6..d2da26ca1cf 100644 --- a/rostests/kmtests/ntos_ex/ExDoubleList.c +++ b/rostests/kmtests/ntos_ex/ExDoubleList.c @@ -6,9 +6,11 @@ */ struct _LIST_ENTRY; +#ifdef _X86_ struct _LIST_ENTRY *__stdcall ExInterlockedInsertHeadList(struct _LIST_ENTRY *, struct _LIST_ENTRY *, unsigned long *); struct _LIST_ENTRY *__stdcall ExInterlockedInsertTailList(struct _LIST_ENTRY *, struct _LIST_ENTRY *, unsigned long *); struct _LIST_ENTRY *__stdcall ExInterlockedRemoveHeadList(struct _LIST_ENTRY *, unsigned long *); +#endif #include diff --git a/rostests/kmtests/ntos_ex/ExSequencedList.c b/rostests/kmtests/ntos_ex/ExSequencedList.c index 1fad7614fdd..8f148f639b9 100644 --- a/rostests/kmtests/ntos_ex/ExSequencedList.c +++ b/rostests/kmtests/ntos_ex/ExSequencedList.c @@ -13,7 +13,7 @@ struct _SINGLE_LIST_ENTRY *__fastcall ExInterlockedPopEntrySList(union _SLIST_HE #include /* TODO: SLIST_HEADER is a lot different for x64 */ - +#ifndef _M_AMD64 #define CheckSListHeader(ListHead, ExpectedPointer, ExpectedDepth) do \ { \ ok_eq_pointer((ListHead)->Next.Next, ExpectedPointer); \ @@ -39,9 +39,11 @@ struct _SINGLE_LIST_ENTRY *__fastcall ExInterlockedPopEntrySList(union _SLIST_HE #undef ExInterlockedPopEntrySList #define TestXListFunctional TestSListFunctionalExports #include "ExXList.h" +#endif START_TEST(ExSequencedList) { +#ifndef _M_AMD64 PSLIST_HEADER ListHead; KSPIN_LOCK SpinLock; USHORT ExpectedSequence = 0; @@ -76,4 +78,5 @@ START_TEST(ExSequencedList) KeLowerIrql(Irql); ExFreePoolWithTag(Buffer, 'TLqS'); +#endif } diff --git a/rostests/kmtests/ntos_ex/ExSingleList.c b/rostests/kmtests/ntos_ex/ExSingleList.c index cebf2652a27..d786ec79227 100644 --- a/rostests/kmtests/ntos_ex/ExSingleList.c +++ b/rostests/kmtests/ntos_ex/ExSingleList.c @@ -6,8 +6,10 @@ */ struct _SINGLE_LIST_ENTRY; +#ifdef _X86_ struct _SINGLE_LIST_ENTRY *__stdcall ExInterlockedPushEntryList(struct _SINGLE_LIST_ENTRY *, struct _SINGLE_LIST_ENTRY *, unsigned long *); struct _SINGLE_LIST_ENTRY *__stdcall ExInterlockedPopEntryList(struct _SINGLE_LIST_ENTRY *, unsigned long *); +#endif #include diff --git a/rostests/kmtests/ntos_ke/KeIrql.c b/rostests/kmtests/ntos_ke/KeIrql.c index 27c4d36daf3..82082cfc7d4 100644 --- a/rostests/kmtests/ntos_ke/KeIrql.c +++ b/rostests/kmtests/ntos_ke/KeIrql.c @@ -7,6 +7,10 @@ __declspec(dllimport) void __stdcall KeRaiseIrql(unsigned char, unsigned char *); __declspec(dllimport) void __stdcall KeLowerIrql(unsigned char); +#ifdef _M_AMD64 +#define CLOCK1_LEVEL CLOCK_LEVEL +#define CLOCK2_LEVEL CLOCK_LEVEL +#endif #include diff --git a/rostests/kmtests/ntos_mm/MmSection.c b/rostests/kmtests/ntos_mm/MmSection.c new file mode 100644 index 00000000000..96246b2a6ae --- /dev/null +++ b/rostests/kmtests/ntos_mm/MmSection.c @@ -0,0 +1,98 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Kernel-Mode Test Suite Section Object test + * PROGRAMMER: Thomas Faber + */ + +#include + +#define StartSeh() ExceptionStatus = STATUS_SUCCESS; _SEH2_TRY { +#define EndSeh(ExpectedStatus) } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { ExceptionStatus = _SEH2_GetExceptionCode(); } _SEH2_END; ok_eq_hex(ExceptionStatus, ExpectedStatus) + +START_TEST(MmSection) +{ + NTSTATUS Status = STATUS_SUCCESS; + NTSTATUS ExceptionStatus; + const PVOID InvalidPointer = (PVOID)0x5555555555555555LLU; + PVOID SectionObject; + LARGE_INTEGER MaximumSize; + + StartSeh() + Status = MmCreateSection(NULL, 0, NULL, NULL, 0, SEC_RESERVE, NULL, NULL); + EndSeh(STATUS_SUCCESS); + ok_eq_hex(Status, STATUS_INVALID_PAGE_PROTECTION); + + if (!KmtIsCheckedBuild) + { + /* PAGE_NOACCESS and missing SEC_RESERVE/SEC_COMMIT/SEC_IMAGE assert */ + StartSeh() + Status = MmCreateSection(NULL, 0, NULL, NULL, PAGE_NOACCESS, SEC_RESERVE, NULL, NULL); + EndSeh(STATUS_ACCESS_VIOLATION); + + StartSeh() + Status = MmCreateSection(NULL, 0, NULL, NULL, PAGE_NOACCESS, 0, NULL, NULL); + EndSeh(STATUS_ACCESS_VIOLATION); + } + + SectionObject = InvalidPointer; + StartSeh() + Status = MmCreateSection(&SectionObject, 0, NULL, NULL, 0, SEC_RESERVE, NULL, NULL); + EndSeh(STATUS_SUCCESS); + ok_eq_hex(Status, STATUS_INVALID_PAGE_PROTECTION); + ok_eq_pointer(SectionObject, InvalidPointer); + + StartSeh() + Status = MmCreateSection(NULL, 0, NULL, NULL, PAGE_READONLY, SEC_RESERVE, NULL, NULL); + EndSeh(STATUS_ACCESS_VIOLATION); + + SectionObject = InvalidPointer; + StartSeh() + Status = MmCreateSection(&SectionObject, 0, NULL, NULL, PAGE_READONLY, SEC_RESERVE, NULL, NULL); + EndSeh(STATUS_ACCESS_VIOLATION); + ok_eq_pointer(SectionObject, InvalidPointer); + + MaximumSize.QuadPart = 0; + StartSeh() + Status = MmCreateSection(NULL, 0, NULL, &MaximumSize, PAGE_READONLY, SEC_RESERVE, NULL, NULL); + EndSeh(STATUS_SUCCESS); + ok_eq_hex(Status, STATUS_INVALID_PARAMETER_4); + ok_eq_longlong(MaximumSize.QuadPart, 0LL); + + MaximumSize.QuadPart = 1; + StartSeh() + Status = MmCreateSection(NULL, 0, NULL, &MaximumSize, PAGE_READONLY, SEC_RESERVE, NULL, NULL); + EndSeh(STATUS_ACCESS_VIOLATION); + ok_eq_longlong(MaximumSize.QuadPart, 1LL); + + SectionObject = InvalidPointer; + MaximumSize.QuadPart = 0; + StartSeh() + Status = MmCreateSection(&SectionObject, 0, NULL, &MaximumSize, PAGE_READONLY, SEC_RESERVE, NULL, NULL); + EndSeh(STATUS_SUCCESS); + ok_eq_hex(Status, STATUS_INVALID_PARAMETER_4); + ok_eq_longlong(MaximumSize.QuadPart, 0LL); + ok_eq_pointer(SectionObject, InvalidPointer); + + SectionObject = InvalidPointer; + MaximumSize.QuadPart = 1; + StartSeh() + Status = MmCreateSection(&SectionObject, 0, NULL, &MaximumSize, PAGE_READONLY, SEC_RESERVE, NULL, NULL); + EndSeh(STATUS_SUCCESS); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_eq_longlong(MaximumSize.QuadPart, 1LL); + ok(SectionObject != InvalidPointer, "Section object pointer untouched\n"); + ok(SectionObject != NULL, "Section object pointer NULL\n"); + + if (SectionObject && SectionObject != InvalidPointer) + ObDereferenceObject(SectionObject); + + SectionObject = InvalidPointer; + MaximumSize.QuadPart = 1; + StartSeh() + Status = MmCreateSection(&SectionObject, 0, NULL, &MaximumSize, PAGE_READONLY, SEC_IMAGE, NULL, NULL); + EndSeh(STATUS_SUCCESS); + ok_eq_hex(Status, STATUS_INVALID_FILE_FOR_SECTION); + ok_eq_longlong(MaximumSize.QuadPart, 1LL); + ok_eq_pointer(SectionObject, InvalidPointer); +} diff --git a/rostests/kmtests/readme.txt b/rostests/kmtests/readme.txt index fa9a66ba7ef..7a328b5d6d2 100644 --- a/rostests/kmtests/readme.txt +++ b/rostests/kmtests/readme.txt @@ -7,5 +7,5 @@ The example subdirectory contains a set of small tests that can be used as examples and templates. -See http://www.reactos.org/wiki/User:ThFabba/KmtestsHowto for more +See http://www.reactos.org/wiki/KmtestsHowto for more information and a guide on how to use the framework.