1 /*
2 * PROJECT:         ReactOS kernel-mode tests
3 * LICENSE:         GPLv2+ - See COPYING in the top level directory
4 * PURPOSE:         Kernel-Mode Test Suite ZwMapViewOfSection
5 * PROGRAMMER:      Nikolay Borisov <nib9@aber.ac.uk>
6 */
7 
8 #include <kmt_test.h>
9 
10 #define IGNORE -99
11 #define NEW_CONTENT "NewContent"
12 #define NEW_CONTENT_LEN sizeof(NEW_CONTENT)
13 
14 static UNICODE_STRING FileReadOnlyPath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\ntdll.dll");
15 static UNICODE_STRING NtosImgPath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\ntoskrnl.exe");
16 static UNICODE_STRING WritableFilePath = RTL_CONSTANT_STRING(L"\\SystemRoot\\kmtest-MmSection.txt");
17 static UNICODE_STRING SharedSectionName = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\kmtest-SharedSection");
18 extern const char TestString[];
19 extern const ULONG TestStringSize;
20 static OBJECT_ATTRIBUTES NtdllObject;
21 static OBJECT_ATTRIBUTES KmtestFileObject;
22 static OBJECT_ATTRIBUTES NtoskrnlFileObject;
23 
24 #define TestMapView(SectionHandle, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect, MapStatus, UnmapStatus) do    \
25     {                                                                                                                                                                                           \
26         Status = ZwMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect);              \
27         ok_eq_hex(Status, MapStatus);                                               \
28         if (NT_SUCCESS(Status))                                                     \
29         {                                                                           \
30             Status = ZwUnmapViewOfSection(ProcessHandle, BaseAddress);              \
31             if (UnmapStatus != IGNORE) ok_eq_hex(Status, UnmapStatus);              \
32             *BaseAddress2 = NULL;                                                   \
33             *ViewSize2 = 0;                                                         \
34         }                                                                           \
35     } while (0)                                                                     \
36 
37 #define MmTestMapView(Object, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect, MapStatus, UnmapStatus) do    \
38     {                                                                                                                                                                                      \
39         Status = MmMapViewOfSection(Object, ProcessHandle, BaseAddress2, ZeroBits, CommitSize, SectionOffset, ViewSize2, InheritDisposition, AllocationType, Win32Protect);                \
40         ok_eq_hex(Status, MapStatus);                                               \
41         if (NT_SUCCESS(Status))                                                     \
42         {                                                                           \
43             Status = MmUnmapViewOfSection(ProcessHandle, BaseAddress);              \
44             if (UnmapStatus != IGNORE) ok_eq_hex(Status, UnmapStatus);              \
45             *BaseAddress2 = NULL;                                                   \
46             *ViewSize2 = 0;                                                         \
47         }                                                                           \
48     } while (0)                                                                     \
49 
50 #define CheckObject(Handle, Pointers, Handles) do                   \
51 {                                                                   \
52     PUBLIC_OBJECT_BASIC_INFORMATION ObjectInfo;                     \
53     Status = ZwQueryObject(Handle, ObjectBasicInformation,          \
54     &ObjectInfo, sizeof ObjectInfo, NULL);                          \
55     ok_eq_hex(Status, STATUS_SUCCESS);                              \
56     ok_eq_ulong(ObjectInfo.PointerCount, Pointers);                 \
57     ok_eq_ulong(ObjectInfo.HandleCount, Handles);                   \
58 } while (0)                                                         \
59 
60 static
61 VOID
62 KmtInitTestFiles(PHANDLE ReadOnlyFile, PHANDLE WriteOnlyFile, PHANDLE ExecutableFile)
63 {
64     NTSTATUS Status;
65     LARGE_INTEGER FileOffset;
66     IO_STATUS_BLOCK IoStatusBlock;
67 
68     //INIT THE READ-ONLY FILE
69     Status = ZwCreateFile(ReadOnlyFile, GENERIC_READ, &NtdllObject, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0);
70     ok_eq_hex(Status, STATUS_SUCCESS);
71     ok(*ReadOnlyFile != NULL, "Couldn't acquire READONLY handle\n");
72 
73     //INIT THE EXECUTABLE FILE
74     Status = ZwCreateFile(ExecutableFile, GENERIC_EXECUTE, &NtdllObject, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0);
75     ok_eq_hex(Status, STATUS_SUCCESS);
76     ok(*ExecutableFile != NULL, "Couldn't acquire EXECUTE handle\n");
77 
78     //INIT THE WRITE-ONLY FILE
79     //TODO: Delete the file when the tests are all executed
80     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);
81     ok_eq_hex(Status, STATUS_SUCCESS);
82     ok_eq_ulongptr(IoStatusBlock.Information, FILE_CREATED);
83     ok(*WriteOnlyFile != NULL, "WriteOnlyFile is NULL\n");
84     if (!skip(*WriteOnlyFile != NULL, "No WriteOnlyFile\n"))
85     {
86         FileOffset.QuadPart = 0;
87         Status = ZwWriteFile(*WriteOnlyFile, NULL, NULL, NULL, &IoStatusBlock, (PVOID)TestString, TestStringSize, &FileOffset, NULL);
88         ok(Status == STATUS_SUCCESS || Status == STATUS_PENDING, "Status = 0x%08lx\n", Status);
89         Status = ZwWaitForSingleObject(*WriteOnlyFile, FALSE, NULL);
90         ok_eq_hex(Status, STATUS_SUCCESS);
91         ok_eq_ulongptr(IoStatusBlock.Information, TestStringSize);
92     }
93 }
94 
95 static
96 VOID
97 SimpleErrorChecks(HANDLE FileHandleReadOnly, HANDLE FileHandleWriteOnly, HANDLE ExecutableImg)
98 {
99     NTSTATUS Status;
100     HANDLE WriteSectionHandle;
101     HANDLE ReadOnlySection;
102     HANDLE PageFileSectionHandle;
103     LARGE_INTEGER MaximumSize;
104     LARGE_INTEGER SectionOffset;
105     SIZE_T AllocSize = TestStringSize;
106     SIZE_T ViewSize = 0;
107     PVOID BaseAddress = NULL;
108     PVOID AllocBase = NULL;
109     MaximumSize.QuadPart = TestStringSize;
110 
111     //Used for parameters working on file-based section
112     Status = ZwCreateSection(&WriteSectionHandle, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_READWRITE, SEC_COMMIT, FileHandleWriteOnly);
113     ok_eq_hex(Status, STATUS_SUCCESS);
114 
115     Status = ZwCreateSection(&ReadOnlySection, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_READONLY, SEC_COMMIT, FileHandleReadOnly);
116     ok_eq_hex(Status, STATUS_SUCCESS);
117 
118     //Used for parameters taking effect only on page-file backed section
119     MaximumSize.QuadPart = 5 * MM_ALLOCATION_GRANULARITY;
120     Status = ZwCreateSection(&PageFileSectionHandle, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_READWRITE, SEC_COMMIT, NULL);
121     ok_eq_hex(Status, STATUS_SUCCESS);
122 
123     MaximumSize.QuadPart = TestStringSize;
124 
125     //section handle
126     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
127     TestMapView((HANDLE)(ULONG_PTR)0xDEADBEEFDEADBEEFull, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE);
128     TestMapView(INVALID_HANDLE_VALUE, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_OBJECT_TYPE_MISMATCH, IGNORE);
129     TestMapView(NULL, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE);
130 
131     //process handle
132     TestMapView(WriteSectionHandle, (HANDLE)(ULONG_PTR)0xDEADBEEFDEADBEEFull, &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE);
133     TestMapView(WriteSectionHandle, (HANDLE)NULL, &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE);
134 
135     //base address
136     BaseAddress = (PVOID)(ULONG_PTR)0x00567A20;
137     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_MAPPED_ALIGNMENT, IGNORE);
138 
139     BaseAddress = (PVOID)(ULONG_PTR)0x60000000;
140     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
141 
142     BaseAddress = (PVOID)((char *)MmSystemRangeStart + 200);
143     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_3, IGNORE);
144 
145     //invalid section handle AND unaligned base address
146     BaseAddress = (PVOID)(ULONG_PTR)0x00567A20;
147     TestMapView((HANDLE)(ULONG_PTR)0xDEADBEEFDEADBEEFull, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE);
148 
149     //invalid process handle AND unaligned base address
150     BaseAddress = (PVOID)(ULONG_PTR)0x00567A20;
151     TestMapView(WriteSectionHandle, (HANDLE)(ULONG_PTR)0xDEADBEEFDEADBEEFull, &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_HANDLE, IGNORE);
152 
153     //try mapping section to an already mapped address
154     Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &AllocBase, 0, &AllocSize, MEM_COMMIT, PAGE_READWRITE);
155     if (!skip(NT_SUCCESS(Status), "Cannot allocate memory\n"))
156     {
157         BaseAddress = AllocBase;
158         TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_CONFLICTING_ADDRESSES, IGNORE);
159         Status = ZwFreeVirtualMemory(NtCurrentProcess(), &AllocBase, &AllocSize, MEM_RELEASE);
160         ok_eq_hex(Status, STATUS_SUCCESS);
161     }
162 
163     //zero bits
164     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 1, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
165     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 5, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
166     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, -1, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_4, IGNORE);
167     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 20, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_NO_MEMORY, IGNORE);
168     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 21, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_NO_MEMORY, IGNORE);
169     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 22, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_4, IGNORE);
170 
171     //commit size
172     TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 500, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
173     TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
174     TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, -1, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, IGNORE);
175     TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0x10000000, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, IGNORE);
176     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 500, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_5, IGNORE);
177     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 500, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
178 
179     //section offset
180     SectionOffset.QuadPart = 0;
181     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
182     ok_eq_ulonglong(SectionOffset.QuadPart, 0);
183 
184     SectionOffset.QuadPart = 0x00040211; //MSDN is wrong, in w2k3 the ZwMapViewOfSection doesn't align offsets automatically
185     TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 500, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_MAPPED_ALIGNMENT, IGNORE);
186 
187     SectionOffset.QuadPart = -1;
188     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_MAPPED_ALIGNMENT, IGNORE);
189 
190     //View Size
191     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
192 
193     ViewSize = -1;
194     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_PARAMETER_3, IGNORE);
195 
196     ViewSize = TestStringSize+1;
197     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_VIEW_SIZE, IGNORE);
198     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
199 
200     ViewSize = TestStringSize;
201     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
202 
203     ViewSize = TestStringSize-1;
204     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
205 
206     //allocation type
207     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
208     TestMapView(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_INVALID_PARAMETER_9, STATUS_SUCCESS);
209     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, (MEM_RESERVE | MEM_COMMIT), PAGE_READWRITE, STATUS_INVALID_PARAMETER_9, IGNORE);
210     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, (MEM_LARGE_PAGES | MEM_RESERVE), PAGE_READWRITE, STATUS_SUCCESS, STATUS_SUCCESS);
211 
212     //win32protect
213     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS);
214     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_NOACCESS, STATUS_SUCCESS, STATUS_SUCCESS);
215     TestMapView(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE_WRITECOPY, STATUS_SECTION_PROTECTION, IGNORE);
216     TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_SECTION_PROTECTION, IGNORE);
217     TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_WRITECOPY, STATUS_SUCCESS, STATUS_SUCCESS);
218     TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE_READ, STATUS_SECTION_PROTECTION, IGNORE);
219     TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE, STATUS_SECTION_PROTECTION, IGNORE);
220     TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_READONLY, STATUS_SUCCESS, STATUS_SUCCESS);
221     TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, PAGE_NOACCESS, STATUS_SUCCESS, STATUS_SUCCESS);
222     TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, 0, (PAGE_READWRITE | PAGE_READONLY), STATUS_INVALID_PAGE_PROTECTION, IGNORE);
223     TestMapView(ReadOnlySection, NtCurrentProcess(), &BaseAddress, 0, 0, NULL, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READONLY, STATUS_SECTION_PROTECTION, IGNORE);
224 
225     ZwClose(WriteSectionHandle);
226     ZwClose(PageFileSectionHandle);
227     ZwClose(ReadOnlySection);
228 }
229 
230 
231 static
232 VOID
233 AdvancedErrorChecks(HANDLE FileHandleReadOnly, HANDLE FileHandleWriteOnly)
234 {
235     NTSTATUS Status;
236     PVOID BaseAddress;
237     HANDLE FileSectionHandle;
238     LARGE_INTEGER SectionOffset;
239     LARGE_INTEGER MaximumSize;
240     SIZE_T ViewSize = 0;
241     PVOID SectionObject;
242 
243     MaximumSize.QuadPart = TestStringSize;
244     //Used for parameters working on file-based section
245     Status = ZwCreateSection(&FileSectionHandle, SECTION_ALL_ACCESS, NULL, &MaximumSize, PAGE_READWRITE, SEC_COMMIT, FileHandleWriteOnly);
246     ok_eq_hex(Status, STATUS_SUCCESS);
247 
248     Status = ObReferenceObjectByHandle(FileSectionHandle,
249         STANDARD_RIGHTS_ALL,
250         NULL,
251         KernelMode,
252         &SectionObject,
253         NULL);
254 
255     ok_eq_hex(Status, STATUS_SUCCESS);
256 
257     //Bypassing Zw function calls mean bypassing the alignment checks which are not crucial for the branches being tested here
258 
259     //test first conditional branch
260     ViewSize = -1;
261     MmTestMapView(SectionObject, PsGetCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE, STATUS_INVALID_VIEW_SIZE, IGNORE);
262 
263     //test second conditional branch
264     ViewSize = 1;
265     SectionOffset.QuadPart = TestStringSize;
266     MmTestMapView(SectionObject, PsGetCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE, STATUS_INVALID_VIEW_SIZE, IGNORE);
267 
268     ObDereferenceObject(SectionObject);
269     ZwClose(FileSectionHandle);
270 }
271 
272 static
273 SIZE_T
274 CompareFileContents(HANDLE FileHandle, ULONG BufferLength, PVOID Buffer)
275 {
276     NTSTATUS Status;
277     LARGE_INTEGER ByteOffset;
278     IO_STATUS_BLOCK IoStatusBlock;
279     PVOID FileContent;
280     SIZE_T Match;
281 
282     Match = 0;
283     ByteOffset.QuadPart = 0;
284 
285     FileContent = ExAllocatePoolWithTag(PagedPool, BufferLength, 'Test');
286     if (!skip((FileContent != NULL), "Error allocating memory for FileContent\n"))
287     {
288         Status = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, FileContent, BufferLength, &ByteOffset, NULL);
289         ok_eq_hex(Status, STATUS_SUCCESS);
290         ok_eq_ulongptr(IoStatusBlock.Information, BufferLength);
291 
292         Match = 0;
293         Match = RtlCompareMemory(FileContent, Buffer, BufferLength);
294         ExFreePoolWithTag(FileContent, 'Test');
295     }
296 
297     return Match;
298 }
299 
300 
301 static
302 VOID
303 NTAPI
304 SystemProcessWorker(PVOID StartContext)
305 {
306     NTSTATUS Status;
307     PVOID BaseAddress;
308     HANDLE SectionHandle;
309     SIZE_T ViewSize;
310     SIZE_T Match;
311     LARGE_INTEGER SectionOffset;
312     OBJECT_ATTRIBUTES ObjectAttributes;
313 
314     UNREFERENCED_PARAMETER(StartContext);
315 
316     BaseAddress = NULL;
317     ViewSize = TestStringSize;
318     SectionOffset.QuadPart = 0;
319 
320     InitializeObjectAttributes(&ObjectAttributes, &SharedSectionName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
321     Status = ZwOpenSection(&SectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes);
322     if (!skip(NT_SUCCESS(Status), "Error acquiring handle to section. Error = %p\n", Status))
323     {
324         CheckObject(SectionHandle, 4, 2);
325         Status = ZwMapViewOfSection(SectionHandle, NtCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE);
326 
327         //make sure ZwMapViewofSection doesn't touch the section ref counts.
328         CheckObject(SectionHandle, 4, 2);
329 
330         if (!skip(NT_SUCCESS(Status), "Error mapping page file view in system process. Error = %p\n", Status))
331         {
332             Match = RtlCompareMemory(BaseAddress, TestString, TestStringSize);
333             ok_eq_size(Match, TestStringSize);
334 
335             RtlCopyMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN);
336             ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
337 
338             //make sure ZwMapViewofSection doesn't touch the section ref counts.
339             CheckObject(SectionHandle, 4, 2);
340         }
341 
342         ZwClose(SectionHandle);
343     }
344 
345     PsTerminateSystemThread(STATUS_SUCCESS);
346 }
347 
348 
349 static
350 VOID
351 BehaviorChecks(HANDLE FileHandleReadOnly, HANDLE FileHandleWriteOnly)
352 {
353     NTSTATUS Status;
354     PVOID BaseAddress = NULL;
355     PVOID ThreadObject;
356     HANDLE WriteSectionHandle;
357     HANDLE SysThreadHandle;
358     OBJECT_ATTRIBUTES ObjectAttributes;
359     LARGE_INTEGER SectionOffset;
360     LARGE_INTEGER MaximumSize;
361     SIZE_T Match;
362     SIZE_T ViewSize = 0;
363 
364     InitializeObjectAttributes(&ObjectAttributes, &SharedSectionName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
365     MaximumSize.QuadPart = TestStringSize;
366     SectionOffset.QuadPart = 0;
367 
368     Status = ZwCreateSection(&WriteSectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes, &MaximumSize, PAGE_READWRITE, SEC_COMMIT, FileHandleWriteOnly);
369     CheckObject(WriteSectionHandle, 3, 1);
370     ok(NT_SUCCESS(Status), "Error creating write section from file. Error = %p\n", Status);
371 
372     //check for section reading/writing by comparing section content to a well-known value.
373     Status = ZwMapViewOfSection(WriteSectionHandle, NtCurrentProcess() ,&BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE);
374     CheckObject(WriteSectionHandle, 3, 1);
375     if (!skip(NT_SUCCESS(Status), "Error mapping view with READ/WRITE priv. Error = %p\n", Status))
376     {
377         Match = RtlCompareMemory(BaseAddress, TestString, TestStringSize);
378         ok_eq_size(Match, TestStringSize);
379 
380         //now check writing to section
381         RtlCopyMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN);
382 
383         Match = RtlCompareMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN);
384         ok_eq_size(Match, NEW_CONTENT_LEN);
385 
386         //check to see if the contents have been flushed to the actual file on disk.
387         Match = CompareFileContents(FileHandleWriteOnly, NEW_CONTENT_LEN, NEW_CONTENT);
388         ok_eq_size(Match, NEW_CONTENT_LEN);
389 
390         //bring everything back to normal
391         RtlCopyMemory(BaseAddress, TestString, TestStringSize);
392 
393         //Initiate an external thread to modify the file
394         InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
395         Status = PsCreateSystemThread(&SysThreadHandle, STANDARD_RIGHTS_ALL, &ObjectAttributes, NULL, NULL, SystemProcessWorker, NULL);
396         if (!skip(NT_SUCCESS(Status), "Error creating System thread. Error = %p\n", Status))
397         {
398             Status = ObReferenceObjectByHandle(SysThreadHandle, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &ThreadObject, NULL);
399             if (!skip(NT_SUCCESS(Status), "Error getting reference to System thread when testing file-backed section\n"))
400             {
401                 //wait until the system thread actually terminates
402                 KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, NULL);
403 
404                 //no longer need the thread object
405                 ObDereferenceObject(ThreadObject);
406 
407                 //test for bi-directional access to the shared page file
408                 Match = RtlCompareMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN);
409                 ok_eq_size(Match, NEW_CONTENT_LEN);
410 
411                 //bring everything back to normal, again
412                 RtlCopyMemory(BaseAddress, TestString, TestStringSize);
413             }
414         }
415 
416         ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
417     }
418 
419     //Try to write to read-only mapped view
420     BaseAddress = NULL;
421     ViewSize = 0;
422     SectionOffset.QuadPart = 0;
423     Status = ZwMapViewOfSection(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READONLY);
424     if (!skip(NT_SUCCESS(Status), "Error mapping view with READ priv. Error = %p\n", Status))
425     {
426         Match = RtlCompareMemory(BaseAddress, TestString, TestStringSize);
427         ok_eq_size(Match, TestStringSize);
428 
429         KmtStartSeh()
430             RtlCopyMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN);
431         KmtEndSeh(STATUS_ACCESS_VIOLATION);
432 
433         ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
434     }
435 
436     //try to access forbidden memory
437     BaseAddress = NULL;
438     ViewSize = 0;
439     SectionOffset.QuadPart = 0;
440     Status = ZwMapViewOfSection(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_NOACCESS);
441     if (!skip(NT_SUCCESS(Status), "Error mapping view with PAGE_NOACCESS priv. Error = %p\n", Status))
442     {
443         KmtStartSeh()
444             RtlCompareMemory(BaseAddress, TestString, TestStringSize);
445         KmtEndSeh(STATUS_ACCESS_VIOLATION);
446 
447         ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
448     }
449 
450     //try to access guarded memory
451     BaseAddress = NULL;
452     ViewSize = 0;
453     SectionOffset.QuadPart = 0;
454     Status = ZwMapViewOfSection(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, 0, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_GUARD | PAGE_READWRITE);
455     if (!skip(NT_SUCCESS(Status), "Error mapping view with PAGE_GUARD priv. Error = %p\n", Status))
456     {
457         KmtStartSeh()
458             RtlCompareMemory(BaseAddress, TestString, TestStringSize);
459         KmtEndSeh(STATUS_GUARD_PAGE_VIOLATION);
460 
461         KmtStartSeh()
462             RtlCompareMemory(BaseAddress, TestString, TestStringSize);
463         KmtEndSeh(STATUS_SUCCESS);
464 
465         ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
466     }
467 
468     ZwClose(WriteSectionHandle);
469 
470     //section created with sec_reserve should not be commited.
471     BaseAddress = NULL;
472     ViewSize = 0;
473     SectionOffset.QuadPart = 0;
474     Status = ZwCreateSection(&WriteSectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes, &MaximumSize, PAGE_READWRITE, SEC_RESERVE, FileHandleWriteOnly);
475     if (!skip(NT_SUCCESS(Status), "Error creating page file section. Error = %p\n", Status))
476     {
477         Status = ZwMapViewOfSection(WriteSectionHandle, NtCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE);
478         if (!skip(NT_SUCCESS(Status), "Error mapping page file view. Error = %p\n", Status))
479         {
480             //check also the SEC_COMMIT flag
481             /* This test proves that MSDN is once again wrong
482              *  msdn.microsoft.com/en-us/library/windows/hardware/aa366537.aspx states that SEC_RESERVE
483              *  should cause the allocated memory for the view to be reserved but in fact it is always committed.
484              *  It fails also on windows.
485              */
486             Test_NtQueryVirtualMemory(BaseAddress, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
487             ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
488         }
489 
490         ZwClose(WriteSectionHandle);
491     }
492 }
493 
494 
495 static
496 VOID
497 PageFileBehaviorChecks()
498 {
499     NTSTATUS Status;
500     LARGE_INTEGER MaxSectionSize;
501     LARGE_INTEGER SectionOffset;
502     HANDLE PageFileSectionHandle;
503     PVOID BaseAddress;
504     SIZE_T ViewSize;
505     SIZE_T Match;
506     PVOID ThreadObject;
507     OBJECT_ATTRIBUTES ObjectAttributes;
508 
509     MaxSectionSize.QuadPart = TestStringSize;
510     SectionOffset.QuadPart = 0;
511     PageFileSectionHandle = INVALID_HANDLE_VALUE;
512     BaseAddress = NULL;
513     ViewSize = TestStringSize;
514     InitializeObjectAttributes(&ObjectAttributes, &SharedSectionName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
515 
516     //test memory sharing between 2 different processes
517     Status = ZwCreateSection(&PageFileSectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes, &MaxSectionSize, PAGE_READWRITE, SEC_COMMIT, NULL);
518     if (!skip(NT_SUCCESS(Status), "Error creating page file section. Error = %p\n", Status))
519     {
520         CheckObject(PageFileSectionHandle, 3, 1);
521         Status = ZwMapViewOfSection(PageFileSectionHandle, NtCurrentProcess(), &BaseAddress, 0, TestStringSize, &SectionOffset, &ViewSize, ViewUnmap, 0, PAGE_READWRITE);
522         if (!skip(NT_SUCCESS(Status), "Error mapping page file view. Error = %p\n", Status))
523         {
524             HANDLE SysThreadHandle;
525 
526             CheckObject(PageFileSectionHandle, 3, 1);
527 
528             //check also the SEC_COMMIT flag
529             Test_NtQueryVirtualMemory(BaseAddress, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
530 
531             RtlCopyMemory(BaseAddress, TestString, TestStringSize);
532 
533             InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
534             Status = PsCreateSystemThread(&SysThreadHandle, STANDARD_RIGHTS_ALL, &ObjectAttributes, NULL, NULL, SystemProcessWorker, NULL);
535 
536             if (!skip(NT_SUCCESS(Status), "Error creating System thread. Error = %p\n", Status))
537             {
538                 Status = ObReferenceObjectByHandle(SysThreadHandle, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &ThreadObject, NULL);
539                 if (!skip(NT_SUCCESS(Status), "Error getting reference to System thread when testing pagefile-backed section\n"))
540                 {
541                     //wait until the system thread actually terminates
542                     KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, NULL);
543 
544                     //no longer need the thread object
545                     ObDereferenceObject(ThreadObject);
546 
547                     //test for bi-directional access to the shared page file
548                     Match = RtlCompareMemory(BaseAddress, NEW_CONTENT, NEW_CONTENT_LEN);
549                     ok_eq_size(Match, NEW_CONTENT_LEN);
550                 }
551             }
552             ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
553         }
554         ZwClose(PageFileSectionHandle);
555     }
556 }
557 
558 
559 START_TEST(ZwMapViewOfSection)
560 {
561     HANDLE FileHandleReadOnly = NULL;
562     HANDLE FileHandleWriteOnly = NULL;
563     HANDLE ExecutableFileHandle = NULL;
564 
565     InitializeObjectAttributes(&NtdllObject, &FileReadOnlyPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
566     InitializeObjectAttributes(&KmtestFileObject, &WritableFilePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
567     InitializeObjectAttributes(&NtoskrnlFileObject, &NtosImgPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
568 
569     KmtInitTestFiles(&FileHandleReadOnly, &FileHandleWriteOnly, &ExecutableFileHandle);
570 
571     SimpleErrorChecks(FileHandleReadOnly, FileHandleWriteOnly, ExecutableFileHandle);
572     AdvancedErrorChecks(FileHandleReadOnly, FileHandleWriteOnly);
573     BehaviorChecks(FileHandleReadOnly, FileHandleWriteOnly);
574     PageFileBehaviorChecks();
575 
576     if (FileHandleReadOnly)
577         ZwClose(FileHandleReadOnly);
578 
579     if (FileHandleWriteOnly)
580         ZwClose(FileHandleWriteOnly);
581 
582     if (ExecutableFileHandle)
583         ZwClose(ExecutableFileHandle);
584 }
585