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