1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Io Regressions KM-Test (IoCreateFile)
5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
6 */
7
8 #include <kmt_test.h>
9
10 static UNICODE_STRING SystemRoot = RTL_CONSTANT_STRING(L"\\SystemRoot\\");
11 static UNICODE_STRING Regedit = RTL_CONSTANT_STRING(L"regedit.exe");
12 static UNICODE_STRING Foobar = RTL_CONSTANT_STRING(L"foobar.exe");
13 static UNICODE_STRING SystemRootRegedit = RTL_CONSTANT_STRING(L"\\SystemRoot\\regedit.exe");
14 static UNICODE_STRING SystemRootFoobar = RTL_CONSTANT_STRING(L"\\SystemRoot\\foobar.exe");
15 static UNICODE_STRING SystemRootFoobarFoobar = RTL_CONSTANT_STRING(L"\\SystemRoot\\foobar\\foobar.exe");
16 static UNICODE_STRING FoobarFoobar = RTL_CONSTANT_STRING(L"foobar\\foobar.exe");
17
18 static
19 VOID
20 NTAPI
KernelModeTest(IN PVOID Context)21 KernelModeTest(IN PVOID Context)
22 {
23 NTSTATUS Status;
24 IO_STATUS_BLOCK IoStatusBlock;
25 OBJECT_ATTRIBUTES ObjectAttributes;
26 HANDLE ParentHandle, SystemRootHandle, TargetHandle;
27 PFILE_OBJECT ParentFileObject, TargetFileObject, SystemRootFileObject;
28
29 UNREFERENCED_PARAMETER(Context);
30
31 /* Kernelmode mandatory for IoCreateFile */
32 ok(ExGetPreviousMode() == KernelMode, "UserMode returned!\n");
33
34 /* First of all, open \\SystemRoot
35 * We're interested in 3 pieces of information about it:
36 * -> Its target (it's a symlink): \Windows or \ReactOS
37 * -> Its associated File Object
38 * -> Its associated FCB
39 */
40 TargetFileObject = NULL;
41 IoStatusBlock.Status = 0xFFFFFFFF;
42 TargetHandle = INVALID_HANDLE_VALUE;
43 IoStatusBlock.Information = 0xFFFFFFFF;
44 InitializeObjectAttributes(&ObjectAttributes,
45 &SystemRoot,
46 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
47 NULL, NULL);
48 Status = ZwOpenFile(&TargetHandle,
49 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
50 &ObjectAttributes,
51 &IoStatusBlock,
52 FILE_SHARE_READ | FILE_SHARE_WRITE,
53 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
54 ok_eq_hex(Status, STATUS_SUCCESS);
55 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
56 if (Status == STATUS_SUCCESS)
57 {
58 Status = ObReferenceObjectByHandle(TargetHandle,
59 FILE_READ_DATA,
60 *IoFileObjectType,
61 KernelMode,
62 (PVOID *)&TargetFileObject,
63 NULL);
64 ok_eq_hex(Status, STATUS_SUCCESS);
65 }
66
67 ok(TargetFileObject != NULL, "Not target to continue!\n");
68 if (TargetFileObject == NULL)
69 {
70 if (TargetHandle != INVALID_HANDLE_VALUE)
71 {
72 ObCloseHandle(TargetHandle, KernelMode);
73 }
74 return;
75 }
76
77 /* Open target directory of \SystemRoot\Regedit.exe
78 * This must lead to \SystemRoot opening
79 */
80 IoStatusBlock.Status = 0xFFFFFFFF;
81 IoStatusBlock.Information = 0xFFFFFFFF;
82 InitializeObjectAttributes(&ObjectAttributes,
83 &SystemRootRegedit,
84 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
85 NULL, NULL);
86 Status = IoCreateFile(&ParentHandle,
87 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
88 &ObjectAttributes,
89 &IoStatusBlock,
90 NULL,
91 0,
92 FILE_SHARE_READ | FILE_SHARE_WRITE,
93 FILE_OPEN,
94 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
95 NULL,
96 0,
97 CreateFileTypeNone,
98 NULL,
99 IO_OPEN_TARGET_DIRECTORY);
100 ok_eq_hex(Status, STATUS_SUCCESS);
101 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
102 if (Status == STATUS_SUCCESS)
103 {
104 Status = ObReferenceObjectByHandle(ParentHandle,
105 FILE_READ_DATA,
106 *IoFileObjectType,
107 KernelMode,
108 (PVOID *)&ParentFileObject,
109 NULL);
110 ok_eq_hex(Status, STATUS_SUCCESS);
111 if (Status == STATUS_SUCCESS)
112 {
113 /* At that point, file object must point to \SystemRoot
114 * But must not be the same FO than target (diverted file object)
115 * This means FCB & FileName are equal
116 * But CCB & FO are different
117 * CCB must be != NULL, otherwise it means open failed
118 */
119 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n");
120 ok_eq_pointer(ParentFileObject->RelatedFileObject, NULL);
121 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext);
122 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n");
123 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n");
124 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0);
125 ObDereferenceObject(ParentFileObject);
126 }
127 /* Because target exists FSD must signal it */
128 ok_eq_long(IoStatusBlock.Information, FILE_EXISTS);
129 ObCloseHandle(ParentHandle, KernelMode);
130 }
131
132 /* Do the same with relative open */
133 IoStatusBlock.Status = 0xFFFFFFFF;
134 IoStatusBlock.Information = 0xFFFFFFFF;
135 InitializeObjectAttributes(&ObjectAttributes,
136 &SystemRoot,
137 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
138 NULL, NULL);
139 Status = ZwOpenFile(&SystemRootHandle,
140 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
141 &ObjectAttributes,
142 &IoStatusBlock,
143 FILE_SHARE_READ | FILE_SHARE_WRITE,
144 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
145 ok_eq_hex(Status, STATUS_SUCCESS);
146 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
147 if (Status == STATUS_SUCCESS)
148 {
149 IoStatusBlock.Status = 0xFFFFFFFF;
150 IoStatusBlock.Information = 0xFFFFFFFF;
151 InitializeObjectAttributes(&ObjectAttributes,
152 &Regedit,
153 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
154 SystemRootHandle,
155 NULL);
156 Status = IoCreateFile(&ParentHandle,
157 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
158 &ObjectAttributes,
159 &IoStatusBlock,
160 NULL,
161 0,
162 FILE_SHARE_READ | FILE_SHARE_WRITE,
163 FILE_OPEN,
164 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
165 NULL,
166 0,
167 CreateFileTypeNone,
168 NULL,
169 IO_OPEN_TARGET_DIRECTORY);
170 ok_eq_hex(Status, STATUS_SUCCESS);
171 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
172 if (Status == STATUS_SUCCESS)
173 {
174 Status = ObReferenceObjectByHandle(ParentHandle,
175 FILE_READ_DATA,
176 *IoFileObjectType,
177 KernelMode,
178 (PVOID *)&ParentFileObject,
179 NULL);
180 ok_eq_hex(Status, STATUS_SUCCESS);
181 if (Status == STATUS_SUCCESS)
182 {
183 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n");
184 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext);
185 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n");
186 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n");
187 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0);
188 Status = ObReferenceObjectByHandle(SystemRootHandle,
189 FILE_READ_DATA,
190 *IoFileObjectType,
191 KernelMode,
192 (PVOID *)&SystemRootFileObject,
193 NULL);
194 ok_eq_hex(Status, STATUS_SUCCESS);
195 if (Status == STATUS_SUCCESS)
196 {
197 ok_eq_pointer(ParentFileObject->RelatedFileObject, SystemRootFileObject);
198 ok(ParentFileObject->RelatedFileObject != TargetFileObject, "File objects must be different\n");
199 ok(SystemRootFileObject != TargetFileObject, "File objects must be different\n");
200 ObDereferenceObject(SystemRootFileObject);
201 }
202 ObDereferenceObject(ParentFileObject);
203 }
204 ok_eq_long(IoStatusBlock.Information, FILE_EXISTS);
205 ObCloseHandle(ParentHandle, KernelMode);
206 }
207 ObCloseHandle(SystemRootHandle, KernelMode);
208 }
209
210 /* *** */
211
212 /* Now redo the same scheme, but using a target that doesn't exist
213 * The difference will be in IoStatusBlock.Information, the FSD will
214 * inform that the target doesn't exist.
215 * Clear for rename :-)
216 */
217 IoStatusBlock.Status = 0xFFFFFFFF;
218 IoStatusBlock.Information = 0xFFFFFFFF;
219 InitializeObjectAttributes(&ObjectAttributes,
220 &SystemRootFoobar,
221 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
222 NULL, NULL);
223 Status = IoCreateFile(&ParentHandle,
224 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
225 &ObjectAttributes,
226 &IoStatusBlock,
227 NULL,
228 0,
229 FILE_SHARE_READ | FILE_SHARE_WRITE,
230 FILE_OPEN,
231 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
232 NULL,
233 0,
234 CreateFileTypeNone,
235 NULL,
236 IO_OPEN_TARGET_DIRECTORY);
237 ok_eq_hex(Status, STATUS_SUCCESS);
238 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
239 if (Status == STATUS_SUCCESS)
240 {
241 Status = ObReferenceObjectByHandle(ParentHandle,
242 FILE_READ_DATA,
243 *IoFileObjectType,
244 KernelMode,
245 (PVOID *)&ParentFileObject,
246 NULL);
247 ok_eq_hex(Status, STATUS_SUCCESS);
248 if (Status == STATUS_SUCCESS)
249 {
250 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n");
251 ok_eq_pointer(ParentFileObject->RelatedFileObject, NULL);
252 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext);
253 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n");
254 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n");
255 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0);
256 ObDereferenceObject(ParentFileObject);
257 }
258 ok_eq_long(IoStatusBlock.Information, FILE_DOES_NOT_EXIST);
259 ObCloseHandle(ParentHandle, KernelMode);
260 }
261
262 IoStatusBlock.Status = 0xFFFFFFFF;
263 IoStatusBlock.Information = 0xFFFFFFFF;
264 InitializeObjectAttributes(&ObjectAttributes,
265 &SystemRoot,
266 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
267 NULL, NULL);
268 Status = ZwOpenFile(&SystemRootHandle,
269 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
270 &ObjectAttributes,
271 &IoStatusBlock,
272 FILE_SHARE_READ | FILE_SHARE_WRITE,
273 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
274 ok_eq_hex(Status, STATUS_SUCCESS);
275 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
276 if (Status == STATUS_SUCCESS)
277 {
278 IoStatusBlock.Status = 0xFFFFFFFF;
279 IoStatusBlock.Information = 0xFFFFFFFF;
280 InitializeObjectAttributes(&ObjectAttributes,
281 &Foobar,
282 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
283 SystemRootHandle,
284 NULL);
285 Status = IoCreateFile(&ParentHandle,
286 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
287 &ObjectAttributes,
288 &IoStatusBlock,
289 NULL,
290 0,
291 FILE_SHARE_READ | FILE_SHARE_WRITE,
292 FILE_OPEN,
293 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
294 NULL,
295 0,
296 CreateFileTypeNone,
297 NULL,
298 IO_OPEN_TARGET_DIRECTORY);
299 ok_eq_hex(Status, STATUS_SUCCESS);
300 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
301 if (Status == STATUS_SUCCESS)
302 {
303 Status = ObReferenceObjectByHandle(ParentHandle,
304 FILE_READ_DATA,
305 *IoFileObjectType,
306 KernelMode,
307 (PVOID *)&ParentFileObject,
308 NULL);
309 ok_eq_hex(Status, STATUS_SUCCESS);
310 if (Status == STATUS_SUCCESS)
311 {
312 ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n");
313 ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext);
314 ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n");
315 ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n");
316 ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0);
317 Status = ObReferenceObjectByHandle(SystemRootHandle,
318 FILE_READ_DATA,
319 *IoFileObjectType,
320 KernelMode,
321 (PVOID *)&SystemRootFileObject,
322 NULL);
323 ok_eq_hex(Status, STATUS_SUCCESS);
324 if (Status == STATUS_SUCCESS)
325 {
326 ok_eq_pointer(ParentFileObject->RelatedFileObject, SystemRootFileObject);
327 ok(ParentFileObject->RelatedFileObject != TargetFileObject, "File objects must be different\n");
328 ok(SystemRootFileObject != TargetFileObject, "File objects must be different\n");
329 ObDereferenceObject(SystemRootFileObject);
330 }
331 ObDereferenceObject(ParentFileObject);
332 }
333 ok_eq_long(IoStatusBlock.Information, FILE_DOES_NOT_EXIST);
334 ObCloseHandle(ParentHandle, KernelMode);
335 }
336 ObCloseHandle(SystemRootHandle, KernelMode);
337 }
338
339 ObDereferenceObject(TargetFileObject);
340 ObCloseHandle(TargetHandle, KernelMode);
341
342 /* *** */
343
344 /* Direct target open of something that doesn't exist */
345 IoStatusBlock.Status = 0xFFFFFFFF;
346 IoStatusBlock.Information = 0xFFFFFFFF;
347 InitializeObjectAttributes(&ObjectAttributes,
348 &SystemRootFoobarFoobar,
349 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
350 NULL, NULL);
351 Status = IoCreateFile(&ParentHandle,
352 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
353 &ObjectAttributes,
354 &IoStatusBlock,
355 NULL,
356 0,
357 FILE_SHARE_READ | FILE_SHARE_WRITE,
358 FILE_OPEN,
359 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
360 NULL,
361 0,
362 CreateFileTypeNone,
363 NULL,
364 IO_OPEN_TARGET_DIRECTORY);
365 ok_eq_hex(Status, STATUS_OBJECT_PATH_NOT_FOUND);
366 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF);
367 if (Status == STATUS_SUCCESS)
368 {
369 ObCloseHandle(ParentHandle, KernelMode);
370 }
371
372 /* Relative target open of something that doesn't exist */
373 IoStatusBlock.Status = 0xFFFFFFFF;
374 IoStatusBlock.Information = 0xFFFFFFFF;
375 InitializeObjectAttributes(&ObjectAttributes,
376 &SystemRoot,
377 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
378 NULL, NULL);
379 Status = ZwOpenFile(&SystemRootHandle,
380 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
381 &ObjectAttributes,
382 &IoStatusBlock,
383 FILE_SHARE_READ | FILE_SHARE_WRITE,
384 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
385 ok_eq_hex(Status, STATUS_SUCCESS);
386 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
387 if (Status == STATUS_SUCCESS)
388 {
389 IoStatusBlock.Status = 0xFFFFFFFF;
390 IoStatusBlock.Information = 0xFFFFFFFF;
391 InitializeObjectAttributes(&ObjectAttributes,
392 &FoobarFoobar,
393 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
394 SystemRootHandle,
395 NULL);
396 Status = IoCreateFile(&ParentHandle,
397 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
398 &ObjectAttributes,
399 &IoStatusBlock,
400 NULL,
401 0,
402 FILE_SHARE_READ | FILE_SHARE_WRITE,
403 FILE_OPEN,
404 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
405 NULL,
406 0,
407 CreateFileTypeNone,
408 NULL,
409 IO_OPEN_TARGET_DIRECTORY);
410 ok_eq_hex(Status, STATUS_OBJECT_PATH_NOT_FOUND);
411 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF);
412 if (Status == STATUS_SUCCESS)
413 {
414 ObCloseHandle(ParentHandle, KernelMode);
415 }
416 ObCloseHandle(SystemRootHandle, KernelMode);
417 }
418 }
419
420 static
421 VOID
422 NTAPI
TestSymlinks(VOID)423 TestSymlinks(VOID)
424 {
425 HANDLE ReparseHandle;
426 NTSTATUS Status;
427 IO_STATUS_BLOCK IoStatusBlock;
428 OBJECT_ATTRIBUTES ObjectAttributes;
429 PREPARSE_DATA_BUFFER Reparse;
430 FILE_DISPOSITION_INFORMATION ToDelete;
431 PFILE_OBJECT FileObject;
432 UNICODE_STRING SysDir, Foobar, Regedit;
433 ULONG Size;
434
435 /* Get Windows/ReactOS directory */
436 InitializeObjectAttributes(&ObjectAttributes,
437 &SystemRoot,
438 OBJ_CASE_INSENSITIVE,
439 NULL,
440 NULL);
441 Status = ZwOpenFile(&ReparseHandle,
442 FILE_READ_DATA,
443 &ObjectAttributes,
444 &IoStatusBlock,
445 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
446 FILE_DIRECTORY_FILE);
447 if (skip(NT_SUCCESS(Status), "Opening \\SystemRoot failed: %lx\n", Status))
448 {
449 return;
450 }
451
452 Status = ObReferenceObjectByHandle(ReparseHandle,
453 FILE_READ_DATA,
454 *IoFileObjectType,
455 UserMode,
456 (PVOID *)&FileObject,
457 NULL);
458 if (skip(NT_SUCCESS(Status), "Querying name failed: %lx\n", Status))
459 {
460 ZwClose(ReparseHandle);
461 return;
462 }
463
464 SysDir.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\??\\C:"));
465 if (skip(SysDir.Buffer != NULL, "Allocating memory failed\n"))
466 {
467 ObDereferenceObject(FileObject);
468 ZwClose(ReparseHandle);
469 return;
470 }
471
472 SysDir.Length = sizeof(L"\\??\\C:") - sizeof(UNICODE_NULL);
473 SysDir.MaximumLength = FileObject->FileName.Length + sizeof(L"\\??\\C:");
474 RtlCopyMemory(SysDir.Buffer, L"\\??\\C:", sizeof(L"\\??\\C:") - sizeof(UNICODE_NULL));
475 RtlAppendUnicodeStringToString(&SysDir, &FileObject->FileName);
476
477 Foobar.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\foobar.exe"));
478 if (skip(Foobar.Buffer != NULL, "Allocating memory failed\n"))
479 {
480 ExFreePool(SysDir.Buffer);
481 ObDereferenceObject(FileObject);
482 ZwClose(ReparseHandle);
483 return;
484 }
485
486 Foobar.Length = 0;
487 Foobar.MaximumLength = FileObject->FileName.Length + sizeof(L"\\foobar.exe");
488 RtlCopyUnicodeString(&Foobar, &FileObject->FileName);
489 RtlCopyMemory(&Foobar.Buffer[Foobar.Length / sizeof(WCHAR)], L"\\foobar.exe", sizeof(L"\\foobar.exe") - sizeof(UNICODE_NULL));
490 Foobar.Length += (sizeof(L"\\foobar.exe") - sizeof(UNICODE_NULL));
491
492 Regedit.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\regedit.exe"));
493 if (skip(Regedit.Buffer != NULL, "Allocating memory failed\n"))
494 {
495 ExFreePool(Foobar.Buffer);
496 ExFreePool(SysDir.Buffer);
497 ObDereferenceObject(FileObject);
498 ZwClose(ReparseHandle);
499 return;
500 }
501
502 Regedit.Length = 0;
503 Regedit.MaximumLength = FileObject->FileName.Length + sizeof(L"\\regedit.exe");
504 RtlCopyUnicodeString(&Regedit, &FileObject->FileName);
505 RtlCopyMemory(&Regedit.Buffer[Regedit.Length / sizeof(WCHAR)], L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
506 Regedit.Length += (sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
507
508 ObDereferenceObject(FileObject);
509 ZwClose(ReparseHandle);
510
511 ToDelete.DeleteFile = TRUE;
512 Size = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL);
513
514 InitializeObjectAttributes(&ObjectAttributes,
515 &SystemRootFoobar,
516 OBJ_CASE_INSENSITIVE,
517 NULL,
518 NULL);
519 Status = ZwCreateFile(&ReparseHandle,
520 GENERIC_READ | GENERIC_WRITE | DELETE,
521 &ObjectAttributes,
522 &IoStatusBlock,
523 NULL,
524 FILE_ATTRIBUTE_NORMAL,
525 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
526 FILE_SUPERSEDE,
527 FILE_NON_DIRECTORY_FILE,
528 NULL,
529 0);
530 ok_eq_hex(Status, STATUS_SUCCESS);
531 if (skip(NT_SUCCESS(Status), "Creating file failed: %lx\n", Status))
532 {
533 ExFreePool(Regedit.Buffer);
534 ExFreePool(Foobar.Buffer);
535 ExFreePool(SysDir.Buffer);
536 return;
537 }
538
539 Reparse = ExAllocatePool(NonPagedPool, Size);
540 RtlZeroMemory(Reparse, Size);
541 Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK;
542 Reparse->ReparseDataLength = 12 + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL);
543 Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL);
544 Reparse->SymbolicLinkReparseBuffer.PrintNameLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(L"\\??\\");
545 Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset = Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
546 RtlCopyMemory(Reparse->SymbolicLinkReparseBuffer.PathBuffer,
547 (WCHAR *)((ULONG_PTR)SysDir.Buffer + sizeof(L"\\??\\") - sizeof(UNICODE_NULL)),
548 SysDir.Length - sizeof(L"\\??\\") + sizeof(UNICODE_NULL));
549 RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + SysDir.Length - sizeof(L"\\??\\") + sizeof(UNICODE_NULL)),
550 L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
551 RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset),
552 SysDir.Buffer, SysDir.Length);
553 RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset + SysDir.Length),
554 L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
555
556 Status = ZwFsControlFile(ReparseHandle,
557 NULL,
558 NULL,
559 NULL,
560 &IoStatusBlock,
561 FSCTL_SET_REPARSE_POINT,
562 Reparse,
563 Size,
564 NULL,
565 0);
566 ok_eq_hex(Status, STATUS_SUCCESS);
567 if (!NT_SUCCESS(Status))
568 {
569 ZwClose(ReparseHandle);
570
571 Status = ZwCreateFile(&ReparseHandle,
572 FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE,
573 &ObjectAttributes,
574 &IoStatusBlock,
575 NULL,
576 FILE_ATTRIBUTE_NORMAL,
577 0,
578 FILE_SUPERSEDE,
579 FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
580 NULL,
581 0);
582 if (skip(NT_SUCCESS(Status), "Creating symlink failed: %lx\n", Status))
583 {
584 Status = ZwOpenFile(&ReparseHandle,
585 DELETE,
586 &ObjectAttributes,
587 &IoStatusBlock,
588 FILE_SHARE_DELETE,
589 FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE);
590 ok_eq_hex(Status, STATUS_SUCCESS);
591 ZwClose(ReparseHandle);
592 ExFreePool(Regedit.Buffer);
593 ExFreePool(Foobar.Buffer);
594 ExFreePool(SysDir.Buffer);
595 ExFreePool(Reparse);
596 return;
597 }
598
599 Status = ZwFsControlFile(ReparseHandle,
600 NULL,
601 NULL,
602 NULL,
603 &IoStatusBlock,
604 FSCTL_SET_REPARSE_POINT,
605 Reparse,
606 Size,
607 NULL,
608 0);
609 }
610
611 if (skip(NT_SUCCESS(Status), "Creating symlink failed: %lx\n", Status))
612 {
613 ZwSetInformationFile(ReparseHandle,
614 &IoStatusBlock,
615 &ToDelete,
616 sizeof(ToDelete),
617 FileDispositionInformation);
618 ZwClose(ReparseHandle);
619 ExFreePool(Regedit.Buffer);
620 ExFreePool(Foobar.Buffer);
621 ExFreePool(SysDir.Buffer);
622 ExFreePool(Reparse);
623 return;
624 }
625
626 ZwClose(ReparseHandle);
627
628 Status = ZwCreateFile(&ReparseHandle,
629 GENERIC_READ,
630 &ObjectAttributes,
631 &IoStatusBlock,
632 NULL,
633 FILE_ATTRIBUTE_NORMAL,
634 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
635 FILE_OPEN,
636 FILE_NON_DIRECTORY_FILE,
637 NULL,
638 0);
639 ok(Status == STATUS_SUCCESS || /* Windows Vista+ */
640 Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED, /* Windows 2003 (SP1, SP2) */
641 "ZwCreateFile returned unexpected status: %lx\n", Status);
642 if (NT_SUCCESS(Status))
643 {
644 Status = ObReferenceObjectByHandle(ReparseHandle,
645 FILE_READ_DATA,
646 *IoFileObjectType,
647 UserMode,
648 (PVOID *)&FileObject,
649 NULL);
650 ok_eq_hex(Status, STATUS_SUCCESS);
651 if (NT_SUCCESS(Status))
652 {
653 ok(RtlCompareUnicodeString(&Regedit, &FileObject->FileName, TRUE) == 0,
654 "Expected: %wZ. Opened: %wZ\n", &Regedit, &FileObject->FileName);
655 ObDereferenceObject(FileObject);
656 }
657
658 ZwClose(ReparseHandle);
659 }
660
661 ExFreePool(Regedit.Buffer);
662
663 Status = IoCreateFile(&ReparseHandle,
664 GENERIC_READ,
665 &ObjectAttributes,
666 &IoStatusBlock,
667 NULL,
668 FILE_ATTRIBUTE_NORMAL,
669 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
670 FILE_OPEN,
671 FILE_NON_DIRECTORY_FILE,
672 NULL,
673 0,
674 CreateFileTypeNone,
675 NULL,
676 IO_NO_PARAMETER_CHECKING | IO_STOP_ON_SYMLINK);
677 ok(Status == STATUS_STOPPED_ON_SYMLINK || /* Windows Vista+ */
678 Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED, /* Windows 2003 (SP1, SP2) */
679 "ZwCreateFile returned unexpected status: %lx\n", Status);
680 if (NT_SUCCESS(Status))
681 {
682 ZwClose(ReparseHandle);
683 }
684
685 Status = ZwCreateFile(&ReparseHandle,
686 GENERIC_READ | GENERIC_WRITE | DELETE,
687 &ObjectAttributes,
688 &IoStatusBlock,
689 NULL,
690 FILE_ATTRIBUTE_NORMAL,
691 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
692 FILE_OPEN,
693 FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT,
694 NULL,
695 0);
696 if (skip(NT_SUCCESS(Status), "Creating opening reparse point: %lx\n", Status))
697 {
698 Status = ZwOpenFile(&ReparseHandle,
699 DELETE,
700 &ObjectAttributes,
701 &IoStatusBlock,
702 FILE_SHARE_DELETE,
703 FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE);
704 ok_eq_hex(Status, STATUS_SUCCESS);
705 ZwClose(ReparseHandle);
706 ExFreePool(Foobar.Buffer);
707 ExFreePool(SysDir.Buffer);
708 ExFreePool(Reparse);
709 return;
710 }
711
712 Status = ObReferenceObjectByHandle(ReparseHandle,
713 FILE_READ_DATA,
714 *IoFileObjectType,
715 UserMode,
716 (PVOID *)&FileObject,
717 NULL);
718 ok_eq_hex(Status, STATUS_SUCCESS);
719 if (NT_SUCCESS(Status))
720 {
721 ok(RtlCompareUnicodeString(&Foobar, &FileObject->FileName, TRUE) == 0,
722 "Expected: %wZ. Opened: %wZ\n", &Foobar, &FileObject->FileName);
723 ObDereferenceObject(FileObject);
724 }
725
726 ExFreePool(Foobar.Buffer);
727
728 RtlZeroMemory(Reparse, Size);
729 Status = ZwFsControlFile(ReparseHandle,
730 NULL,
731 NULL,
732 NULL,
733 &IoStatusBlock,
734 FSCTL_GET_REPARSE_POINT,
735 NULL,
736 0,
737 Reparse,
738 Size);
739 ok_eq_hex(Status, STATUS_SUCCESS);
740 ok_eq_hex(IoStatusBlock.Information, Size);
741 if (NT_SUCCESS(Status))
742 {
743 PWSTR Buffer;
744 UNICODE_STRING ReparsePath, FullPath;
745
746 ok_eq_hex(Reparse->ReparseTag, IO_REPARSE_TAG_SYMLINK);
747 ok_eq_hex(Reparse->ReparseDataLength, 12 + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL));
748 ok_eq_hex(Reparse->SymbolicLinkReparseBuffer.Flags, 0);
749
750 FullPath.Length = 0;
751 FullPath.MaximumLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL);
752 Buffer = FullPath.Buffer = ExAllocatePool(NonPagedPool, FullPath.MaximumLength);
753 if (!skip(Buffer != NULL, "Memory allocation failed!\n"))
754 {
755 RtlCopyUnicodeString(&FullPath, &SysDir);
756 RtlCopyMemory(&FullPath.Buffer[FullPath.Length / sizeof(WCHAR)], L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
757 FullPath.Length += (sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
758 ReparsePath.Buffer = (PWSTR)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset);
759 ReparsePath.Length = ReparsePath.MaximumLength = Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength;
760 ok(RtlCompareUnicodeString(&ReparsePath, &FullPath, TRUE) == 0, "Expected: %wZ. Got: %wZ\n", &ReparsePath, &FullPath);
761
762 FullPath.Length -= (sizeof(L"\\??\\") - sizeof(UNICODE_NULL));
763 FullPath.MaximumLength -= (sizeof(L"\\??\\") - sizeof(UNICODE_NULL));
764 FullPath.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(L"\\??\\") - sizeof(UNICODE_NULL));
765 ReparsePath.Buffer = (PWSTR)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.PrintNameOffset);
766 ReparsePath.Length = ReparsePath.MaximumLength = Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
767 ok(RtlCompareUnicodeString(&ReparsePath, &FullPath, TRUE) == 0, "Expected: %wZ. Got: %wZ\n", &ReparsePath, &FullPath);
768
769 ExFreePool(Buffer);
770 }
771 }
772
773 ExFreePool(SysDir.Buffer);
774 ExFreePool(Reparse);
775
776 ZwSetInformationFile(ReparseHandle,
777 &IoStatusBlock,
778 &ToDelete,
779 sizeof(ToDelete),
780 FileDispositionInformation);
781 ZwClose(ReparseHandle);
782 }
783
784 //static
785 VOID
786 NTAPI
UserModeTest(VOID)787 UserModeTest(VOID)
788 {
789 NTSTATUS Status;
790 IO_STATUS_BLOCK IoStatusBlock;
791 OBJECT_ATTRIBUTES ObjectAttributes;
792 HANDLE ParentHandle, SystemRootHandle;
793
794 ok(ExGetPreviousMode() == UserMode, "KernelMode returned!\n");
795
796 /* Attempt direct target open */
797 IoStatusBlock.Status = 0xFFFFFFFF;
798 IoStatusBlock.Information = 0xFFFFFFFF;
799 InitializeObjectAttributes(&ObjectAttributes,
800 &SystemRootRegedit,
801 OBJ_CASE_INSENSITIVE,
802 NULL, NULL);
803 Status = IoCreateFile(&ParentHandle,
804 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
805 &ObjectAttributes,
806 &IoStatusBlock,
807 NULL,
808 0,
809 FILE_SHARE_READ | FILE_SHARE_WRITE,
810 FILE_OPEN,
811 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
812 NULL,
813 0,
814 CreateFileTypeNone,
815 NULL,
816 IO_OPEN_TARGET_DIRECTORY);
817 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
818 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF);
819 if (Status == STATUS_SUCCESS)
820 {
821 ObCloseHandle(ParentHandle, UserMode);
822 }
823
824 /* Attempt relative target open */
825 IoStatusBlock.Status = 0xFFFFFFFF;
826 IoStatusBlock.Information = 0xFFFFFFFF;
827 InitializeObjectAttributes(&ObjectAttributes,
828 &SystemRoot,
829 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
830 NULL, NULL);
831 Status = ZwOpenFile(&SystemRootHandle,
832 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
833 &ObjectAttributes,
834 &IoStatusBlock,
835 FILE_SHARE_READ | FILE_SHARE_WRITE,
836 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
837 ok_eq_hex(Status, STATUS_SUCCESS);
838 ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS);
839 if (Status == STATUS_SUCCESS)
840 {
841 IoStatusBlock.Status = 0xFFFFFFFF;
842 IoStatusBlock.Information = 0xFFFFFFFF;
843 InitializeObjectAttributes(&ObjectAttributes,
844 &Regedit,
845 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
846 SystemRootHandle,
847 NULL);
848 Status = IoCreateFile(&ParentHandle,
849 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
850 &ObjectAttributes,
851 &IoStatusBlock,
852 NULL,
853 0,
854 FILE_SHARE_READ | FILE_SHARE_WRITE,
855 FILE_OPEN,
856 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
857 NULL,
858 0,
859 CreateFileTypeNone,
860 NULL,
861 IO_OPEN_TARGET_DIRECTORY);
862 ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
863 ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF);
864 if (Status == STATUS_SUCCESS)
865 {
866 ObCloseHandle(ParentHandle, KernelMode);
867 }
868 ObCloseHandle(SystemRootHandle, KernelMode);
869 }
870 }
871
START_TEST(IoCreateFile)872 START_TEST(IoCreateFile)
873 {
874 PKTHREAD ThreadHandle;
875
876 TestSymlinks();
877
878 /* Justify the next comment/statement */
879 UserModeTest();
880
881 /* We've to be in kernel mode, so spawn a thread */
882 ThreadHandle = KmtStartThread(KernelModeTest, NULL);
883 KmtFinishThread(ThreadHandle, NULL);
884 }
885