Index: kmtests/CMakeLists.txt =================================================================== --- kmtests/CMakeLists.txt (revision 58858) +++ kmtests/CMakeLists.txt (working copy) @@ -52,6 +52,9 @@ ntos_ke/KeSpinLock.c ntos_ke/KeTimer.c ntos_mm/MmSection.c + ntos_mm/ZwAllocateVirtualMemory.c + ntos_mm/ZwCreateSection.c + ntos_mm/ZwMapViewOfSection.c ntos_ob/ObReference.c ntos_ob/ObType.c ntos_ob/ObTypes.c @@ -65,6 +68,7 @@ set_module_type(kmtest_drv kernelmodedriver) target_link_libraries(kmtest_drv kmtest_printf chkstk ${PSEH_LIB}) add_importlibs(kmtest_drv ntoskrnl hal) +add_dependencies(kmtest_drv bugcodes) add_target_compile_definitions(kmtest_drv KMT_KERNEL_MODE NTDDI_VERSION=NTDDI_WS03SP1) #add_pch(kmtest_drv include/kmt_test.h) Index: kmtests/include/kmt_public.h =================================================================== --- kmtests/include/kmt_public.h (revision 58858) +++ kmtests/include/kmt_public.h (working copy) @@ -17,6 +17,12 @@ #define IOCTL_KMTEST_SET_RESULTBUFFER \ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) +#define IOCTL_KMTEST_USERMODE_SEND_RESPONSE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_IN_DIRECT, FILE_WRITE_DATA) + +#define IOCTL_KMTEST_USERMODE_AWAIT_REQ \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_READ_DATA) + #define KMTEST_DEVICE_NAME L"Kmtest" #define KMTEST_DEVICE_DRIVER_PATH L"\\Device\\" KMTEST_DEVICE_NAME #define KMTEST_DEVICE_PATH L"\\\\.\\Global\\GLOBALROOT" KMTEST_DEVICE_DRIVER_PATH Index: kmtests/include/kmt_test.h =================================================================== --- kmtests/include/kmt_test.h (revision 58858) +++ kmtests/include/kmt_test.h (working copy) @@ -38,6 +38,48 @@ CHAR LogBuffer[ANYSIZE_ARRAY]; } KMT_RESULTBUFFER, *PKMT_RESULTBUFFER; +#ifndef KMT_STANDALONE_DRIVER + +/* usermode call-back mechanism */ + +/* list of supported operations */ +typedef enum _KMT_CALLBACK_INFORMATION_CLASS +{ + QueryVirtualMemory +} KMT_CALLBACK_INFORMATION_CLASS, *PKMT_CALLBACK_INFORMATION_CLASS; + +/* TODO: "response" is a little generic */ +typedef union _KMT_RESPONSE +{ + MEMORY_BASIC_INFORMATION MemInfo; +} KMT_RESPONSE, *PKMT_RESPONSE; + +/* this struct is sent from driver to usermode */ +typedef struct _KMT_CALLBACK_REQUEST_PACKET +{ + ULONG RequestId; + KMT_CALLBACK_INFORMATION_CLASS OperationClass; + PVOID Parameters; +} KMT_CALLBACK_REQUEST_PACKET, *PKMT_CALLBACK_REQUEST_PACKET; + +PKMT_RESPONSE KmtUserModeCallback(KMT_CALLBACK_INFORMATION_CLASS Operation, PVOID Parameters); +VOID KmtFreeCallbackResponse(PKMT_RESPONSE Response); + +//macro to simplify using the mechanism +#define Test_NtQueryVirtualMemory(BaseAddress, Size, AllocationType, ProtectionType) \ + do { \ + PKMT_RESPONSE NtQueryTest = KmtUserModeCallback(QueryVirtualMemory, BaseAddress); \ + if (NtQueryTest != NULL) \ + { \ + ok_eq_hex(NtQueryTest->MemInfo.Protect, ProtectionType); \ + ok_eq_hex(NtQueryTest->MemInfo.State, AllocationType); \ + ok_eq_size(NtQueryTest->MemInfo.RegionSize, Size); \ + KmtFreeCallbackResponse(NtQueryTest); \ + } \ + } while (0) \ + +#endif + #ifdef KMT_STANDALONE_DRIVER #define KMT_KERNEL_MODE Index: kmtests/kmtest/support.c =================================================================== --- kmtests/kmtest/support.c (revision 58858) +++ kmtests/kmtest/support.c (working copy) @@ -11,10 +11,74 @@ #include #include +#include extern HANDLE KmtestHandle; /** + * @name KmtUserCallbackThread + * + * Thread routine which awaits callback requests from kernel-mode + * + * @return Win32 error code + */ +DWORD +WINAPI +KmtUserCallbackThread( + PVOID Parameter) +{ + DWORD Error = ERROR_SUCCESS; + /* TODO: RequestPacket? */ + KMT_CALLBACK_REQUEST_PACKET RequestPacket; + KMT_RESPONSE Response; + DWORD BytesReturned; + HANDLE LocalKmtHandle; + + UNREFERENCED_PARAMETER(Parameter); + + /* concurrent IoCtls on the same (non-overlapped) handle aren't possible, + * so open a separate one. + * For more info http://www.osronline.com/showthread.cfm?link=230782 */ + LocalKmtHandle = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (LocalKmtHandle == INVALID_HANDLE_VALUE) + error_goto(Error, cleanup); + + while (1) + { + if (!DeviceIoControl(LocalKmtHandle, IOCTL_KMTEST_USERMODE_AWAIT_REQ, NULL, 0, &RequestPacket, sizeof(RequestPacket), &BytesReturned, NULL)) + error_goto(Error, cleanup); + ASSERT(BytesReturned == sizeof(RequestPacket)); + + switch (RequestPacket.OperationClass) + { + case QueryVirtualMemory: + { + SIZE_T InfoBufferSize = VirtualQuery(RequestPacket.Parameters, &Response.MemInfo, sizeof(Response.MemInfo)); + /* FIXME: an error is a valid result. That should go as a response to kernel mode instead of terminating the thread */ + if (InfoBufferSize == 0) + error_goto(Error, cleanup); + + if (!DeviceIoControl(LocalKmtHandle, IOCTL_KMTEST_USERMODE_SEND_RESPONSE, &RequestPacket.RequestId, sizeof(RequestPacket.RequestId), &Response, sizeof(Response), &BytesReturned, NULL)) + error_goto(Error, cleanup); + ASSERT(BytesReturned == 0); + + break; + } + default: + DPRINT1("Unrecognized user-mode callback request\n"); + break; + } + } + +cleanup: + if (LocalKmtHandle != INVALID_HANDLE_VALUE) + CloseHandle(LocalKmtHandle); + + DPRINT("Callback handler dying! Error code %lu", Error); + return Error; +} + +/** * @name KmtRunKernelTest * * Run the specified kernel-mode test part @@ -28,12 +92,18 @@ KmtRunKernelTest( IN PCSTR TestName) { + HANDLE CallbackThread; DWORD Error = ERROR_SUCCESS; DWORD BytesRead; + CallbackThread = CreateThread(NULL, 0, KmtUserCallbackThread, NULL, 0, NULL); + if (!DeviceIoControl(KmtestHandle, IOCTL_KMTEST_RUN_TEST, (PVOID)TestName, (DWORD)strlen(TestName), NULL, 0, &BytesRead, NULL)) error(Error); + if (CallbackThread != NULL) + CloseHandle(CallbackThread); + return Error; } Index: kmtests/kmtest_drv/kmtest_drv.c =================================================================== --- kmtests/kmtest_drv/kmtest_drv.c (revision 58858) +++ kmtests/kmtest_drv/kmtest_drv.c (working copy) @@ -19,6 +19,22 @@ #define KMT_DEFINE_TEST_FUNCTIONS #include +/* Usermode callback definitions */ +typedef struct _KMT_USER_WORK_ENTRY +{ + LIST_ENTRY ListEntry; + KEVENT WorkDoneEvent; + KMT_CALLBACK_REQUEST_PACKET Request; + PKMT_RESPONSE Response; +} KMT_USER_WORK_ENTRY, *PKMT_USER_WORK_ENTRY; + +typedef struct _KMT_USER_WORK_LIST +{ + LIST_ENTRY ListHead; + FAST_MUTEX Lock; + KEVENT NewWorkEvent; +} KMT_USER_WORK_LIST, *PKMT_USER_WORK_LIST; + /* Prototypes */ DRIVER_INITIALIZE DriverEntry; static DRIVER_UNLOAD DriverUnload; @@ -30,10 +46,13 @@ static DRIVER_DISPATCH DriverClose; __drv_dispatchType(IRP_MJ_DEVICE_CONTROL) static DRIVER_DISPATCH DriverIoControl; +static VOID KmtCleanUsermodeCallbacks(VOID); /* Globals */ static PDEVICE_OBJECT MainDeviceObject; PDRIVER_OBJECT KmtDriverObject = NULL; +static KMT_USER_WORK_LIST WorkList; +static ULONG RequestId = 0; /* Entry */ /** @@ -92,6 +111,10 @@ DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIoControl; + ExInitializeFastMutex(&WorkList.Lock); + KeInitializeEvent(&WorkList.NewWorkEvent, NotificationEvent, FALSE); + InitializeListHead(&WorkList.ListHead); + cleanup: if (MainDeviceObject && !NT_SUCCESS(Status)) { @@ -123,6 +146,8 @@ DPRINT("DriverUnload\n"); + KmtCleanUsermodeCallbacks(); + if (MainDeviceObject) { PKMT_DEVICE_EXTENSION DeviceExtension = MainDeviceObject->DeviceExtension; @@ -403,6 +428,93 @@ ResultBuffer->LogBufferLength, ResultBuffer->LogBufferMaxLength); break; } + case IOCTL_KMTEST_USERMODE_AWAIT_REQ: + { + PLIST_ENTRY Entry; + PKMT_USER_WORK_ENTRY WorkItem; + + DPRINT("DriverIoControl. IOCTL_KMTEST_USERMODE_AWAIT_REQ, len=%lu\n", + IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength); + + /* TODO: prevent multiple concurrent invocations */ + Status = KeWaitForSingleObject(&WorkList.NewWorkEvent, UserRequest, UserMode, FALSE, NULL); + if (Status == STATUS_USER_APC || Status == STATUS_KERNEL_APC) + break; + + if (IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KMT_CALLBACK_REQUEST_PACKET)) + { + Status = STATUS_INVALID_BUFFER_SIZE; + break; + } + + ASSERT(!IsListEmpty(&WorkList.ListHead)); + + Entry = WorkList.ListHead.Flink; + WorkItem = CONTAINING_RECORD(Entry, KMT_USER_WORK_ENTRY, ListEntry); + + Length = sizeof(WorkItem->Request); + RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &WorkItem->Request, Length); + Status = STATUS_SUCCESS; + + KeResetEvent(&WorkList.NewWorkEvent); + break; + + } + case IOCTL_KMTEST_USERMODE_SEND_RESPONSE: + { + PLIST_ENTRY Entry; + PKMT_USER_WORK_ENTRY WorkEntry; + PVOID Response; + ULONG ResponseSize = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength; + + DPRINT("DriverIoControl. IOCTL_KMTEST_USERMODE_SEND_RESPONSE, inlen=%lu, outlen=%lu\n", + IoStackLocation->Parameters.DeviceIoControl.InputBufferLength, + IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength); + + if (IoStackLocation->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG) || ResponseSize != sizeof(KMT_RESPONSE)) + { + Status = STATUS_INVALID_BUFFER_SIZE; + break; + } + + /* FIXME: don't misuse the output buffer as an input! */ + Response = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + if (Response == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + ExAcquireFastMutex(&WorkList.Lock); + + Status = STATUS_OBJECTID_NOT_FOUND; + + Entry = WorkList.ListHead.Flink; + while (Entry != &WorkList.ListHead) + { + WorkEntry = CONTAINING_RECORD(Entry, KMT_USER_WORK_ENTRY, ListEntry); + if (WorkEntry->Request.RequestId == *(PULONG)Irp->AssociatedIrp.SystemBuffer) + { + WorkEntry->Response = ExAllocatePoolWithTag(PagedPool, sizeof(KMT_RESPONSE), 'pseR'); + if (WorkEntry->Response == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + RtlCopyMemory(WorkEntry->Response, Response, ResponseSize); + KeSetEvent(&WorkEntry->WorkDoneEvent, IO_NO_INCREMENT, FALSE); + Status = STATUS_SUCCESS; + break; + } + + Entry = Entry->Flink; + } + + ExReleaseFastMutex(&WorkList.Lock); + + break; + } default: DPRINT1("DriverIoControl. Invalid IoCtl code 0x%08X\n", IoStackLocation->Parameters.DeviceIoControl.IoControlCode); @@ -417,3 +529,113 @@ return Status; } + +/** + * @name KmtUserModeCallback + * + * Enqueue a request to the usermode callback queue and blocks until the work + * is finished. + * + * @param Operation + * TODO + * @param Parameters + * TODO + * TODO: why is this PVOID? + * + * @return Response from user mode + */ +PKMT_RESPONSE +KmtUserModeCallback( + IN KMT_CALLBACK_INFORMATION_CLASS Operation, + IN PVOID Parameters) +{ + PKMT_RESPONSE Result; + NTSTATUS Status; + PKMT_USER_WORK_ENTRY WorkEntry; + LARGE_INTEGER Timeout; + + PAGED_CODE(); + + WorkEntry = ExAllocatePoolWithTag(PagedPool, sizeof(KMT_USER_WORK_ENTRY), 'ekrW'); + if (WorkEntry == NULL) + return NULL; + + KeInitializeEvent(&WorkEntry->WorkDoneEvent, NotificationEvent, FALSE); + WorkEntry->Request.RequestId = RequestId++; + WorkEntry->Request.OperationClass = Operation; + WorkEntry->Request.Parameters = Parameters; + WorkEntry->Response = NULL; + + ExAcquireFastMutex(&WorkList.Lock); + InsertTailList(&WorkList.ListHead, &WorkEntry->ListEntry); + ExReleaseFastMutex(&WorkList.Lock); + + KeSetEvent(&WorkList.NewWorkEvent, IO_NO_INCREMENT, FALSE); + + Timeout.QuadPart = -10 * 1000 * 1000 * 10; //wait for 10 seconds + Status = KeWaitForSingleObject(&WorkEntry->WorkDoneEvent, Executive, UserMode, FALSE, &Timeout); + + if (Status == STATUS_USER_APC || Status == STATUS_KERNEL_APC || Status == STATUS_TIMEOUT) + { + DPRINT1("Unexpected callback abortion! Reason: %lx\n", Status); + } + + ExAcquireFastMutex(&WorkList.Lock); + RemoveEntryList(&WorkEntry->ListEntry); + ExReleaseFastMutex(&WorkList.Lock); + + Result = WorkEntry->Response; + + ExFreePoolWithTag(WorkEntry, 'ekrW'); + + return Result; +} + +/** + * @name KmtFreeCallbackResponse + * + * TODO + * + * @param Response + * TODO + */ +VOID +KmtFreeCallbackResponse( + PKMT_RESPONSE Response) +{ + PAGED_CODE(); + + ExFreePoolWithTag(Response, 'pseR'); +} + +/** + * @name KmtCleanUsermodeCallbacks + * + * TODO + */ +static +VOID +KmtCleanUsermodeCallbacks(VOID) +{ + PLIST_ENTRY Entry; + + PAGED_CODE(); + + ExAcquireFastMutex(&WorkList.Lock); + + Entry = WorkList.ListHead.Flink; + while (Entry != &WorkList.ListHead) + { + PKMT_USER_WORK_ENTRY WorkEntry = CONTAINING_RECORD(Entry, KMT_USER_WORK_ENTRY, ListEntry); + if (WorkEntry->Response != NULL) + { + KmtFreeCallbackResponse(WorkEntry->Response); + } + + Entry = Entry->Flink; + + ExFreePoolWithTag(WorkEntry, 'ekrW'); + } + + ExReleaseFastMutex(&WorkList.Lock); +} Index: kmtests/kmtest_drv/testlist.c =================================================================== --- kmtests/kmtest_drv/testlist.c (revision 58859) +++ kmtests/kmtest_drv/testlist.c (working copy) @@ -46,6 +46,9 @@ KMT_TESTFUNC Test_RtlException; KMT_TESTFUNC Test_RtlMemory; KMT_TESTFUNC Test_RtlSplayTree; +KMT_TESTFUNC Test_ZwAllocateVirtualMemory; +KMT_TESTFUNC Test_ZwCreateSection; +KMT_TESTFUNC Test_ZwMapViewOfSection; const KMT_TEST TestList[] = { @@ -89,5 +92,8 @@ { "RtlExceptionKM", Test_RtlException }, { "RtlMemoryKM", Test_RtlMemory }, { "RtlSplayTreeKM", Test_RtlSplayTree }, + {"ZwAllocateVirtualMemory", Test_ZwAllocateVirtualMemory}, + {"ZwCreateSection", Test_ZwCreateSection}, + {"ZwMapViewOfSection", Test_ZwMapViewOfSection}, { NULL, NULL } }; Index: kmtests/ntos_mm/ZwAllocateVirtualMemory.c =================================================================== --- kmtests/ntos_mm/ZwAllocateVirtualMemory.c (revision 0) +++ kmtests/ntos_mm/ZwAllocateVirtualMemory.c (working copy) @@ -0,0 +1,511 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Kernel-Mode Test Suite ZwAllocateVirtualMemory/ZwFreeVirtualMemory + * PROGRAMMER: Nikolay Borisov + */ + + +#include + +#define ROUND_DOWN(n,align) (((ULONG_PTR)n) & ~((align) - 1l)) +#define DEFAULT_ALLOC_SIZE 200 +#define IGNORE -1 +#define PAGE_NOPROT 0x0 //MEM_RESERVE has this type of "protection" + +/* These are being used in ZwMapViewOfSection as well */ +const char TestString[] = "TheLongBrownFoxJumpedTheWhiteRabbitTheLongBrownFoxJumpedTheWhiteRabbitTheLongBrownFoxJumpedTheWhiteRabbitTheLongBrownFoxJumpedTheWhiteRabbitTheLongBrownFoxJumpedTheWhiteRabbitTheLongBrownFoxJumpedThe"; +const SIZE_T TestStringSize = sizeof(TestString); + +VOID Test_ZwAllocateVirtualMemory(VOID); + +typedef struct _TEST_CONTEXT +{ + HANDLE ProcessHandle; + ULONG RegionSize; + ULONG AllocationType; + ULONG Protect; + PVOID Bases[1024]; + SHORT ThreadId; +} TEST_CONTEXT, *PTEST_CONTEXT; + + +#define ALLOC_MEMORY_WITH_FREE(ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect, RetStatus, FreeStatus) \ + do { \ + Status = ZwAllocateVirtualMemory(ProcessHandle, &BaseAddress, ZeroBits, &RegionSize, AllocationType, Protect); \ + ok_eq_hex(Status, RetStatus); \ + RegionSize = 0; \ + Status = ZwFreeVirtualMemory(ProcessHandle, &BaseAddress, &RegionSize, MEM_RELEASE); \ + if (FreeStatus != IGNORE) ok_eq_hex(Status, FreeStatus); \ + BaseAddress = NULL; \ + RegionSize = DEFAULT_ALLOC_SIZE; \ + } while (0) \ + + +static +BOOLEAN +CheckBuffer(PVOID Buffer, SIZE_T Size, UCHAR Value) +{ + PUCHAR Array = Buffer; + SIZE_T i; + + for (i = 0; i < Size; i++) + { + if (Array[i] != Value) + { + trace("Expected %x, found %x at offset %lu\n", Value, Array[i], (ULONG)i); + return FALSE; + } + } + return TRUE; +} + +static +SIZE_T +CheckBufferRead(CONST VOID *Source, CONST VOID *Destination, SIZE_T Length, NTSTATUS ExpectedStatus) +{ + NTSTATUS ExceptionStatus; + SIZE_T Match = 0; + + KmtStartSeh() + Match = RtlCompareMemory(Source, Destination, Length); + KmtEndSeh(ExpectedStatus); + + return Match; + +} + +static +VOID +CheckBufferReadWrite(PVOID Destination, CONST VOID *Source, SIZE_T Length, NTSTATUS ExpectedStatus) +{ + //do a little bit of writing/reading to memory + NTSTATUS ExceptionStatus; + SIZE_T Match = 0; + + KmtStartSeh() + RtlCopyMemory(Destination, Source, Length); + KmtEndSeh(ExpectedStatus); + + Match = CheckBufferRead(Source, Destination, Length, ExpectedStatus); + if (ExpectedStatus == STATUS_SUCCESS) ok_eq_int(Match, Length); +} + + +static +VOID +SimpleErrorChecks(VOID) +{ + + NTSTATUS Status; + PVOID Base = NULL; + SIZE_T RegionSize = DEFAULT_ALLOC_SIZE; + + //HANDLE TESTS + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + ALLOC_MEMORY_WITH_FREE(NULL, Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_INVALID_HANDLE, STATUS_INVALID_HANDLE); + ALLOC_MEMORY_WITH_FREE((HANDLE)0xdeadbeef, Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_INVALID_HANDLE, STATUS_INVALID_HANDLE); + + //BASE ADDRESS TESTS + Base = (PVOID)0x00567A20; + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_CONFLICTING_ADDRESSES, STATUS_FREE_VM_NOT_AT_BASE); + + Base = (PVOID) 0x60000000; + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + + Base = (PVOID)((char *)MmSystemRangeStart + 200); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_INVALID_PARAMETER_2, STATUS_INVALID_PARAMETER_2); + + /* http://jira.reactos.org/browse/CORE-6814 */ + RegionSize = 0x1000; + Base = Test_ZwAllocateVirtualMemory; + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, MEM_COMMIT, PAGE_READWRITE, STATUS_INVALID_PARAMETER_2, STATUS_MEMORY_NOT_ALLOCATED); + + //ZERO BITS TESTS + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 21, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_NO_MEMORY, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 22, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_INVALID_PARAMETER_3, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, -1, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_INVALID_PARAMETER_3, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 3, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + + //REGION SIZE TESTS + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + RegionSize = -1; + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_INVALID_PARAMETER_4, STATUS_MEMORY_NOT_ALLOCATED); + RegionSize = 0; + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_INVALID_PARAMETER_4, STATUS_MEMORY_NOT_ALLOCATED); + RegionSize = 0xFFFFFFFF; // 4 gb is invalid + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_INVALID_PARAMETER_4, STATUS_MEMORY_NOT_ALLOCATED); + + //Allocation type tests + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, MEM_PHYSICAL, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESET), PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, MEM_TOP_DOWN, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_TOP_DOWN | MEM_RESET), PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_TOP_DOWN | MEM_COMMIT), PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_PHYSICAL | MEM_RESERVE), PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_PHYSICAL | MEM_COMMIT), PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_RESET | MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, -1, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, MEM_COMMIT, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, MEM_RESERVE, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, MEM_RESERVE, PAGE_WRITECOPY, STATUS_INVALID_PAGE_PROTECTION, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, MEM_RESERVE, PAGE_EXECUTE_WRITECOPY, STATUS_INVALID_PAGE_PROTECTION, STATUS_MEMORY_NOT_ALLOCATED); + + //Memory protection tests + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), 0, STATUS_INVALID_PAGE_PROTECTION, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), -1, STATUS_INVALID_PAGE_PROTECTION, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), (PAGE_NOACCESS | PAGE_GUARD), STATUS_INVALID_PAGE_PROTECTION, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), (PAGE_NOACCESS | PAGE_WRITECOMBINE), STATUS_INVALID_PAGE_PROTECTION, STATUS_MEMORY_NOT_ALLOCATED); + ALLOC_MEMORY_WITH_FREE(NtCurrentProcess(), Base, 0, RegionSize, (MEM_COMMIT | MEM_RESERVE), (PAGE_READONLY | PAGE_WRITECOMBINE), STATUS_SUCCESS, STATUS_SUCCESS); +} + + +static +NTSTATUS +SimpleAllocation(VOID) +{ + NTSTATUS Status; + NTSTATUS ExceptionStatus; + PVOID Base = NULL; + SIZE_T RegionSize = DEFAULT_ALLOC_SIZE; + + ////////////////////////////////////////////////////////////////////////// + //Normal operation + ////////////////////////////////////////////////////////////////////////// + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &Base, 0, &RegionSize, MEM_COMMIT, PAGE_READWRITE); + ok_eq_size(RegionSize, 4096); + + //check for the zero-filled pages + ok_bool_true(CheckBuffer(Base, RegionSize, 0), "The buffer is not zero-filled"); + + CheckBufferReadWrite(Base, TestString, TestStringSize, STATUS_SUCCESS); + + // try freeing + RegionSize = 0; + Status = ZwFreeVirtualMemory(NtCurrentProcess(), &Base, &RegionSize, MEM_RELEASE); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_eq_size(RegionSize, PAGE_SIZE); + + ////////////////////////////////////////////////////////////////////////// + // COMMIT AND RESERVE SCENARIO AND STATE CHANGE + ////////////////////////////////////////////////////////////////////////// + //reserve and then commit + Base = NULL; + RegionSize = DEFAULT_ALLOC_SIZE; + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &Base, 0, &RegionSize, MEM_RESERVE, PAGE_READWRITE); + Test_NtQueryVirtualMemory(Base, RegionSize, MEM_RESERVE, PAGE_NOPROT); + CheckBufferReadWrite(Base, TestString, TestStringSize, STATUS_ACCESS_VIOLATION); + + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &Base, 0, &RegionSize, MEM_COMMIT, PAGE_READWRITE); + CheckBufferReadWrite(Base, TestString, TestStringSize, STATUS_SUCCESS); + Test_NtQueryVirtualMemory(Base, RegionSize, MEM_COMMIT, PAGE_READWRITE); + + RegionSize = 0; + ZwFreeVirtualMemory(NtCurrentProcess(), &Base, &RegionSize, MEM_RELEASE); + + ////////////////////////////////////////////////////////////////////////// + // TRY READING/WRITING TO INVALID PROTECTION PAGES + ////////////////////////////////////////////////////////////////////////// + RegionSize = DEFAULT_ALLOC_SIZE; + Base = NULL; + ZwAllocateVirtualMemory(NtCurrentProcess(), &Base, 0, &RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_NOACCESS); + + KmtStartSeh() + RtlCopyMemory(Base, TestString, TestStringSize); + KmtEndSeh(STATUS_ACCESS_VIOLATION); + + Test_NtQueryVirtualMemory(Base, RegionSize, MEM_COMMIT, PAGE_NOACCESS); + CheckBufferRead(Base, TestString, TestStringSize, STATUS_ACCESS_VIOLATION); + + RegionSize = 0; + ZwFreeVirtualMemory(NtCurrentProcess(), &Base, &RegionSize, MEM_RELEASE); + + ZwAllocateVirtualMemory(NtCurrentProcess(), &Base, 0, &RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READONLY); + KmtStartSeh() + RtlCopyMemory(Base, TestString, TestStringSize); + KmtEndSeh(STATUS_ACCESS_VIOLATION); + + Test_NtQueryVirtualMemory(Base, RegionSize, MEM_COMMIT, PAGE_READONLY); + + ok_bool_true(CheckBuffer(Base, TestStringSize, 0), "Couldn't read a read-only buffer"); + + RegionSize = 0; + ZwFreeVirtualMemory(NtCurrentProcess(), &Base, &RegionSize, MEM_RELEASE); + + ////////////////////////////////////////////////////////////////////////// + // GUARD PAGES + ////////////////////////////////////////////////////////////////////////// + RegionSize = 1000; + Base = NULL; + ZwAllocateVirtualMemory(NtCurrentProcess(), &Base, 0, &RegionSize, (MEM_COMMIT | MEM_RESERVE), (PAGE_GUARD | PAGE_READWRITE)); + + Test_NtQueryVirtualMemory(Base, RegionSize, MEM_COMMIT, (PAGE_GUARD | PAGE_READWRITE)); + KmtStartSeh() + RtlCopyMemory(Base, TestString, TestStringSize); + KmtEndSeh(STATUS_GUARD_PAGE_VIOLATION); + + Test_NtQueryVirtualMemory(Base, RegionSize, MEM_COMMIT, PAGE_READWRITE); + + KmtStartSeh() + RtlCopyMemory(Base, TestString, TestStringSize); + KmtEndSeh(STATUS_SUCCESS); + + RegionSize = 0; + ZwFreeVirtualMemory(NtCurrentProcess(), &Base, &RegionSize, MEM_RELEASE); + + return Status; +} + + +static +VOID +CustomBaseAllocation(VOID) +{ + NTSTATUS Status; + SIZE_T RegionSize = 200; + PVOID Base = (PVOID) 0x60025000; + PVOID ActualStartingAddress = (PVOID)ROUND_DOWN(Base, MM_ALLOCATION_GRANULARITY); //it is rounded down to the nearest allocation granularity (64k) address + PVOID EndingAddress = (PVOID)(((ULONG_PTR)Base + RegionSize - 1) | (PAGE_SIZE - 1)); + SIZE_T ActualSize = BYTES_TO_PAGES((ULONG_PTR)EndingAddress - (ULONG_PTR)ActualStartingAddress) * PAGE_SIZE; //calculates the actual size based on the required pages + + // allocate the memory + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), (PVOID *)&Base, 0, &RegionSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_eq_size(RegionSize, ActualSize); + ok_eq_ulong(Base, ActualStartingAddress); + Test_NtQueryVirtualMemory(ActualStartingAddress, ActualSize, MEM_COMMIT, PAGE_READWRITE); + + // try freeing + RegionSize = 0; + Status = ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *)&Base, &RegionSize, MEM_RELEASE); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_eq_ulong(RegionSize, ActualSize); +} + + +static +NTSTATUS +StressTesting(ULONG AllocationType) +{ + NTSTATUS Status = STATUS_SUCCESS; + NTSTATUS ReturnStatus = STATUS_SUCCESS; + static PVOID bases[1024]; //assume we are going to allocate only 5 gigs. static here means the arrays is not allocated on the stack but in the BSS segment of the driver + ULONG Index = 0; + PVOID Base = NULL; + SIZE_T RegionSize = 5 * 1024 * 1024; // 5 megabytes; + + RtlZeroMemory(bases, sizeof(bases)); + + for (Index = 0; Index < RTL_NUMBER_OF(bases) && NT_SUCCESS(Status); Index++) + { + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &Base, 0, &RegionSize, AllocationType, PAGE_READWRITE); + + bases[Index] = Base; + if ((Index % 10) == 0) + { + + if (AllocationType == MEM_COMMIT && NT_SUCCESS(Status)) + { + CheckBufferReadWrite(Base, TestString, TestStringSize, STATUS_SUCCESS); + } + else + { + CheckBufferReadWrite(Base, TestString, TestStringSize, STATUS_ACCESS_VIOLATION); + } + } + + Base = NULL; + + } + + trace("Finished reserving. Error code %x. Chunks allocated: %d\n", Status, Index ); + + ReturnStatus = Status; + + //free the allocated memory so that we can continue with the tests + Status = STATUS_SUCCESS; + Index = 0; + while (NT_SUCCESS(Status) && Index < RTL_NUMBER_OF(bases)) + { + RegionSize = 0; + Status = ZwFreeVirtualMemory(NtCurrentProcess(), &bases[Index], &RegionSize, MEM_RELEASE); + bases[Index++] = NULL; + + } + + return ReturnStatus; +} + + +static +VOID +NTAPI +SystemProcessTestWorker(PVOID StartContext) +{ + NTSTATUS Status = STATUS_SUCCESS; + PTEST_CONTEXT Context = (PTEST_CONTEXT) StartContext; + ULONG Index = 0; + PVOID Base = NULL; + + PAGED_CODE(); + + RtlZeroMemory(Context->Bases, sizeof(Context->Bases)); + + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &Base, 0, &Context->RegionSize, Context->AllocationType, Context->Protect); + ZwFreeVirtualMemory(NtCurrentProcess(), &Base, &Context->RegionSize, MEM_RELEASE); + Base = NULL; + + //if the previous allocation has failed there is no need to do the loop + while (NT_SUCCESS(Status) && Index < RTL_NUMBER_OF(Context->Bases)) + { + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &Base, 0, &Context->RegionSize, Context->AllocationType, Context->Protect); + + Context->Bases[Index] = Base; + if ((Index % 10) == 0) + { + + if (Context->AllocationType == MEM_COMMIT) + { + CheckBufferReadWrite(Base, TestString, TestStringSize, STATUS_SUCCESS); + } + else + { + CheckBufferReadWrite(Base, TestString, TestStringSize, STATUS_ACCESS_VIOLATION); + } + } + + Base = NULL; + Index++; + } + + trace("[SYSTEM THREAD %d]. Error code %x. Chunks allocated: %d\n", Context->ThreadId, Status, Index); + + //free the allocated memory so that we can continue with the tests + Status = STATUS_SUCCESS; + Index = 0; + while (NT_SUCCESS(Status) && Index < RTL_NUMBER_OF(Context->Bases)) + { + Context->RegionSize = 0; + Status = ZwFreeVirtualMemory(NtCurrentProcess(), &Context->Bases[Index], &Context->RegionSize, MEM_RELEASE); + Context->Bases[Index++] = NULL; + } + + PsTerminateSystemThread(Status); +} + + +static +VOID +KmtInitTestContext(PTEST_CONTEXT Ctx, SHORT ThreadId, ULONG RegionSize, ULONG AllocationType, ULONG Protect) +{ + PAGED_CODE(); + + Ctx->AllocationType = AllocationType; + Ctx->Protect = Protect; + Ctx->RegionSize = RegionSize; + Ctx->ThreadId = ThreadId; +} + + +static +VOID +SystemProcessTest(VOID) +{ + NTSTATUS Status; + HANDLE Thread1 = INVALID_HANDLE_VALUE; + HANDLE Thread2 = INVALID_HANDLE_VALUE; + PVOID ThreadObjects[2] = { NULL }; + OBJECT_ATTRIBUTES ObjectAttributes; + PTEST_CONTEXT StartContext1; + PTEST_CONTEXT StartContext2; + + PAGED_CODE(); + + StartContext1 = ExAllocatePoolWithTag(PagedPool, sizeof(TEST_CONTEXT), 'tXTC'); + StartContext2 = ExAllocatePoolWithTag(PagedPool, sizeof(TEST_CONTEXT), 'tXTC'); + if (StartContext1 == NULL || StartContext2 == NULL) + { + trace("Error allocating space for context structs\n"); + goto cleanup; + } + + KmtInitTestContext(StartContext1, 1, 1 * 1024 * 1024, MEM_COMMIT, PAGE_READWRITE); + KmtInitTestContext(StartContext2, 2, 3 * 1024 * 1024, MEM_COMMIT, PAGE_READWRITE); + InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(&Thread1, THREAD_ALL_ACCESS, &ObjectAttributes, NULL, NULL, SystemProcessTestWorker, StartContext1); + if (!NT_SUCCESS(Status)) + { + trace("Error creating thread1\n"); + goto cleanup; + } + + Status = ObReferenceObjectByHandle(Thread1, THREAD_ALL_ACCESS, PsThreadType, KernelMode, &ThreadObjects[0], NULL); + if (!NT_SUCCESS(Status)) + { + trace("error referencing thread1 \n"); + goto cleanup; + } + + Status = PsCreateSystemThread(&Thread2, THREAD_ALL_ACCESS, &ObjectAttributes, NULL, NULL, SystemProcessTestWorker, StartContext2); + if (!NT_SUCCESS(Status)) + { + trace("Error creating thread2\n"); + goto cleanup; + } + + Status = ObReferenceObjectByHandle(Thread2, THREAD_ALL_ACCESS, PsThreadType, KernelMode, &ThreadObjects[1], NULL); + if (!NT_SUCCESS(Status)) + { + trace("error referencing thread2 \n"); + goto cleanup; + } + +cleanup: + + if (ThreadObjects[0]) + Status = KeWaitForSingleObject(ThreadObjects[0], Executive, KernelMode, FALSE, NULL); + + if (StartContext1 != NULL) + ExFreePoolWithTag(StartContext1, 'tXTC'); + + if (ThreadObjects[1]) + Status = KeWaitForSingleObject(ThreadObjects[1], Executive, KernelMode, FALSE, NULL); + + if (StartContext2 != NULL) + ExFreePoolWithTag(StartContext2, 'tXTC'); + + if (ThreadObjects[0] != NULL) + ObDereferenceObject(ThreadObjects[0]); + + if (ThreadObjects[1] != NULL) + ObDereferenceObject(ThreadObjects[1]); + + if (Thread1 != INVALID_HANDLE_VALUE) + ZwClose(Thread1); + + if (Thread2 != INVALID_HANDLE_VALUE) + ZwClose(Thread2); +} + + +START_TEST(ZwAllocateVirtualMemory) +{ + NTSTATUS Status; + + SimpleErrorChecks(); + + SimpleAllocation(); + + CustomBaseAllocation(); + + Status = StressTesting(MEM_RESERVE); + ok_eq_hex(Status, STATUS_NO_MEMORY); + + Status = STATUS_SUCCESS; + Status = StressTesting(MEM_COMMIT); + ok_eq_hex(Status, STATUS_COMMITMENT_LIMIT); + + SystemProcessTest(); +} Index: kmtests/ntos_mm/ZwCreateSection.c =================================================================== --- kmtests/ntos_mm/ZwCreateSection.c (revision 0) +++ kmtests/ntos_mm/ZwCreateSection.c (working copy) @@ -0,0 +1,521 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Kernel-Mode Test Suite ZwCreateSection + * PROGRAMMER: Nikolay Borisov + */ + +#include + +#define IGNORE -999 +#define NO_HANDLE_CLOSE -998 +#define _4mb 4194304 +extern const char TestString[]; +extern const SIZE_T TestStringSize; +static UNICODE_STRING FileReadOnlyPath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\ntdll.dll"); +static UNICODE_STRING WritableFilePath = RTL_CONSTANT_STRING(L"\\SystemRoot\\kmtest-MmSection.txt"); +static UNICODE_STRING NtosImgPath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\calc.exe"); +static OBJECT_ATTRIBUTES NtdllObject; +static OBJECT_ATTRIBUTES KmtestFileObject; +static OBJECT_ATTRIBUTES NtoskrnlFileObject; + +#define CREATE_SECTION(Handle, DesiredAccess, Attributes, Size, SectionPageProtection, AllocationAttributes, FileHandle, RetStatus, CloseRetStatus) do \ +{ \ + Status = ZwCreateSection(&Handle, DesiredAccess, Attributes, &Size, SectionPageProtection, AllocationAttributes, FileHandle); \ + ok_eq_hex(Status, RetStatus); \ + if (NT_SUCCESS(Status)) \ + { \ + if (CloseRetStatus != NO_HANDLE_CLOSE) \ + { \ + Status = ZwClose(Handle); \ + Handle = NULL; \ + if (CloseRetStatus != IGNORE) ok_eq_hex(Status, CloseRetStatus); \ + } \ + } \ +} while (0) + +#define TestMapView(SectionHandle, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect, MapStatus, UnmapStatus) do \ +{ \ + Status = ZwMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect); \ + ok_eq_hex(Status, MapStatus); \ + if (NT_SUCCESS(Status)) \ + { \ + Status = ZwUnmapViewOfSection(ProcessHandle, BaseAddress); \ + if(UnmapStatus != IGNORE) ok_eq_hex(Status, UnmapStatus); \ + *BaseAddress2 = NULL; \ + *ViewSize2 = 0; \ + } \ +} while (0) + +#define CheckObject(Handle, Pointers, Handles) do \ +{ \ + PUBLIC_OBJECT_BASIC_INFORMATION ObjectInfo; \ + Status = ZwQueryObject(Handle, ObjectBasicInformation, \ + &ObjectInfo, sizeof ObjectInfo, NULL); \ + ok_eq_hex(Status, STATUS_SUCCESS); \ + ok_eq_ulong(ObjectInfo.PointerCount, Pointers); \ + ok_eq_ulong(ObjectInfo.HandleCount, Handles); \ +} while (0) + + +#define CheckSection(SectionHandle, SectionFlag, SectionSize, RetStatus) do \ +{ \ + SECTION_BASIC_INFORMATION Sbi; \ + NTSTATUS Status; \ + Status = ZwQuerySection(SectionHandle, SectionBasicInformation, \ + &Sbi, sizeof Sbi, NULL); \ + ok_eq_hex(Status, RetStatus); \ + if (RetStatus == STATUS_SUCCESS && NT_SUCCESS(Status)) \ + { \ + ok_eq_pointer(Sbi.BaseAddress, NULL); \ + ok_eq_longlong(Sbi.Size.QuadPart, SectionSize); \ + ok_eq_hex(Sbi.Attributes, SectionFlag | SEC_FILE); \ + } \ +} while (0) + +static +VOID +FileSectionViewPermissionCheck(HANDLE ReadOnlyFile, HANDLE WriteOnlyFile, HANDLE ExecutableFile) +{ + NTSTATUS Status; + HANDLE SectionHandle = NULL; + PVOID BaseAddress = NULL; + SIZE_T ViewSize = 0; + LARGE_INTEGER MaximumSize; + + MaximumSize.QuadPart = TestStringSize; + + //READ-ONLY FILE COMBINATIONS + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_EXECUTE, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SUCCESS, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_EXECUTE, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SUCCESS, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_EXECUTE, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SUCCESS, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, ReadOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + //WRITE-ONLY FILE COMBINATIONS + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_EXECUTE, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SUCCESS, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_EXECUTE, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SUCCESS, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_EXECUTE, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SUCCESS, STATUS_SUCCESS); + ZwClose(SectionHandle); + + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, WriteOnlyFile, STATUS_SUCCESS, NO_HANDLE_CLOSE); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(SectionHandle, ZwCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, STATUS_SUCCESS); + ZwClose(SectionHandle); + + //EXECUTE ONLY FILE + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_EXECUTE, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(SectionHandle, SECTION_MAP_READ, NULL, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_EXECUTE, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(SectionHandle, SECTION_MAP_WRITE, NULL, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_EXECUTE, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(SectionHandle, SECTION_MAP_EXECUTE, NULL, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, ExecutableFile, STATUS_SUCCESS, STATUS_SUCCESS); +} + +static +VOID +KmtInitTestFiles(PHANDLE ReadOnlyFile, PHANDLE WriteOnlyFile, PHANDLE ExecutableFile) +{ + NTSTATUS Status; + LARGE_INTEGER FileOffset; + IO_STATUS_BLOCK IoStatusBlock; + + //INIT THE READ-ONLY FILE + Status = ZwCreateFile(ReadOnlyFile, ( GENERIC_READ | GENERIC_EXECUTE ), &NtdllObject, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0); + ok_eq_hex(Status, STATUS_SUCCESS); + ok(*ReadOnlyFile != NULL, "Couldn't acquire READONLY handle\n"); + + //INIT THE EXECUTABLE FILE + Status = ZwCreateFile(ExecutableFile, GENERIC_EXECUTE, &NtoskrnlFileObject, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0); + ok_eq_hex(Status, STATUS_SUCCESS); + ok(*ExecutableFile != NULL, "Couldn't acquire EXECUTE handle\n"); + + //INIT THE WRITE-ONLY FILE + //NB: this file is deleted at the end of basic behavior checks + Status = ZwCreateFile(WriteOnlyFile, (GENERIC_WRITE | SYNCHRONIZE), &KmtestFileObject, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_SUPERSEDE, FILE_NON_DIRECTORY_FILE, NULL, 0); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_eq_ulongptr(IoStatusBlock.Information, FILE_CREATED); + ok(*WriteOnlyFile != NULL, "WriteOnlyFile is NULL\n"); + if (WriteOnlyFile) + { + FileOffset.QuadPart = 0; + Status = ZwWriteFile(*WriteOnlyFile, NULL, NULL, NULL, &IoStatusBlock, (PVOID)TestString, TestStringSize, &FileOffset, NULL); + ok(Status == STATUS_SUCCESS || Status == STATUS_PENDING, "Status = 0x%08lx\n", Status); + Status = ZwWaitForSingleObject(*WriteOnlyFile, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_eq_ulongptr(IoStatusBlock.Information, TestStringSize); + } +} + +static +VOID +SimpleErrorChecks(HANDLE FileHandleReadOnly, HANDLE FileHandleWriteOnly, HANDLE FileHandleExecuteOnly) +{ + NTSTATUS Status; + HANDLE Section = NULL; + OBJECT_ATTRIBUTES ObjectAttributesReadOnly; + OBJECT_ATTRIBUTES ObjectAttributesWriteOnly; + OBJECT_ATTRIBUTES InvalidObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + FILE_STANDARD_INFORMATION FileStandardInfo; + LARGE_INTEGER MaximumSize; + UNICODE_STRING SectReadOnly = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\KmtTestReadSect"); + UNICODE_STRING SectWriteOnly = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\KmtTestWriteSect"); + UNICODE_STRING InvalidObjectString = RTL_CONSTANT_STRING(L"THIS/IS/INVALID"); + + MaximumSize.QuadPart = TestStringSize; + + InitializeObjectAttributes(&ObjectAttributesReadOnly, &SectReadOnly, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + InitializeObjectAttributes(&ObjectAttributesWriteOnly, &SectWriteOnly, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + InitializeObjectAttributes(&InvalidObjectAttributes, &InvalidObjectString, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + + /////////////////////////////////////////////////////////////////////////////////////// + //PAGE FILE BACKED SECTION + //DESIRED ACCESS TESTS + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, NULL, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, 0, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, NULL, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, -1, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, NULL, STATUS_SUCCESS, STATUS_SUCCESS); + + //OBJECT ATTRIBUTES + CREATE_SECTION(Section, SECTION_ALL_ACCESS, &ObjectAttributesReadOnly, MaximumSize, PAGE_READWRITE, SEC_COMMIT, NULL, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, &InvalidObjectAttributes, MaximumSize, PAGE_READWRITE, SEC_COMMIT, NULL, STATUS_OBJECT_PATH_SYNTAX_BAD, STATUS_SUCCESS); + + //MAXIMUM SIZE + MaximumSize.QuadPart = -1; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, NULL, STATUS_SECTION_TOO_BIG, IGNORE); + + MaximumSize.QuadPart = 0; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_COMMIT, NULL, STATUS_INVALID_PARAMETER_4, IGNORE); + + //division by zero in ROS + if (!skip((SharedUserData->LargePageMinimum > 0), "LargePageMinimum is 0")) + { + MaximumSize.QuadPart = (_4mb / SharedUserData->LargePageMinimum) * SharedUserData->LargePageMinimum; //4mb + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_LARGE_PAGES | SEC_COMMIT), NULL, STATUS_SUCCESS, STATUS_SUCCESS); + } + + MaximumSize.QuadPart = TestStringSize; + + //SECTION PAGE PROTECTION + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_READ, SEC_COMMIT, NULL, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_WRITECOPY, SEC_COMMIT, NULL, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, NULL, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, (PAGE_EXECUTE_READ | PAGE_READWRITE), SEC_COMMIT, NULL, STATUS_INVALID_PAGE_PROTECTION, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, (PAGE_READONLY | PAGE_READWRITE), SEC_COMMIT, NULL, STATUS_INVALID_PAGE_PROTECTION, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, (PAGE_WRITECOPY | PAGE_READONLY), SEC_COMMIT, NULL, STATUS_INVALID_PAGE_PROTECTION, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, 0, SEC_COMMIT, NULL, STATUS_INVALID_PAGE_PROTECTION, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, -1, SEC_COMMIT, NULL, STATUS_INVALID_PAGE_PROTECTION, STATUS_SUCCESS); + + //ALLOCATION ATTRIBUTES + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, 0, NULL, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_COMMIT | SEC_RESERVE), NULL, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_RESERVE, NULL, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_IMAGE, NULL, STATUS_INVALID_FILE_FOR_SECTION, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_IMAGE | SEC_COMMIT), NULL, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, -1, NULL, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_LARGE_PAGES, NULL, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_LARGE_PAGES | SEC_COMMIT), NULL, STATUS_INVALID_PARAMETER_4, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_NOCACHE, NULL, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_NOCACHE | SEC_RESERVE | SEC_COMMIT), NULL, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_NOCACHE | SEC_COMMIT), NULL, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_NOCACHE | SEC_RESERVE), NULL, STATUS_SUCCESS, STATUS_SUCCESS); + + ///////////////////////////////////////////////////////////////////////////////////////////// + //NORMAL FILE-BACKED SECTION + + //DESIRED ACCESS TESTS + CREATE_SECTION(Section, SECTION_ALL_ACCESS, &ObjectAttributesReadOnly, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleReadOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, &ObjectAttributesWriteOnly, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_MAP_WRITE, &ObjectAttributesReadOnly, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleReadOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_MAP_READ, &ObjectAttributesWriteOnly, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + + //Object Attributes + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleReadOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, &InvalidObjectAttributes, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleReadOnly, STATUS_OBJECT_PATH_SYNTAX_BAD, IGNORE); + + //MAXIMUM SIZE + MaximumSize.QuadPart = TestStringSize - 100; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + + MaximumSize.QuadPart = -1; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleWriteOnly, STATUS_SECTION_TOO_BIG, IGNORE); + + MaximumSize.QuadPart = TestStringSize + 1; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleWriteOnly, STATUS_SECTION_TOO_BIG, IGNORE); + + MaximumSize.QuadPart = 0; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + + //SECTION PAGE PROTECTION + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_READ, SEC_COMMIT, FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_WRITECOPY, SEC_COMMIT, FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, (PAGE_EXECUTE_READ | PAGE_READWRITE), SEC_COMMIT, FileHandleWriteOnly, STATUS_INVALID_PAGE_PROTECTION, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, (PAGE_READONLY | PAGE_READWRITE), SEC_COMMIT, FileHandleWriteOnly, STATUS_INVALID_PAGE_PROTECTION, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, (PAGE_WRITECOPY | PAGE_READONLY), SEC_COMMIT, FileHandleWriteOnly, STATUS_INVALID_PAGE_PROTECTION, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, 0, SEC_COMMIT, FileHandleWriteOnly, STATUS_INVALID_PAGE_PROTECTION, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, -1, SEC_COMMIT, FileHandleWriteOnly, STATUS_INVALID_PAGE_PROTECTION, STATUS_SUCCESS); + + //allocation type + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, 0, FileHandleWriteOnly, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_COMMIT | SEC_RESERVE), FileHandleWriteOnly, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_RESERVE, FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_IMAGE | SEC_COMMIT), FileHandleWriteOnly, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, -1, FileHandleWriteOnly, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_LARGE_PAGES, FileHandleWriteOnly, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_LARGE_PAGES | SEC_COMMIT), FileHandleWriteOnly, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_NOCACHE, FileHandleWriteOnly, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_NOCACHE | SEC_RESERVE | SEC_COMMIT), FileHandleWriteOnly, STATUS_INVALID_PARAMETER_6, IGNORE); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_NOCACHE | SEC_COMMIT), FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, (SEC_NOCACHE | SEC_RESERVE), FileHandleWriteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READWRITE, SEC_IMAGE, FileHandleWriteOnly, STATUS_INVALID_IMAGE_NOT_MZ, IGNORE); + + ////////////////////////////////////////////////// + //EXECUTABLE IMAGE + CREATE_SECTION(Section, SECTION_MAP_READ, &ObjectAttributesWriteOnly, MaximumSize, PAGE_WRITECOPY, SEC_IMAGE, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_MAP_EXECUTE, &ObjectAttributesWriteOnly, MaximumSize, PAGE_WRITECOPY, SEC_IMAGE, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + + //DESIRED ACCESS TESTS + CREATE_SECTION(Section, SECTION_ALL_ACCESS, &ObjectAttributesReadOnly, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, &ObjectAttributesWriteOnly, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_MAP_WRITE, &ObjectAttributesReadOnly, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_MAP_READ, &ObjectAttributesWriteOnly, MaximumSize, PAGE_WRITECOPY, SEC_COMMIT, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + + //Object Attributes + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + CREATE_SECTION(Section, SECTION_ALL_ACCESS, &InvalidObjectAttributes, MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleExecuteOnly, STATUS_OBJECT_PATH_SYNTAX_BAD, IGNORE); + + //MaximumSize + Status = ZwQueryInformationFile(FileHandleExecuteOnly, &IoStatusBlock, &FileStandardInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); + if (!skip(NT_SUCCESS(Status), "Cannot query file information")) + { + //as big as file + MaximumSize = FileStandardInfo.AllocationSize; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_READ, SEC_IMAGE, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + + //less than file + MaximumSize.QuadPart = FileStandardInfo.AllocationSize.QuadPart - 2; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_READ, SEC_IMAGE, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + + //larger than file + MaximumSize.QuadPart = FileStandardInfo.AllocationSize.QuadPart + 2; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_READ, SEC_IMAGE, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + + //0 + MaximumSize.QuadPart = 0; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_READ, SEC_IMAGE, FileHandleExecuteOnly, STATUS_SUCCESS, STATUS_SUCCESS); + + //-1 (very big number) + MaximumSize.QuadPart = -1; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, MaximumSize, PAGE_EXECUTE_READ, SEC_IMAGE, FileHandleExecuteOnly, STATUS_SECTION_TOO_BIG, IGNORE); + } +} + +static +VOID +BasicBehaviorChecks(HANDLE FileHandle) +{ + NTSTATUS Status; + HANDLE Section = NULL; + PFILE_OBJECT FileObject; + LARGE_INTEGER Length; + Length.QuadPart = TestStringSize; + + //mimic lack of section support for a particular file as well. + Status = ObReferenceObjectByHandle(FileHandle, STANDARD_RIGHTS_ALL, IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL); + if (!skip(NT_SUCCESS(Status), "Cannot reference object by handle\n")) + { + PSECTION_OBJECT_POINTERS Pointers = FileObject->SectionObjectPointer; + + FileObject->SectionObjectPointer = NULL; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, Length, PAGE_READONLY, SEC_COMMIT, FileHandle, STATUS_INVALID_FILE_FOR_SECTION, IGNORE); + FileObject->SectionObjectPointer = Pointers; + ObDereferenceObject(FileObject); + } + + Length.QuadPart = TestStringSize; + CREATE_SECTION(Section, (SECTION_ALL_ACCESS), NULL, Length, PAGE_READONLY, SEC_COMMIT, FileHandle, STATUS_SUCCESS, NO_HANDLE_CLOSE); + CheckObject(Section, 2, 1); + CheckSection(Section, SEC_FILE, Length.QuadPart, STATUS_SUCCESS); + ZwClose(Section); //manually close it due to NO_HANDLE_CLOSE in CREATE_SECTION + + //section length should be set to that of file + Length.QuadPart = 0; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, Length, PAGE_READONLY, SEC_COMMIT, FileHandle, STATUS_SUCCESS, NO_HANDLE_CLOSE); + CheckSection(Section, SEC_FILE, TestStringSize, STATUS_SUCCESS); + ZwClose(Section); + + //create a smaller section than file + Length.QuadPart = TestStringSize - 100; + CREATE_SECTION(Section, SECTION_ALL_ACCESS, NULL, Length, PAGE_READONLY, SEC_COMMIT, FileHandle, STATUS_SUCCESS, NO_HANDLE_CLOSE); + CheckSection(Section, SEC_FILE, TestStringSize - 100, STATUS_SUCCESS); + ZwClose(Section); +} + + +START_TEST(ZwCreateSection) +{ + HANDLE FileHandleReadOnly = NULL; + HANDLE FileHandleWriteOnly = NULL; + HANDLE FileHandleExecuteOnly = NULL; + + InitializeObjectAttributes(&NtdllObject, &FileReadOnlyPath, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + InitializeObjectAttributes(&KmtestFileObject, &WritableFilePath, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + InitializeObjectAttributes(&NtoskrnlFileObject, &NtosImgPath, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + + KmtInitTestFiles(&FileHandleReadOnly, &FileHandleWriteOnly, &FileHandleExecuteOnly); + + FileSectionViewPermissionCheck(FileHandleReadOnly, FileHandleWriteOnly, FileHandleExecuteOnly); + SimpleErrorChecks(FileHandleReadOnly, FileHandleWriteOnly, FileHandleExecuteOnly); + BasicBehaviorChecks(FileHandleWriteOnly); + + if (FileHandleReadOnly) + ZwClose(FileHandleReadOnly); + + if (FileHandleWriteOnly) + { + ZwClose(FileHandleWriteOnly); + ZwDeleteFile(&KmtestFileObject); + } + + if (FileHandleExecuteOnly) + ZwClose(FileHandleExecuteOnly); +} Index: kmtests/ntos_mm/ZwMapViewOfSection.c =================================================================== --- kmtests/ntos_mm/ZwMapViewOfSection.c (revision 0) +++ kmtests/ntos_mm/ZwMapViewOfSection.c (working copy) @@ -0,0 +1,564 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Kernel-Mode Test Suite ZwMapViewOfSection + * PROGRAMMER: Nikolay Borisov + */ + +#include + +#define IGNORE -99 +#define NEW_CONTENT "NewContent" +#define NEW_CONTENT_LEN sizeof(NEW_CONTENT) + +static UNICODE_STRING FileReadOnlyPath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\ntdll.dll"); +static UNICODE_STRING NtosImgPath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\ntoskrnl.exe"); +static UNICODE_STRING WritableFilePath = RTL_CONSTANT_STRING(L"\\SystemRoot\\kmtest-MmSection.txt"); +static UNICODE_STRING SharedSectionName = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\kmtest-SharedSection"); +extern const char TestString[]; +extern const SIZE_T TestStringSize; +static OBJECT_ATTRIBUTES NtdllObject; +static OBJECT_ATTRIBUTES KmtestFileObject; +static OBJECT_ATTRIBUTES NtoskrnlFileObject; + +#define TestMapView(SectionHandle, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect, MapStatus, UnmapStatus) do \ + { \ + Status = ZwMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect); \ + ok_eq_hex(Status, MapStatus); \ + if (NT_SUCCESS(Status)) \ + { \ + Status = ZwUnmapViewOfSection(ProcessHandle, BaseAddress); \ + if (UnmapStatus != IGNORE) ok_eq_hex(Status, UnmapStatus); \ + *BaseAddress2 = NULL; \ + *ViewSize2 = 0; \ + } \ + } while (0) \ + +#define MmTestMapView(Object, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect, MapStatus, UnmapStatus) do \ + { \ + Status = MmMapViewOfSection(Object, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect); \ + ok_eq_hex(Status, MapStatus); \ + if (NT_SUCCESS(Status)) \ + { \ + Status = MmUnmapViewOfSection(ProcessHandle, BaseAddress); \ + if (UnmapStatus != IGNORE) ok_eq_hex(Status, UnmapStatus); \ + *BaseAddress2 = NULL; \ + *ViewSize2 = 0; \ + } \ + } while (0) \ + +#define CheckObject(Handle, Pointers, Handles) do \ +{ \ + PUBLIC_OBJECT_BASIC_INFORMATION ObjectInfo; \ + Status = ZwQueryObject(Handle, ObjectBasicInformation, \ + &ObjectInfo, sizeof ObjectInfo, NULL); \ + ok_eq_hex(Status, STATUS_SUCCESS); \ + ok_eq_ulong(ObjectInfo.PointerCount, Pointers); \ + ok_eq_ulong(ObjectInfo.HandleCount, Handles); \ +} while (0) \ + +static +VOID +KmtInitTestFiles(PHANDLE ReadOnlyFile, PHANDLE WriteOnlyFile, PHANDLE ExecutableFile) +{ + NTSTATUS Status; + LARGE_INTEGER FileOffset; + IO_STATUS_BLOCK IoStatusBlock; + + //INIT THE READ-ONLY FILE + Status = ZwCreateFile(ReadOnlyFile, GENERIC_READ, &NtdllObject, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0); + ok_eq_hex(Status, STATUS_SUCCESS); + ok(*ReadOnlyFile != NULL, "Couldn't acquire READONLY handle\n"); + + //INIT THE EXECUTABLE FILE + Status = ZwCreateFile(ExecutableFile, GENERIC_EXECUTE, &NtdllObject, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0); + ok_eq_hex(Status, STATUS_SUCCESS); + ok(*ExecutableFile != NULL, "Couldn't acquire EXECUTE handle\n"); + + //INIT THE WRITE-ONLY FILE + //TODO: Delete the file when the tests are all executed + Status = ZwCreateFile(WriteOnlyFile, (GENERIC_WRITE | SYNCHRONIZE), &KmtestFileObject, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_SUPERSEDE, (FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE), NULL, 0); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_eq_ulongptr(IoStatusBlock.Information, FILE_CREATED); + ok(*WriteOnlyFile != NULL, "WriteOnlyFile is NULL\n"); + if (WriteOnlyFile) + { + FileOffset.QuadPart = 0; + Status = ZwWriteFile(*WriteOnlyFile, NULL, NULL, NULL, &IoStatusBlock, (PVOID)TestString, TestStringSize, &FileOffset, NULL); + ok(Status == STATUS_SUCCESS || Status == STATUS_PENDING, "Status = 0x%08lx\n", Status); + Status = ZwWaitForSingleObject(*WriteOnlyFile, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_eq_ulongptr(IoStatusBlock.Information, TestStringSize); + } +} + +static +VOID +SimpleErrorChecks(HANDLE FileHandleReadOnly, HANDLE FileHandleWriteOnly, HANDLE ExecutableImg) +{ + NTSTATUS Status; + HANDLE WriteSectionHandle; + HANDLE ReadOnlySection; + HANDLE PageFileSectionHandle; + LARGE_INTEGER MaximumSize; + LARGE_INTEGER SectionOffset; + SIZE_T AllocSize = TestStringSize; + SIZE_T ViewSize = 0; + PVOID BaseAddress = NULL; + PVOID AllocBase = NULL; + MaximumSize.QuadPart = TestStringSize; + + //Used for parameters working on file-based section + Status = ZwCreateSection(&WriteSectionHandle, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_READWRITE, SEC_COMMIT, FileHandleWriteOnly); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = ZwCreateSection(&ReadOnlySection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleReadOnly); + ok_eq_hex(Status, STATUS_SUCCESS); + + //Used for parameters taking effect only on page-file backed section + MaximumSize.QuadPart = 5 * MM_ALLOCATION_GRANULARITY; + Status = ZwCreateSection(&PageFileSectionHandle, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_READWRITE, SEC_COMMIT, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + MaximumSize.QuadPart = TestStringSize; + + //section handle + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView((HANDLE)0xDEADBEEF, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE); + TestMapView(INVALID_HANDLE_VALUE, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_OBJECT_TYPE_MISMATCH, IGNORE); + TestMapView(NULL, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE); + + //process handle + TestMapView(WriteSectionHandle, (HANDLE)0xDEADBEEF, &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE); + TestMapView(WriteSectionHandle, (HANDLE)NULL, &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE); + + //base address + BaseAddress = (PVOID)0x00567A20; + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_MAPPED_ALIGNMENT, IGNORE); + + BaseAddress = (PVOID) 0x60000000; + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + + BaseAddress = (PVOID)((char *)MmSystemRangeStart + 200); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_3, IGNORE); + + //try mapping section to an already mapped address + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &AllocBase, 0, &AllocSize, MEM_COMMIT, PAGE_READWRITE); + if (!skip(NT_SUCCESS(Status), "Cannot allocate memory\n")) + { + BaseAddress = AllocBase; + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_CONFLICTING_ADDRESSES, IGNORE); + Status = ZwFreeVirtualMemory(NtCurrentProcess(), &AllocBase, &AllocSize, MEM_RELEASE); + ok_eq_hex(Status, STATUS_SUCCESS); + } + + //zero bits + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 1, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 5, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, -1, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_4, IGNORE); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 20, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_NO_MEMORY, IGNORE); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 21, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_NO_MEMORY, IGNORE); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 22, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_4, IGNORE); + + //commit size + TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 500, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, -1, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, IGNORE); + TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0x10000000, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, IGNORE); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 500, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, IGNORE); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 500, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + + //section offset + SectionOffset.QuadPart = 0; + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + ok_eq_ulonglong(SectionOffset.QuadPart, 0); + + SectionOffset.QuadPart = 0x00040211; //MSDN is wrong, in w2k3 the ZwMapViewOfSection doesn't align offsets automatically + TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 500, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_MAPPED_ALIGNMENT, IGNORE); + + SectionOffset.QuadPart = -1; + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_MAPPED_ALIGNMENT, IGNORE); + + //View Size + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + + ViewSize = -1; + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_3, IGNORE); + + ViewSize = TestStringSize+1; + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_VIEW_SIZE, IGNORE); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + + ViewSize = TestStringSize; + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + + ViewSize = TestStringSize-1; + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + + //allocation type + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_INVALID_PARAMETER_9, STATUS_SUCCESS); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, (MEM_RESERVE | MEM_COMMIT), PAGE_READWRITE, STATUS_INVALID_PARAMETER_9, IGNORE); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, (MEM_LARGE_PAGES | MEM_RESERVE), PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS); + + //win32protect + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_NOACCESS, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE_WRITECOPY, STATUS_SECTION_PROTECTION, IGNORE); + TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, IGNORE); + TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_WRITECOPY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE_READ, STATUS_SECTION_PROTECTION, IGNORE); + TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, IGNORE); + TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_NOACCESS, STATUS_SUCCESS, STATUS_SUCCESS); + TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, (PAGE_READWRITE | PAGE_READONLY), STATUS_INVALID_PAGE_PROTECTION, IGNORE); + TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READONLY, STATUS_SECTION_PROTECTION, IGNORE); + + ZwClose(WriteSectionHandle); + ZwClose(PageFileSectionHandle); + ZwClose(ReadOnlySection); +} + + +static +VOID +AdvancedErrorChecks(HANDLE FileHandleReadOnly, HANDLE FileHandleWriteOnly) +{ + NTSTATUS Status; + PVOID BaseAddress; + HANDLE FileSectionHandle; + LARGE_INTEGER SectionOffset; + LARGE_INTEGER MaximumSize; + SIZE_T ViewSize = 0; + PVOID SectionObject; + + MaximumSize.QuadPart = TestStringSize; + //Used for parameters working on file-based section + Status = ZwCreateSection(&FileSectionHandle, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_READWRITE, SEC_COMMIT, FileHandleWriteOnly); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = ObReferenceObjectByHandle(FileSectionHandle, + STANDARD_RIGHTS_ALL, + NULL, + KernelMode, + &SectionObject, + NULL); + + ok_eq_hex(Status, STATUS_SUCCESS); + + //Bypassing Zw function calls mean bypassing the alignment checks which are not crucial for the branches being tested here + + //test first conditional branch + ViewSize = -1; + MmTestMapView(SectionObject, PsGetCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_INVALID_VIEW_SIZE, IGNORE); + + //test second conditional branch + ViewSize = 1; + SectionOffset.QuadPart = TestStringSize; + MmTestMapView(SectionObject, PsGetCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_VIEW_SIZE, IGNORE); + + ObDereferenceObject(SectionObject); + ZwClose(FileSectionHandle); +} + +static +SIZE_T +CompareFileContents(HANDLE FileHandle, SIZE_T BufferLength, PVOID Buffer) +{ + NTSTATUS Status; + LARGE_INTEGER ByteOffset; + IO_STATUS_BLOCK IoStatusBlock; + PVOID FileContent; + SIZE_T Match; + + Match = 0; + ByteOffset.QuadPart = 0; + + FileContent = ExAllocatePoolWithTag(PagedPool, BufferLength, 'Test'); + if (!skip((FileContent != NULL), "Error allocating memory for FileContent\n")) + { + Status = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, FileContent, BufferLength, &ByteOffset, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_eq_ulongptr(IoStatusBlock.Information, BufferLength); + + Match = 0; + Match = RtlCompareMemory(FileContent, Buffer, BufferLength); + ExFreePoolWithTag(FileContent, 'Test'); + } + + return Match; +} + + +static +VOID +NTAPI +SystemProcessWorker(PVOID StartContext) +{ + NTSTATUS Status; + PVOID BaseAddress; + HANDLE SectionHandle; + SIZE_T ViewSize; + SIZE_T Match; + LARGE_INTEGER SectionOffset; + OBJECT_ATTRIBUTES ObjectAttributes; + + UNREFERENCED_PARAMETER(StartContext); + + BaseAddress = NULL; + ViewSize = TestStringSize; + SectionOffset.QuadPart = 0; + + InitializeObjectAttributes(&ObjectAttributes, &SharedSectionName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + Status = ZwOpenSection(&SectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes); + if (!skip(NT_SUCCESS(Status), "Error acquiring handle to section. Error = %p\n", Status)) + { + CheckObject(SectionHandle, 4, 2); + Status = ZwMapViewOfSection(SectionHandle, NtCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE); + + //make sure ZwMapViewofSection doesn't touch the section ref counts. + CheckObject(SectionHandle, 4, 2); + + if (!skip(NT_SUCCESS(Status), "Error mapping page file view in system process. Error = %p\n", Status)) + { + Match = RtlCompareMemory(BaseAddress, TestString, TestStringSize); + ok_eq_size(Match, TestStringSize); + + RtlCopyMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN); + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + + //make sure ZwMapViewofSection doesn't touch the section ref counts. + CheckObject(SectionHandle, 4, 2); + } + + ZwClose(SectionHandle); + } + + PsTerminateSystemThread(STATUS_SUCCESS); +} + + +static +VOID +BehaviorChecks(HANDLE FileHandleReadOnly, HANDLE FileHandleWriteOnly) +{ + NTSTATUS Status; + PVOID BaseAddress = NULL; + PVOID ThreadObject; + HANDLE WriteSectionHandle; + HANDLE SysThreadHandle; + OBJECT_ATTRIBUTES ObjectAttributes; + LARGE_INTEGER SectionOffset; + LARGE_INTEGER MaximumSize; + SIZE_T Match; + SIZE_T ViewSize = 0; + + InitializeObjectAttributes(&ObjectAttributes, &SharedSectionName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + MaximumSize.QuadPart = TestStringSize; + SectionOffset.QuadPart = 0; + + Status = ZwCreateSection(&WriteSectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes, &MaximumSize, PAGE_READWRITE, SEC_COMMIT, FileHandleWriteOnly); + CheckObject(WriteSectionHandle, 3, 1); + ok(NT_SUCCESS(Status), "Error creating write section from file. Error = %p\n", Status); + + //check for section reading/writing by comparing section content to a well-known value. + Status = ZwMapViewOfSection(WriteSectionHandle, NtCurrentProcess() ,&BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE); + CheckObject(WriteSectionHandle, 3, 1); + if (!skip(NT_SUCCESS(Status), "Error mapping view with READ/WRITE priv. Error = %p\n", Status)) + { + Match = RtlCompareMemory(BaseAddress, TestString, TestStringSize); + ok_eq_size(Match, TestStringSize); + + //now check writing to section + RtlCopyMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN); + + Match = RtlCompareMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN); + ok_eq_size(Match, NEW_CONTENT_LEN); + + //check to see if the contents have been flushed to the actual file on disk. + Match = CompareFileContents(FileHandleWriteOnly, NEW_CONTENT_LEN, NEW_CONTENT); + ok_eq_size(Match, NEW_CONTENT_LEN); + + //bring everything back to normal + RtlCopyMemory(BaseAddress, TestString, TestStringSize); + + //Initiate an external thread to modify the file + InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + Status = PsCreateSystemThread(&SysThreadHandle, STANDARD_RIGHTS_ALL, &ObjectAttributes, NULL, NULL, SystemProcessWorker, NULL); + if (!skip(NT_SUCCESS(Status), "Error creating System thread. Error = %p\n", Status)) + { + Status = ObReferenceObjectByHandle(SysThreadHandle, THREAD_ALL_ACCESS, PsThreadType, KernelMode, &ThreadObject, NULL); + if (!skip(NT_SUCCESS(Status), "Error getting reference to System thread when testing file-backed section\n")) + { + //wait until the system thread actually terminates + KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, NULL); + + //no longer need the thread object + ObDereferenceObject(ThreadObject); + + //test for bi-directional access to the shared page file + Match = RtlCompareMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN); + ok_eq_size(Match, NEW_CONTENT_LEN); + + //bring everything back to normal, again + RtlCopyMemory(BaseAddress, TestString, TestStringSize); + } + } + + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + + } + + //Try to write to read-only mapped view + BaseAddress = NULL; + ViewSize = 0; + SectionOffset.QuadPart = 0; + Status = ZwMapViewOfSection(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READONLY); + if (!skip(NT_SUCCESS(Status), "Error mapping view with READ priv. Error = %p\n", Status)) + { + NTSTATUS ExceptionStatus; + + Match = RtlCompareMemory(BaseAddress, TestString, TestStringSize); + ok_eq_size(Match, TestStringSize); + + KmtStartSeh() + RtlCopyMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN); + KmtEndSeh(STATUS_ACCESS_VIOLATION); + + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + + //try to access forbidden memory + BaseAddress = NULL; + ViewSize = 0; + SectionOffset.QuadPart = 0; + Status = ZwMapViewOfSection(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_NOACCESS); + if (!skip(NT_SUCCESS(Status), "Error mapping view with PAGE_NOACCESS priv. Error = %p\n", Status)) + { + NTSTATUS ExceptionStatus; + + KmtStartSeh() + RtlCompareMemory(BaseAddress, TestString, TestStringSize); + KmtEndSeh(STATUS_ACCESS_VIOLATION); + + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + + ZwClose(WriteSectionHandle); + + //section created with sec_reserve should not be commited. + BaseAddress = NULL; + ViewSize = 0; + SectionOffset.QuadPart = 0; + Status = ZwCreateSection(&WriteSectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes, &MaximumSize, PAGE_READWRITE, SEC_RESERVE, FileHandleWriteOnly); + if (!skip(NT_SUCCESS(Status), "Error creating page file section. Error = %p\n", Status)) + { + Status = ZwMapViewOfSection(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE); + if (!skip(NT_SUCCESS(Status), "Error mapping page file view. Error = %p\n", Status)) + { + //check also the SEC_COMMIT flag + /* This test proves that MSDN is once again wrong + * msdn.microsoft.com/en-us/library/windows/hardware/aa366537.aspx states that SEC_RESERVE + * should cause the allocated memory for the view to be reserved but in fact it is always committed. + * It fails also on windows. + */ + Test_NtQueryVirtualMemory(BaseAddress, PAGE_SIZE, MEM_RESERVE, PAGE_READWRITE); + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + + ZwClose(WriteSectionHandle); + } +} + + +static +VOID +PageFileBehaviorChecks() +{ + NTSTATUS Status; + LARGE_INTEGER MaxSectionSize; + LARGE_INTEGER SectionOffset; + HANDLE PageFileSectionHandle; + PVOID BaseAddress; + SIZE_T ViewSize; + SIZE_T Match; + PVOID ThreadObject; + OBJECT_ATTRIBUTES ObjectAttributes; + + MaxSectionSize.QuadPart = TestStringSize; + SectionOffset.QuadPart = 0; + PageFileSectionHandle = INVALID_HANDLE_VALUE; + BaseAddress = NULL; + ViewSize = TestStringSize; + InitializeObjectAttributes(&ObjectAttributes, &SharedSectionName, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + + //test memory sharing between 2 different processes + Status = ZwCreateSection(&PageFileSectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes, &MaxSectionSize, PAGE_READWRITE, SEC_COMMIT, NULL); + if (!skip(NT_SUCCESS(Status), "Error creating page file section. Error = %p\n", Status)) + { + CheckObject(PageFileSectionHandle, 3, 1); + Status = ZwMapViewOfSection(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE); + if (!skip(NT_SUCCESS(Status), "Error mapping page file view. Error = %p\n", Status)) + { + HANDLE SysThreadHandle; + + CheckObject(PageFileSectionHandle, 3, 1); + + //check also the SEC_COMMIT flag + Test_NtQueryVirtualMemory(BaseAddress, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE); + + RtlCopyMemory(BaseAddress, TestString, TestStringSize); + + InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + Status = PsCreateSystemThread(&SysThreadHandle, STANDARD_RIGHTS_ALL, &ObjectAttributes, NULL, NULL, SystemProcessWorker, NULL); + + if (!skip(NT_SUCCESS(Status), "Error creating System thread. Error = %p\n", Status)) + { + Status = ObReferenceObjectByHandle(SysThreadHandle, THREAD_ALL_ACCESS, PsThreadType, KernelMode, &ThreadObject, NULL); + if (!skip(NT_SUCCESS(Status), "Error getting reference to System thread when testing pagefile-backed section\n")) + { + //wait until the system thread actually terminates + KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, NULL); + + //no longer need the thread object + ObDereferenceObject(ThreadObject); + + //test for bi-directional access to the shared page file + Match = RtlCompareMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN); + ok_eq_size(Match, NEW_CONTENT_LEN); + } + } + ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); + } + ZwClose(PageFileSectionHandle); + } +} + + +START_TEST(ZwMapViewOfSection) +{ + HANDLE FileHandleReadOnly = NULL; + HANDLE FileHandleWriteOnly = NULL; + HANDLE ExecutableFileHandle = NULL; + + InitializeObjectAttributes(&NtdllObject, &FileReadOnlyPath, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + InitializeObjectAttributes(&KmtestFileObject, &WritableFilePath, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + InitializeObjectAttributes(&NtoskrnlFileObject, &NtosImgPath, (OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE), NULL, NULL); + + KmtInitTestFiles(&FileHandleReadOnly, &FileHandleWriteOnly, &ExecutableFileHandle); + + SimpleErrorChecks(FileHandleReadOnly, FileHandleWriteOnly, ExecutableFileHandle); + AdvancedErrorChecks(FileHandleReadOnly, FileHandleWriteOnly); + BehaviorChecks(FileHandleReadOnly, FileHandleWriteOnly); + PageFileBehaviorChecks(); + + if (FileHandleReadOnly) + ZwClose(FileHandleReadOnly); + + if (FileHandleWriteOnly) + ZwClose(FileHandleWriteOnly); + + if (ExecutableFileHandle) + ZwClose(ExecutableFileHandle); +} +