[KMTESTS:IO]

Add more tests for IoCreateFile(), this time purely dealing with symlinks reparse points.
They won't run on ReactOS (obviously) as we don't have RW NTFS support.

On Windows, they show interesting results....
With Windows 2003, creating the symlink is allowed and works, but then Windows is totally unable to deal with it and keeps complaining about an unhandled reparse tag.
The only way to open it is to open the reparse point itself. Not that working symlinks... Not sure which part is not able to handle the said reparse tag. NTFS? Io?
With Windows Vista+, it just works fine. Symlink is created & functionnal.

Broken logic!

svn path=/trunk/; revision=69353
This commit is contained in:
Pierre Schweitzer 2015-09-25 15:57:28 +00:00
parent 9099445189
commit 549ecc5195

View file

@ -420,6 +420,370 @@ KernelModeTest(IN PVOID Context)
static
VOID
NTAPI
TestSymlinks(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);
}
//static
VOID
NTAPI
UserModeTest(VOID)
{
NTSTATUS Status;
@ -512,6 +876,8 @@ START_TEST(IoCreateFile)
HANDLE ThreadHandle;
PVOID ThreadObject = NULL;
TestSymlinks();
/* Justify the next comment/statement */
UserModeTest();