mirror of
https://github.com/reactos/reactos.git
synced 2024-08-28 22:28:36 +00:00
![Thomas Faber](/assets/img/avatar_default.png)
- Show that NtMapViewOfSection validates section and process handles before checking base address alignment CORE-13113 svn path=/trunk/; revision=74390
570 lines
29 KiB
C
570 lines
29 KiB
C
/*
|
|
* PROJECT: ReactOS kernel-mode tests
|
|
* LICENSE: GPLv2+ - See COPYING in the top level directory
|
|
* PURPOSE: Kernel-Mode Test Suite ZwMapViewOfSection
|
|
* PROGRAMMER: Nikolay Borisov <nib9@aber.ac.uk>
|
|
*/
|
|
|
|
#include <kmt_test.h>
|
|
|
|
#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 ULONG 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 (!skip(*WriteOnlyFile != NULL, "No WriteOnlyFile\n"))
|
|
{
|
|
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);
|
|
|
|
//invalid section handle AND unaligned base address
|
|
BaseAddress = (PVOID)0x00567A20;
|
|
TestMapView((HANDLE)0xDEADBEEF, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE);
|
|
|
|
//invalid process handle AND unaligned base address
|
|
BaseAddress = (PVOID)0x00567A20;
|
|
TestMapView(WriteSectionHandle, (HANDLE)0xDEADBEEF, &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, 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, ULONG 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))
|
|
{
|
|
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);
|
|
}
|
|
|
|
/* FIXME: Crash. See ROSTESTS-110 */
|
|
#ifdef ROSTESTS_110_FIXED
|
|
//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))
|
|
{
|
|
KmtStartSeh()
|
|
RtlCompareMemory(BaseAddress, TestString, TestStringSize);
|
|
KmtEndSeh(STATUS_ACCESS_VIOLATION);
|
|
|
|
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
|
|
}
|
|
#endif /* ROSTESTS_110_FIXED */
|
|
|
|
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_COMMIT, 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);
|
|
}
|