From 98972036d9aa7cfbdb3d3c9c6cf1d9c15472fa34 Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Tue, 16 Apr 2019 08:25:09 +0200 Subject: [PATCH] [KMTESTS:CC] Add tests for CcCopyWrite CORE-15384 --- modules/rostests/kmtests/CMakeLists.txt | 1 + modules/rostests/kmtests/kmtest/testlist.c | 2 + .../rostests/kmtests/ntos_cc/CMakeLists.txt | 15 + .../kmtests/ntos_cc/CcCopyWrite_drv.c | 373 ++++++++++++++++++ .../kmtests/ntos_cc/CcCopyWrite_user.c | 94 +++++ 5 files changed, 485 insertions(+) create mode 100644 modules/rostests/kmtests/ntos_cc/CcCopyWrite_drv.c create mode 100644 modules/rostests/kmtests/ntos_cc/CcCopyWrite_user.c diff --git a/modules/rostests/kmtests/CMakeLists.txt b/modules/rostests/kmtests/CMakeLists.txt index ddfde9600da..b7cf7093ad0 100644 --- a/modules/rostests/kmtests/CMakeLists.txt +++ b/modules/rostests/kmtests/CMakeLists.txt @@ -138,6 +138,7 @@ list(APPEND KMTEST_SOURCE kernel32/FileAttributes_user.c kernel32/FindFile_user.c ntos_cc/CcCopyRead_user.c + ntos_cc/CcCopyWrite_user.c ntos_cc/CcMapData_user.c ntos_cc/CcPinMappedData_user.c ntos_cc/CcPinRead_user.c diff --git a/modules/rostests/kmtests/kmtest/testlist.c b/modules/rostests/kmtests/kmtest/testlist.c index 0c5e2010d6f..5375d04cdec 100644 --- a/modules/rostests/kmtests/kmtest/testlist.c +++ b/modules/rostests/kmtests/kmtest/testlist.c @@ -7,6 +7,7 @@ #include KMT_TESTFUNC Test_CcCopyRead; +KMT_TESTFUNC Test_CcCopyWrite; KMT_TESTFUNC Test_CcMapData; KMT_TESTFUNC Test_CcPinMappedData; KMT_TESTFUNC Test_CcPinRead; @@ -39,6 +40,7 @@ KMT_TESTFUNC Test_TcpIpConnect; const KMT_TEST TestList[] = { { "CcCopyRead", Test_CcCopyRead }, + { "CcCopyWrite", Test_CcCopyWrite }, { "CcMapData", Test_CcMapData }, { "CcPinMappedData", Test_CcPinMappedData }, { "CcPinRead", Test_CcPinRead }, diff --git a/modules/rostests/kmtests/ntos_cc/CMakeLists.txt b/modules/rostests/kmtests/ntos_cc/CMakeLists.txt index 60912ad1ccb..b31a1e50588 100644 --- a/modules/rostests/kmtests/ntos_cc/CMakeLists.txt +++ b/modules/rostests/kmtests/ntos_cc/CMakeLists.txt @@ -16,6 +16,21 @@ add_target_compile_definitions(cccopyread_drv KMT_STANDALONE_DRIVER) #add_pch(cccopyread_drv ../include/kmt_test.h) add_rostests_file(TARGET cccopyread_drv) +# +# CcCopyWrite +# +list(APPEND CCCOPYWRITE_DRV_SOURCE + ../kmtest_drv/kmtest_standalone.c + CcCopyWrite_drv.c) + +add_library(cccopywrite_drv MODULE ${CCCOPYWRITE_DRV_SOURCE}) +set_module_type(cccopywrite_drv kernelmodedriver) +target_link_libraries(cccopywrite_drv kmtest_printf ${PSEH_LIB}) +add_importlibs(cccopywrite_drv ntoskrnl hal) +add_target_compile_definitions(cccopywrite_drv KMT_STANDALONE_DRIVER) +#add_pch(cccopyread_drv ../include/kmt_test.h) +add_rostests_file(TARGET cccopywrite_drv) + # # CcMapData # diff --git a/modules/rostests/kmtests/ntos_cc/CcCopyWrite_drv.c b/modules/rostests/kmtests/ntos_cc/CcCopyWrite_drv.c new file mode 100644 index 00000000000..9404be1c143 --- /dev/null +++ b/modules/rostests/kmtests/ntos_cc/CcCopyWrite_drv.c @@ -0,0 +1,373 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory + * PURPOSE: Test driver for CcCopyWrite function + * PROGRAMMER: Pierre Schweitzer + */ + +#include + +#define NDEBUG +#include + +typedef struct _TEST_FCB +{ + FSRTL_ADVANCED_FCB_HEADER Header; + SECTION_OBJECT_POINTERS SectionObjectPointers; + FAST_MUTEX HeaderMutex; + ULONG WriteLength; +} TEST_FCB, *PTEST_FCB; + +static PFILE_OBJECT TestFileObject; +static PDEVICE_OBJECT TestDeviceObject; +static KMT_IRP_HANDLER TestIrpHandler; +static FAST_IO_DISPATCH TestFastIoDispatch; + +static +BOOLEAN +NTAPI +FastIoRead( + _In_ PFILE_OBJECT FileObject, + _In_ PLARGE_INTEGER FileOffset, + _In_ ULONG Length, + _In_ BOOLEAN Wait, + _In_ ULONG LockKey, + _Out_ PVOID Buffer, + _Out_ PIO_STATUS_BLOCK IoStatus, + _In_ PDEVICE_OBJECT DeviceObject) +{ + IoStatus->Status = STATUS_NOT_SUPPORTED; + return FALSE; +} + +static +BOOLEAN +NTAPI +FastIoWrite( + _In_ PFILE_OBJECT FileObject, + _In_ PLARGE_INTEGER FileOffset, + _In_ ULONG Length, + _In_ BOOLEAN Wait, + _In_ ULONG LockKey, + _Out_ PVOID Buffer, + _Out_ PIO_STATUS_BLOCK IoStatus, + _In_ PDEVICE_OBJECT DeviceObject) +{ + IoStatus->Status = STATUS_NOT_SUPPORTED; + return FALSE; +} + +NTSTATUS +TestEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PCUNICODE_STRING RegistryPath, + _Out_ PCWSTR *DeviceName, + _Inout_ INT *Flags) +{ + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(RegistryPath); + + *DeviceName = L"CcCopyWrite"; + *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE | + TESTENTRY_BUFFERED_IO_DEVICE | + TESTENTRY_NO_READONLY_DEVICE; + + KmtRegisterIrpHandler(IRP_MJ_CLEANUP, NULL, TestIrpHandler); + KmtRegisterIrpHandler(IRP_MJ_CREATE, NULL, TestIrpHandler); + KmtRegisterIrpHandler(IRP_MJ_READ, NULL, TestIrpHandler); + KmtRegisterIrpHandler(IRP_MJ_WRITE, NULL, TestIrpHandler); + KmtRegisterIrpHandler(IRP_MJ_FLUSH_BUFFERS, NULL, TestIrpHandler); + + TestFastIoDispatch.FastIoRead = FastIoRead; + TestFastIoDispatch.FastIoWrite = FastIoWrite; + DriverObject->FastIoDispatch = &TestFastIoDispatch; + + + return Status; +} + +VOID +TestUnload( + _In_ PDRIVER_OBJECT DriverObject) +{ + PAGED_CODE(); +} + +BOOLEAN +NTAPI +AcquireForLazyWrite( + _In_ PVOID Context, + _In_ BOOLEAN Wait) +{ + return TRUE; +} + +VOID +NTAPI +ReleaseFromLazyWrite( + _In_ PVOID Context) +{ + return; +} + +BOOLEAN +NTAPI +AcquireForReadAhead( + _In_ PVOID Context, + _In_ BOOLEAN Wait) +{ + return TRUE; +} + +VOID +NTAPI +ReleaseFromReadAhead( + _In_ PVOID Context) +{ + return; +} + +static CACHE_MANAGER_CALLBACKS Callbacks = { + AcquireForLazyWrite, + ReleaseFromLazyWrite, + AcquireForReadAhead, + ReleaseFromReadAhead, +}; + +static +PVOID +MapAndLockUserBuffer( + _In_ _Out_ PIRP Irp, + _In_ ULONG BufferLength) +{ + PMDL Mdl; + + if (Irp->MdlAddress == NULL) + { + Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp); + if (Mdl == NULL) + { + return NULL; + } + + _SEH2_TRY + { + MmProbeAndLockPages(Mdl, Irp->RequestorMode, IoWriteAccess); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + IoFreeMdl(Mdl); + Irp->MdlAddress = NULL; + _SEH2_YIELD(return NULL); + } + _SEH2_END; + } + + return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); +} + + +static +NTSTATUS +TestIrpHandler( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_ PIO_STACK_LOCATION IoStack) +{ + LARGE_INTEGER Zero = RTL_CONSTANT_LARGE_INTEGER(0LL); + NTSTATUS Status; + PTEST_FCB Fcb; + CACHE_UNINITIALIZE_EVENT CacheUninitEvent; + + PAGED_CODE(); + + DPRINT("IRP %x/%x\n", IoStack->MajorFunction, IoStack->MinorFunction); + ASSERT(IoStack->MajorFunction == IRP_MJ_CLEANUP || + IoStack->MajorFunction == IRP_MJ_CREATE || + IoStack->MajorFunction == IRP_MJ_READ || + IoStack->MajorFunction == IRP_MJ_WRITE || + IoStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS); + + Status = STATUS_NOT_SUPPORTED; + Irp->IoStatus.Information = 0; + + if (IoStack->MajorFunction == IRP_MJ_CREATE) + { + ok_irql(PASSIVE_LEVEL); + + if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR)) + { + TestDeviceObject = DeviceObject; + TestFileObject = IoStack->FileObject; + } + Fcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Fcb), 'FwrI'); + RtlZeroMemory(Fcb, sizeof(*Fcb)); + ExInitializeFastMutex(&Fcb->HeaderMutex); + FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex); + if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) && + IoStack->FileObject->FileName.Buffer[1] == 'B') + { + Fcb->Header.AllocationSize.QuadPart = 1000000; + Fcb->Header.FileSize.QuadPart = 1000000; + Fcb->Header.ValidDataLength.QuadPart = 1000000; + } + else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) && + IoStack->FileObject->FileName.Buffer[1] == 'S') + { + Fcb->Header.AllocationSize.QuadPart = 512; + Fcb->Header.FileSize.QuadPart = 512; + Fcb->Header.ValidDataLength.QuadPart = 512; + } + else if (IoStack->FileObject->FileName.Length >= 2 * sizeof(WCHAR) && + IoStack->FileObject->FileName.Buffer[1] == 'V') + { + Fcb->Header.AllocationSize.QuadPart = 62; + Fcb->Header.FileSize.QuadPart = 62; + Fcb->Header.ValidDataLength.QuadPart = 62; + } + else + { + Fcb->Header.AllocationSize.QuadPart = 1004; + Fcb->Header.FileSize.QuadPart = 1004; + Fcb->Header.ValidDataLength.QuadPart = 1004; + } + Fcb->Header.IsFastIoPossible = FastIoIsNotPossible; + IoStack->FileObject->FsContext = Fcb; + IoStack->FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; + + CcInitializeCacheMap(IoStack->FileObject, + (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, + FALSE, &Callbacks, NULL); + + Irp->IoStatus.Information = FILE_OPENED; + Status = STATUS_SUCCESS; + } + else if (IoStack->MajorFunction == IRP_MJ_READ) + { + PMDL Mdl; + ULONG Length; + PVOID Buffer; + LARGE_INTEGER Offset; + + Offset = IoStack->Parameters.Read.ByteOffset; + Length = IoStack->Parameters.Read.Length; + Fcb = IoStack->FileObject->FsContext; + + ok_eq_pointer(DeviceObject, TestDeviceObject); + ok_eq_pointer(IoStack->FileObject, TestFileObject); + + ok(BooleanFlagOn(Irp->Flags, IRP_NOCACHE), "IRP not coming from Cc!\n"); + ok_irql(APC_LEVEL); + ok((Offset.QuadPart == 0 || Offset.QuadPart == 4096 || Offset.QuadPart == 8192), "Unexpected offset: %I64i\n", Offset.QuadPart); + ok(Length % PAGE_SIZE == 0, "Length is not aligned: %I64i\n", Length); + + ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n"); + Buffer = MapAndLockUserBuffer(Irp, Length); + ok(Buffer != NULL, "Null pointer!\n"); + RtlFillMemory(Buffer, Length, 0xBA); + + Status = STATUS_SUCCESS; + + Mdl = Irp->MdlAddress; + ok(Mdl != NULL, "Null pointer for MDL!\n"); + ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n"); + ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n"); + ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0, "Non paging IO\n"); + ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n"); + + Irp->IoStatus.Information = Length; + IoStack->FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length; + } + else if (IoStack->MajorFunction == IRP_MJ_WRITE) + { + PMDL Mdl; + ULONG Length; + PVOID Buffer; + LARGE_INTEGER Offset; + + Offset = IoStack->Parameters.Read.ByteOffset; + Length = IoStack->Parameters.Read.Length; + Fcb = IoStack->FileObject->FsContext; + + if (!FlagOn(Irp->Flags, IRP_NOCACHE)) + { + BOOLEAN Ret; + + ok_irql(PASSIVE_LEVEL); + + Buffer = Irp->AssociatedIrp.SystemBuffer; + ok(Buffer != NULL, "Null pointer!\n"); + + Fcb->WriteLength = Length; + + _SEH2_TRY + { + Ret = CcCopyWrite(IoStack->FileObject, &Offset, Length, TRUE, Buffer); + ok_bool_true(Ret, "CcCopyWrite"); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Irp->IoStatus.Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; + + Status = Irp->IoStatus.Status; + } + else + { + ok_irql(PASSIVE_LEVEL); + ok((Offset.QuadPart == 0 || Offset.QuadPart == 4096), "Unexpected offset: %I64i\n", Offset.QuadPart); + ok_eq_ulong(Length, ROUND_TO_PAGES(Fcb->WriteLength)); + + ok(Irp->AssociatedIrp.SystemBuffer == NULL, "A SystemBuffer was allocated!\n"); + Buffer = MapAndLockUserBuffer(Irp, Length); + ok(Buffer != NULL, "Null pointer!\n"); + + Status = STATUS_SUCCESS; + + Mdl = Irp->MdlAddress; + ok(Mdl != NULL, "Null pointer for MDL!\n"); + ok((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0, "MDL not locked\n"); + ok((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0, "MDL from non paged\n"); + ok((Mdl->MdlFlags & MDL_IO_PAGE_READ) == 0, "MDL for read paging IO\n"); + ok((Irp->Flags & IRP_PAGING_IO) != 0, "Non paging IO\n"); + } + } + else if (IoStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) + { + IO_STATUS_BLOCK IoStatus; + + Fcb = IoStack->FileObject->FsContext; + CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, &IoStatus); + + Status = STATUS_SUCCESS; + } + else if (IoStack->MajorFunction == IRP_MJ_CLEANUP) + { + ok_irql(PASSIVE_LEVEL); + KeInitializeEvent(&CacheUninitEvent.Event, NotificationEvent, FALSE); + CcUninitializeCacheMap(IoStack->FileObject, &Zero, &CacheUninitEvent); + KeWaitForSingleObject(&CacheUninitEvent.Event, Executive, KernelMode, FALSE, NULL); + Fcb = IoStack->FileObject->FsContext; + ExFreePoolWithTag(Fcb, 'FwrI'); + IoStack->FileObject->FsContext = NULL; + Status = STATUS_SUCCESS; + } + + if (Status == STATUS_PENDING) + { + IoMarkIrpPending(Irp); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + Status = STATUS_PENDING; + } + else + { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return Status; +} diff --git a/modules/rostests/kmtests/ntos_cc/CcCopyWrite_user.c b/modules/rostests/kmtests/ntos_cc/CcCopyWrite_user.c new file mode 100644 index 00000000000..1b5f8d61876 --- /dev/null +++ b/modules/rostests/kmtests/ntos_cc/CcCopyWrite_user.c @@ -0,0 +1,94 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Kernel-Mode Test Suite CcCopyWrite test user-mode part + * PROGRAMMER: Pierre Schweitzer + */ + +#include + +START_TEST(CcCopyWrite) +{ + HANDLE Handle; + NTSTATUS Status; + LARGE_INTEGER ByteOffset; + IO_STATUS_BLOCK IoStatusBlock; + OBJECT_ATTRIBUTES ObjectAttributes; + PVOID Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, 4097); + UNICODE_STRING BigFile = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-CcCopyWrite\\BigFile"); + UNICODE_STRING SmallFile = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-CcCopyWrite\\SmallFile"); + UNICODE_STRING VerySmallFile = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-CcCopyWrite\\VerySmallFile"); + UNICODE_STRING NormalFile = RTL_CONSTANT_STRING(L"\\Device\\Kmtest-CcCopyWrite\\NormalFile"); + + KmtLoadDriver(L"CcCopyWrite", FALSE); + KmtOpenDriver(); + + InitializeObjectAttributes(&ObjectAttributes, &VerySmallFile, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenFile(&Handle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + ok_eq_hex(Status, STATUS_SUCCESS); + + ByteOffset.QuadPart = 0; + Status = NtWriteFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 62, &ByteOffset, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = NtFlushBuffersFile(Handle, &IoStatusBlock); + ok_eq_hex(Status, STATUS_SUCCESS); + + NtClose(Handle); + + InitializeObjectAttributes(&ObjectAttributes, &SmallFile, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenFile(&Handle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + ok_eq_hex(Status, STATUS_SUCCESS); + + ByteOffset.QuadPart = 0; + Status = NtWriteFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 512, &ByteOffset, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = NtFlushBuffersFile(Handle, &IoStatusBlock); + ok_eq_hex(Status, STATUS_SUCCESS); + + NtClose(Handle); + + InitializeObjectAttributes(&ObjectAttributes, &NormalFile, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenFile(&Handle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + ok_eq_hex(Status, STATUS_SUCCESS); + + ByteOffset.QuadPart = 0; + Status = NtWriteFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 1004, &ByteOffset, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = NtFlushBuffersFile(Handle, &IoStatusBlock); + ok_eq_hex(Status, STATUS_SUCCESS); + + NtClose(Handle); + + InitializeObjectAttributes(&ObjectAttributes, &BigFile, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenFile(&Handle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + ok_eq_hex(Status, STATUS_SUCCESS); + + ByteOffset.QuadPart = 0; + Status = NtWriteFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 4097, &ByteOffset, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = NtFlushBuffersFile(Handle, &IoStatusBlock); + ok_eq_hex(Status, STATUS_SUCCESS); + + NtClose(Handle); + + InitializeObjectAttributes(&ObjectAttributes, &BigFile, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenFile(&Handle, FILE_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, 0, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); + ok_eq_hex(Status, STATUS_SUCCESS); + + ByteOffset.QuadPart = 4097; + Status = NtWriteFile(Handle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 4097, &ByteOffset, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = NtFlushBuffersFile(Handle, &IoStatusBlock); + ok_eq_hex(Status, STATUS_SUCCESS); + + NtClose(Handle); + + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + KmtCloseDriver(); + KmtUnloadDriver(); +}