Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885/* * PROJECT: ReactOS kernel-mode tests * LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory * PURPOSE: Kernel-Mode Test Suite Io Regressions KM-Test (IoCreateFile) * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org> */
#include <kmt_test.h>
static UNICODE_STRING SystemRoot = RTL_CONSTANT_STRING(L"\\SystemRoot\\");static UNICODE_STRING Regedit = RTL_CONSTANT_STRING(L"regedit.exe");static UNICODE_STRING Foobar = RTL_CONSTANT_STRING(L"foobar.exe");static UNICODE_STRING SystemRootRegedit = RTL_CONSTANT_STRING(L"\\SystemRoot\\regedit.exe");static UNICODE_STRING SystemRootFoobar = RTL_CONSTANT_STRING(L"\\SystemRoot\\foobar.exe");static UNICODE_STRING SystemRootFoobarFoobar = RTL_CONSTANT_STRING(L"\\SystemRoot\\foobar\\foobar.exe");static UNICODE_STRING FoobarFoobar = RTL_CONSTANT_STRING(L"foobar\\foobar.exe");
staticVOIDNTAPIKernelModeTest(IN PVOID Context){ NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE ParentHandle, SystemRootHandle, TargetHandle; PFILE_OBJECT ParentFileObject, TargetFileObject, SystemRootFileObject;
UNREFERENCED_PARAMETER(Context);
/* Kernelmode mandatory for IoCreateFile */ ok(ExGetPreviousMode() == KernelMode, "UserMode returned!\n");
/* First of all, open \\SystemRoot * We're interested in 3 pieces of information about it: * -> Its target (it's a symlink): \Windows or \ReactOS * -> Its associated File Object * -> Its associated FCB */ TargetFileObject = NULL; IoStatusBlock.Status = 0xFFFFFFFF; TargetHandle = INVALID_HANDLE_VALUE; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &SystemRoot, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenFile(&TargetHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { Status = ObReferenceObjectByHandle(TargetHandle, FILE_READ_DATA, *IoFileObjectType, KernelMode, (PVOID *)&TargetFileObject, NULL); ok_eq_hex(Status, STATUS_SUCCESS); }
ok(TargetFileObject != NULL, "Not target to continue!\n"); if (TargetFileObject == NULL) { if (TargetHandle != INVALID_HANDLE_VALUE) { ObCloseHandle(TargetHandle, KernelMode); } return; }
/* Open target directory of \SystemRoot\Regedit.exe * This must lead to \SystemRoot opening */ IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &SystemRootRegedit, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = IoCreateFile(&ParentHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, CreateFileTypeNone, NULL, IO_OPEN_TARGET_DIRECTORY); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { Status = ObReferenceObjectByHandle(ParentHandle, FILE_READ_DATA, *IoFileObjectType, KernelMode, (PVOID *)&ParentFileObject, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { /* At that point, file object must point to \SystemRoot * But must not be the same FO than target (diverted file object) * This means FCB & FileName are equal * But CCB & FO are different * CCB must be != NULL, otherwise it means open failed */ ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n"); ok_eq_pointer(ParentFileObject->RelatedFileObject, NULL); ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext); ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n"); ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n"); ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0); ObDereferenceObject(ParentFileObject); } /* Because target exists FSD must signal it */ ok_eq_long(IoStatusBlock.Information, FILE_EXISTS); ObCloseHandle(ParentHandle, KernelMode); }
/* Do the same with relative open */ IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &SystemRoot, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenFile(&SystemRootHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &Regedit, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, SystemRootHandle, NULL); Status = IoCreateFile(&ParentHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, CreateFileTypeNone, NULL, IO_OPEN_TARGET_DIRECTORY); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { Status = ObReferenceObjectByHandle(ParentHandle, FILE_READ_DATA, *IoFileObjectType, KernelMode, (PVOID *)&ParentFileObject, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n"); ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext); ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n"); ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n"); ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0); Status = ObReferenceObjectByHandle(SystemRootHandle, FILE_READ_DATA, *IoFileObjectType, KernelMode, (PVOID *)&SystemRootFileObject, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { ok_eq_pointer(ParentFileObject->RelatedFileObject, SystemRootFileObject); ok(ParentFileObject->RelatedFileObject != TargetFileObject, "File objects must be different\n"); ok(SystemRootFileObject != TargetFileObject, "File objects must be different\n"); ObDereferenceObject(SystemRootFileObject); } ObDereferenceObject(ParentFileObject); } ok_eq_long(IoStatusBlock.Information, FILE_EXISTS); ObCloseHandle(ParentHandle, KernelMode); } ObCloseHandle(SystemRootHandle, KernelMode); }
/* *** */
/* Now redo the same scheme, but using a target that doesn't exist * The difference will be in IoStatusBlock.Information, the FSD will * inform that the target doesn't exist. * Clear for rename :-) */ IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &SystemRootFoobar, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = IoCreateFile(&ParentHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, CreateFileTypeNone, NULL, IO_OPEN_TARGET_DIRECTORY); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { Status = ObReferenceObjectByHandle(ParentHandle, FILE_READ_DATA, *IoFileObjectType, KernelMode, (PVOID *)&ParentFileObject, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n"); ok_eq_pointer(ParentFileObject->RelatedFileObject, NULL); ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext); ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n"); ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n"); ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0); ObDereferenceObject(ParentFileObject); } ok_eq_long(IoStatusBlock.Information, FILE_DOES_NOT_EXIST); ObCloseHandle(ParentHandle, KernelMode); }
IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &SystemRoot, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenFile(&SystemRootHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &Foobar, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, SystemRootHandle, NULL); Status = IoCreateFile(&ParentHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, CreateFileTypeNone, NULL, IO_OPEN_TARGET_DIRECTORY); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { Status = ObReferenceObjectByHandle(ParentHandle, FILE_READ_DATA, *IoFileObjectType, KernelMode, (PVOID *)&ParentFileObject, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { ok(ParentFileObject != TargetFileObject, "Diverted file object must be different\n"); ok_eq_pointer(ParentFileObject->FsContext, TargetFileObject->FsContext); ok(ParentFileObject->FsContext2 != 0x0, "Parent must be open!\n"); ok(ParentFileObject->FsContext2 != TargetFileObject->FsContext2, "Parent open must have its own context!\n"); ok_eq_long(RtlCompareUnicodeString(&ParentFileObject->FileName, &TargetFileObject->FileName, FALSE), 0); Status = ObReferenceObjectByHandle(SystemRootHandle, FILE_READ_DATA, *IoFileObjectType, KernelMode, (PVOID *)&SystemRootFileObject, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { ok_eq_pointer(ParentFileObject->RelatedFileObject, SystemRootFileObject); ok(ParentFileObject->RelatedFileObject != TargetFileObject, "File objects must be different\n"); ok(SystemRootFileObject != TargetFileObject, "File objects must be different\n"); ObDereferenceObject(SystemRootFileObject); } ObDereferenceObject(ParentFileObject); } ok_eq_long(IoStatusBlock.Information, FILE_DOES_NOT_EXIST); ObCloseHandle(ParentHandle, KernelMode); } ObCloseHandle(SystemRootHandle, KernelMode); }
ObDereferenceObject(TargetFileObject); ObCloseHandle(TargetHandle, KernelMode);
/* *** */
/* Direct target open of something that doesn't exist */ IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &SystemRootFoobarFoobar, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = IoCreateFile(&ParentHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, CreateFileTypeNone, NULL, IO_OPEN_TARGET_DIRECTORY); ok_eq_hex(Status, STATUS_OBJECT_PATH_NOT_FOUND); ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF); if (Status == STATUS_SUCCESS) { ObCloseHandle(ParentHandle, KernelMode); }
/* Relative target open of something that doesn't exist */ IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &SystemRoot, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenFile(&SystemRootHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &FoobarFoobar, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, SystemRootHandle, NULL); Status = IoCreateFile(&ParentHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, CreateFileTypeNone, NULL, IO_OPEN_TARGET_DIRECTORY); ok_eq_hex(Status, STATUS_OBJECT_PATH_NOT_FOUND); ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF); if (Status == STATUS_SUCCESS) { ObCloseHandle(ParentHandle, KernelMode); } ObCloseHandle(SystemRootHandle, KernelMode); }}
staticVOIDNTAPITestSymlinks(VOID){ HANDLE ReparseHandle; NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; PREPARSE_DATA_BUFFER Reparse; FILE_DISPOSITION_INFORMATION ToDelete; PFILE_OBJECT FileObject; UNICODE_STRING SysDir, Foobar, Regedit; ULONG Size;
/* Get Windows/ReactOS directory */ InitializeObjectAttributes(&ObjectAttributes, &SystemRoot, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenFile(&ReparseHandle, FILE_READ_DATA, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_DIRECTORY_FILE); if (skip(NT_SUCCESS(Status), "Opening \\SystemRoot failed: %lx\n", Status)) { return; }
Status = ObReferenceObjectByHandle(ReparseHandle, FILE_READ_DATA, *IoFileObjectType, UserMode, (PVOID *)&FileObject, NULL); if (skip(NT_SUCCESS(Status), "Querying name failed: %lx\n", Status)) { ZwClose(ReparseHandle); return; }
SysDir.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\??\\C:")); if (skip(SysDir.Buffer != NULL, "Allocating memory failed\n")) { ObDereferenceObject(FileObject); ZwClose(ReparseHandle); return; }
SysDir.Length = sizeof(L"\\??\\C:") - sizeof(UNICODE_NULL); SysDir.MaximumLength = FileObject->FileName.Length + sizeof(L"\\??\\C:"); RtlCopyMemory(SysDir.Buffer, L"\\??\\C:", sizeof(L"\\??\\C:") - sizeof(UNICODE_NULL)); RtlAppendUnicodeStringToString(&SysDir, &FileObject->FileName);
Foobar.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\foobar.exe")); if (skip(Foobar.Buffer != NULL, "Allocating memory failed\n")) { ExFreePool(SysDir.Buffer); ObDereferenceObject(FileObject); ZwClose(ReparseHandle); return; }
Foobar.Length = 0; Foobar.MaximumLength = FileObject->FileName.Length + sizeof(L"\\foobar.exe"); RtlCopyUnicodeString(&Foobar, &FileObject->FileName); RtlCopyMemory(&Foobar.Buffer[Foobar.Length / sizeof(WCHAR)], L"\\foobar.exe", sizeof(L"\\foobar.exe") - sizeof(UNICODE_NULL)); Foobar.Length += (sizeof(L"\\foobar.exe") - sizeof(UNICODE_NULL));
Regedit.Buffer = ExAllocatePool(NonPagedPool, FileObject->FileName.Length + sizeof(L"\\regedit.exe")); if (skip(Regedit.Buffer != NULL, "Allocating memory failed\n")) { ExFreePool(Foobar.Buffer); ExFreePool(SysDir.Buffer); ObDereferenceObject(FileObject); ZwClose(ReparseHandle); return; }
Regedit.Length = 0; Regedit.MaximumLength = FileObject->FileName.Length + sizeof(L"\\regedit.exe"); RtlCopyUnicodeString(&Regedit, &FileObject->FileName); RtlCopyMemory(&Regedit.Buffer[Regedit.Length / sizeof(WCHAR)], L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); Regedit.Length += (sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
ObDereferenceObject(FileObject); ZwClose(ReparseHandle);
ToDelete.DeleteFile = TRUE; Size = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL);
InitializeObjectAttributes(&ObjectAttributes, &SystemRootFoobar, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwCreateFile(&ReparseHandle, GENERIC_READ | GENERIC_WRITE | DELETE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SUPERSEDE, FILE_NON_DIRECTORY_FILE, NULL, 0); ok_eq_hex(Status, STATUS_SUCCESS); if (skip(NT_SUCCESS(Status), "Creating file failed: %lx\n", Status)) { ExFreePool(Regedit.Buffer); ExFreePool(Foobar.Buffer); ExFreePool(SysDir.Buffer); return; }
Reparse = ExAllocatePool(NonPagedPool, Size); RtlZeroMemory(Reparse, Size); Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK; Reparse->ReparseDataLength = 12 + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL); Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL); Reparse->SymbolicLinkReparseBuffer.PrintNameLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(L"\\??\\"); Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset = Reparse->SymbolicLinkReparseBuffer.PrintNameLength; RtlCopyMemory(Reparse->SymbolicLinkReparseBuffer.PathBuffer, (WCHAR *)((ULONG_PTR)SysDir.Buffer + sizeof(L"\\??\\") - sizeof(UNICODE_NULL)), SysDir.Length - sizeof(L"\\??\\") + sizeof(UNICODE_NULL)); RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + SysDir.Length - sizeof(L"\\??\\") + sizeof(UNICODE_NULL)), L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset), SysDir.Buffer, SysDir.Length); RtlCopyMemory((WCHAR *)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset + SysDir.Length), L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL));
Status = ZwFsControlFile(ReparseHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_SET_REPARSE_POINT, Reparse, Size, NULL, 0); ok_eq_hex(Status, STATUS_SUCCESS); if (!NT_SUCCESS(Status)) { ZwClose(ReparseHandle);
Status = ZwCreateFile(&ReparseHandle, FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_SUPERSEDE, FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0); if (skip(NT_SUCCESS(Status), "Creating symlink failed: %lx\n", Status)) { Status = ZwOpenFile(&ReparseHandle, DELETE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_DELETE, FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE); ok_eq_hex(Status, STATUS_SUCCESS); ZwClose(ReparseHandle); ExFreePool(Regedit.Buffer); ExFreePool(Foobar.Buffer); ExFreePool(SysDir.Buffer); ExFreePool(Reparse); return; }
Status = ZwFsControlFile(ReparseHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_SET_REPARSE_POINT, Reparse, Size, NULL, 0); }
if (skip(NT_SUCCESS(Status), "Creating symlink failed: %lx\n", Status)) { ZwSetInformationFile(ReparseHandle, &IoStatusBlock, &ToDelete, sizeof(ToDelete), FileDispositionInformation); ZwClose(ReparseHandle); ExFreePool(Regedit.Buffer); ExFreePool(Foobar.Buffer); ExFreePool(SysDir.Buffer); ExFreePool(Reparse); return; }
ZwClose(ReparseHandle);
Status = ZwCreateFile(&ReparseHandle, GENERIC_READ, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0); ok(Status == STATUS_SUCCESS || /* Windows Vista+ */ Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED, /* Windows 2003 (SP1, SP2) */ "ZwCreateFile returned unexpected status: %lx\n", Status); if (NT_SUCCESS(Status)) { Status = ObReferenceObjectByHandle(ReparseHandle, FILE_READ_DATA, *IoFileObjectType, UserMode, (PVOID *)&FileObject, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (NT_SUCCESS(Status)) { ok(RtlCompareUnicodeString(&Regedit, &FileObject->FileName, TRUE) == 0, "Expected: %wZ. Opened: %wZ\n", &Regedit, &FileObject->FileName); ObDereferenceObject(FileObject); }
ZwClose(ReparseHandle); }
ExFreePool(Regedit.Buffer);
Status = IoCreateFile(&ReparseHandle, GENERIC_READ, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0, CreateFileTypeNone, NULL, IO_NO_PARAMETER_CHECKING | IO_STOP_ON_SYMLINK); ok(Status == STATUS_STOPPED_ON_SYMLINK || /* Windows Vista+ */ Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED, /* Windows 2003 (SP1, SP2) */ "ZwCreateFile returned unexpected status: %lx\n", Status); if (NT_SUCCESS(Status)) { ZwClose(ReparseHandle); }
Status = ZwCreateFile(&ReparseHandle, GENERIC_READ | GENERIC_WRITE | DELETE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0); if (skip(NT_SUCCESS(Status), "Creating opening reparse point: %lx\n", Status)) { Status = ZwOpenFile(&ReparseHandle, DELETE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_DELETE, FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE); ok_eq_hex(Status, STATUS_SUCCESS); ZwClose(ReparseHandle); ExFreePool(Foobar.Buffer); ExFreePool(SysDir.Buffer); ExFreePool(Reparse); return; }
Status = ObReferenceObjectByHandle(ReparseHandle, FILE_READ_DATA, *IoFileObjectType, UserMode, (PVOID *)&FileObject, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (NT_SUCCESS(Status)) { ok(RtlCompareUnicodeString(&Foobar, &FileObject->FileName, TRUE) == 0, "Expected: %wZ. Opened: %wZ\n", &Foobar, &FileObject->FileName); ObDereferenceObject(FileObject); }
ExFreePool(Foobar.Buffer);
RtlZeroMemory(Reparse, Size); Status = ZwFsControlFile(ReparseHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_GET_REPARSE_POINT, NULL, 0, Reparse, Size); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Information, Size); if (NT_SUCCESS(Status)) { PWSTR Buffer; UNICODE_STRING ReparsePath, FullPath;
ok_eq_hex(Reparse->ReparseTag, IO_REPARSE_TAG_SYMLINK); ok_eq_hex(Reparse->ReparseDataLength, 12 + SysDir.Length * 2 + sizeof(L"\\regedit.exe") * 2 - sizeof(L"\\??\\") - sizeof(UNICODE_NULL)); ok_eq_hex(Reparse->SymbolicLinkReparseBuffer.Flags, 0);
FullPath.Length = 0; FullPath.MaximumLength = SysDir.Length + sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL); Buffer = FullPath.Buffer = ExAllocatePool(NonPagedPool, FullPath.MaximumLength); if (!skip(Buffer != NULL, "Memory allocation failed!\n")) { RtlCopyUnicodeString(&FullPath, &SysDir); RtlCopyMemory(&FullPath.Buffer[FullPath.Length / sizeof(WCHAR)], L"\\regedit.exe", sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); FullPath.Length += (sizeof(L"\\regedit.exe") - sizeof(UNICODE_NULL)); ReparsePath.Buffer = (PWSTR)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset); ReparsePath.Length = ReparsePath.MaximumLength = Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength; ok(RtlCompareUnicodeString(&ReparsePath, &FullPath, TRUE) == 0, "Expected: %wZ. Got: %wZ\n", &ReparsePath, &FullPath);
FullPath.Length -= (sizeof(L"\\??\\") - sizeof(UNICODE_NULL)); FullPath.MaximumLength -= (sizeof(L"\\??\\") - sizeof(UNICODE_NULL)); FullPath.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(L"\\??\\") - sizeof(UNICODE_NULL)); ReparsePath.Buffer = (PWSTR)((ULONG_PTR)Reparse->SymbolicLinkReparseBuffer.PathBuffer + Reparse->SymbolicLinkReparseBuffer.PrintNameOffset); ReparsePath.Length = ReparsePath.MaximumLength = Reparse->SymbolicLinkReparseBuffer.PrintNameLength; ok(RtlCompareUnicodeString(&ReparsePath, &FullPath, TRUE) == 0, "Expected: %wZ. Got: %wZ\n", &ReparsePath, &FullPath);
ExFreePool(Buffer); } }
ExFreePool(SysDir.Buffer); ExFreePool(Reparse);
ZwSetInformationFile(ReparseHandle, &IoStatusBlock, &ToDelete, sizeof(ToDelete), FileDispositionInformation); ZwClose(ReparseHandle);}
//staticVOIDNTAPIUserModeTest(VOID){ NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE ParentHandle, SystemRootHandle;
ok(ExGetPreviousMode() == UserMode, "KernelMode returned!\n");
/* Attempt direct target open */ IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &SystemRootRegedit, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = IoCreateFile(&ParentHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, CreateFileTypeNone, NULL, IO_OPEN_TARGET_DIRECTORY); ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF); if (Status == STATUS_SUCCESS) { ObCloseHandle(ParentHandle, UserMode); }
/* Attempt relative target open */ IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &SystemRoot, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenFile(&SystemRootHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); ok_eq_hex(Status, STATUS_SUCCESS); ok_eq_hex(IoStatusBlock.Status, STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { IoStatusBlock.Status = 0xFFFFFFFF; IoStatusBlock.Information = 0xFFFFFFFF; InitializeObjectAttributes(&ObjectAttributes, &Regedit, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, SystemRootHandle, NULL); Status = IoCreateFile(&ParentHandle, GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, CreateFileTypeNone, NULL, IO_OPEN_TARGET_DIRECTORY); ok_eq_hex(Status, STATUS_ACCESS_VIOLATION); ok_eq_hex(IoStatusBlock.Status, 0xFFFFFFFF); if (Status == STATUS_SUCCESS) { ObCloseHandle(ParentHandle, KernelMode); } ObCloseHandle(SystemRootHandle, KernelMode); }}
START_TEST(IoCreateFile){ PKTHREAD ThreadHandle;
TestSymlinks();
/* Justify the next comment/statement */ UserModeTest();
/* We've to be in kernel mode, so spawn a thread */ ThreadHandle = KmtStartThread(KernelModeTest, NULL); KmtFinishThread(ThreadHandle, NULL);}