static VOID TestResourceExclusiveAccess( IN PERESOURCE Res) { LONG Count = 0; KeEnterCriticalRegion(); ok_bool_true(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned"); ++Count; CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU); ok_bool_true(ExAcquireResourceExclusiveLite(Res, TRUE), "ExAcquireResourceExclusiveLite returned"); ++Count; CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU); ok_bool_true(ExAcquireResourceSharedLite(Res, FALSE), "ExAcquireResourceSharedLite returned"); ++Count; ok_bool_true(ExAcquireResourceSharedLite(Res, TRUE), "ExAcquireResourceSharedLite returned"); ++Count; ok_bool_true(ExAcquireSharedStarveExclusive(Res, FALSE), "ExAcquireSharedStarveExclusive returned"); ++Count; ok_bool_true(ExAcquireSharedStarveExclusive(Res, TRUE), "ExAcquireSharedStarveExclusive returned"); ++Count; ok_bool_true(ExAcquireSharedWaitForExclusive(Res, FALSE), "ExAcquireSharedWaitForExclusive returned"); ++Count; ok_bool_true(ExAcquireSharedWaitForExclusive(Res, TRUE), "ExAcquireSharedWaitForExclusive returned"); ++Count; CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU); ExConvertExclusiveToSharedLite(Res); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); while (Count--) ExReleaseResourceLite(Res); KeLeaveCriticalRegion(); }
static VOID NTAPI AcquireResourceThread( PVOID Context) { NTSTATUS Status = STATUS_SUCCESS; PTHREAD_DATA ThreadData = Context; BOOLEAN Ret; KeEnterCriticalRegion(); Ret = ThreadData->AcquireResource(ThreadData->Res, ThreadData->Wait); if (ThreadData->RetExpected) ok_bool_true(Ret, "AcquireResource returned"); else ok_bool_false(Ret, "AcquireResource returned"); ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned"); Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (Ret) ExReleaseResource(ThreadData->Res); KeLeaveCriticalRegion(); }
static VOID TestResourceSharedAccess( IN PERESOURCE Res) { LONG Count = 0; KeEnterCriticalRegion(); ok_bool_true(ExAcquireResourceSharedLite(Res, FALSE), "ExAcquireResourceSharedLite returned"); ++Count; CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); ok_bool_true(ExAcquireResourceSharedLite(Res, FALSE), "ExAcquireResourceSharedLite returned"); ++Count; ok_bool_true(ExAcquireResourceSharedLite(Res, TRUE), "ExAcquireResourceSharedLite returned"); ++Count; ok_bool_true(ExAcquireSharedStarveExclusive(Res, FALSE), "ExAcquireSharedStarveExclusive returned"); ++Count; ok_bool_true(ExAcquireSharedStarveExclusive(Res, TRUE), "ExAcquireSharedStarveExclusive returned"); ++Count; ok_bool_true(ExAcquireSharedWaitForExclusive(Res, FALSE), "ExAcquireSharedWaitForExclusive returned"); ++Count; ok_bool_true(ExAcquireSharedWaitForExclusive(Res, TRUE), "ExAcquireSharedWaitForExclusive returned"); ++Count; CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); /* this one fails, TRUE would deadlock */ ok_bool_false(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned"); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); /* this asserts */ if (!KmtIsCheckedBuild) ExConvertExclusiveToSharedLite(Res); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); while (Count--) ExReleaseResourceLite(Res); KeLeaveCriticalRegion(); }
static VOID TestResourceUndocumentedShortcuts( IN PERESOURCE Res, IN BOOLEAN AreApcsDisabled) { PVOID Ret; LONG Count = 0; ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled); /* ExEnterCriticalRegionAndAcquireResourceShared, ExEnterCriticalRegionAndAcquireSharedWaitForExclusive */ Count = 0; Ret = ExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count; ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); Ret = ExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count; ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res); ++Count; ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); while (Count-- > 1) { ExReleaseResourceAndLeaveCriticalRegion(Res); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); } ExReleaseResourceAndLeaveCriticalRegion(Res); ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); /* ExEnterCriticalRegionAndAcquireResourceExclusive */ Count = 0; ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); Ret = ExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count; ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU); Ret = ExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count; ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU); ExReleaseResourceAndLeaveCriticalRegion(Res); --Count; ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU); ExReleaseResourceAndLeaveCriticalRegion(Res); --Count; ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); }
static NTSTATUS TestIrpHandler( _In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PIO_STACK_LOCATION IoStack) { 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); Status = STATUS_NOT_SUPPORTED; Irp->IoStatus.Information = 0; if (IoStack->MajorFunction == IRP_MJ_CREATE) { 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 = 3000; Fcb->Header.FileSize.QuadPart = 3000; Fcb->Header.ValidDataLength.QuadPart = 3000; } else { Fcb->Header.AllocationSize.QuadPart = 512; Fcb->Header.FileSize.QuadPart = 512; Fcb->Header.ValidDataLength.QuadPart = 512; } Fcb->Header.IsFastIoPossible = FALSE; 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) { BOOLEAN Ret; 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); if (!FlagOn(Irp->Flags, IRP_NOCACHE)) { ok(Offset.QuadPart % 512 != 0, "Offset is aligned: %I64i\n", Offset.QuadPart); ok(Length % 512 != 0, "Length is aligned: %I64i\n", Length); Buffer = MapUserBuffer(Irp); ok(Buffer != NULL, "Null pointer!\n"); _SEH2_TRY { Ret = CcCopyRead(IoStack->FileObject, &Offset, Length, TRUE, Buffer, &Irp->IoStatus); ok_bool_true(Ret, "CcCopyRead"); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Irp->IoStatus.Status = _SEH2_GetExceptionCode(); } _SEH2_END; Status = Irp->IoStatus.Status; }
static VOID TestConnect( IN HANDLE ServerHandle, IN PCWSTR PipePath) { NTSTATUS Status; THREAD_CONTEXT ConnectContext; THREAD_CONTEXT ListenContext; BOOLEAN Okay; HANDLE ClientHandle; StartWorkerThread(&ConnectContext); StartWorkerThread(&ListenContext); /* Server should start out listening */ CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE); /* Connect a client */ ClientHandle = NULL; Okay = CheckConnectPipe(&ConnectContext, PipePath, 100); ok_bool_true(Okay, "CheckConnectPipe returned"); ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS); if (NT_SUCCESS(ConnectContext.Connect.Status)) { ClientHandle = ConnectContext.Connect.ClientHandle; CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE); } CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE); /* Connect another client */ Okay = CheckConnectPipe(&ConnectContext, PipePath, 100); ok_bool_true(Okay, "CheckConnectPipe returned"); ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE); if (NT_SUCCESS(ConnectContext.Connect.Status)) ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode); CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE); CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE); /* Disconnecting the client should fail */ Status = NpDisconnectPipe(ClientHandle); ok_eq_hex(Status, STATUS_ILLEGAL_FUNCTION); CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE); CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE); /* Listening on the client should fail */ Status = NpListenPipe(ClientHandle); ok_eq_hex(Status, STATUS_ILLEGAL_FUNCTION); CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE); CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE); /* Close client */ if (ClientHandle) ObCloseHandle(ClientHandle, KernelMode); CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE); /* Connecting a client now should fail */ Okay = CheckConnectPipe(&ConnectContext, PipePath, 100); ok_bool_true(Okay, "CheckConnectPipe returned"); ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE); if (NT_SUCCESS(ConnectContext.Connect.Status)) ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode); CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE); /* Listening should fail */ Okay = CheckListenPipe(&ListenContext, ServerHandle, 100); ok_bool_true(Okay, "CheckListenPipe returned"); if (!skip(Okay, "Listen succeeded unexpectedly\n")) CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE); /* Disconnect server */ Status = NpDisconnectPipe(ServerHandle); ok_eq_hex(Status, STATUS_SUCCESS); CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE); /* Disconnecting again should fail */ Status = NpDisconnectPipe(ServerHandle); ok_eq_hex(Status, STATUS_PIPE_DISCONNECTED); CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE); /* Connecting a client now should fail */ Okay = CheckConnectPipe(&ConnectContext, PipePath, 100); ok_bool_true(Okay, "CheckConnectPipe returned"); ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE); if (NT_SUCCESS(ConnectContext.Connect.Status)) ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode); CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE); /**************************************************************************/ /* Now listen again */ Okay = CheckListenPipe(&ListenContext, ServerHandle, 100); ok_bool_false(Okay, "CheckListenPipe returned"); //blocks: CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE); /* Connect client */ ClientHandle = NULL; Okay = CheckConnectPipe(&ConnectContext, PipePath, 100); ok_bool_true(Okay, "CheckConnectPipe returned"); ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS); if (NT_SUCCESS(ConnectContext.Connect.Status)) { ClientHandle = ConnectContext.Connect.ClientHandle; CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE); } Okay = WaitForWork(&ListenContext, 100); ok_bool_true(Okay, "WaitForWork returned"); ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS); CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE); /* Listening again should fail */ Okay = CheckListenPipe(&ListenContext, ServerHandle, 100); ok_bool_true(Okay, "CheckListenPipe returned"); ok_eq_hex(ListenContext.Listen.Status, STATUS_PIPE_CONNECTED); CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE); CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE); /* Disconnect server */ Status = NpDisconnectPipe(ServerHandle); ok_eq_hex(Status, STATUS_SUCCESS); NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED); CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE); /* Close client */ if (ClientHandle) ObCloseHandle(ClientHandle, KernelMode); CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE); /**************************************************************************/ /* Listen once more */ Okay = CheckListenPipe(&ListenContext, ServerHandle, 100); ok_bool_false(Okay, "CheckListenPipe returned"); //blocks: CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE); /* Connect client */ ClientHandle = NULL; Okay = CheckConnectPipe(&ConnectContext, PipePath, 100); ok_bool_true(Okay, "CheckConnectPipe returned"); ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS); if (NT_SUCCESS(ConnectContext.Connect.Status)) { ClientHandle = ConnectContext.Connect.ClientHandle; CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE); } Okay = WaitForWork(&ListenContext, 100); ok_bool_true(Okay, "WaitForWork returned"); ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS); CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE); /* Close server */ Status = ObCloseHandle(ServerHandle, KernelMode); ok_eq_hex(Status, STATUS_SUCCESS); CheckClient(ClientHandle, FILE_PIPE_CLOSING_STATE); /* Close client */ if (ClientHandle) ObCloseHandle(ClientHandle, KernelMode); FinishWorkerThread(&ListenContext); FinishWorkerThread(&ConnectContext); }
static VOID TestFastMutex( PFAST_MUTEX Mutex, KIRQL OriginalIrql) { PKTHREAD Thread = KeGetCurrentThread(); ok_irql(OriginalIrql); /* acquire/release normally */ ExAcquireFastMutex(Mutex); CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL); ok_bool_false(ExTryToAcquireFastMutex(Mutex), "ExTryToAcquireFastMutex returned"); CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL); ExReleaseFastMutex(Mutex); CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql); #ifdef _M_IX86 /* ntoskrnl's fastcall version */ ExiAcquireFastMutex(Mutex); CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL); ok_bool_false(ExiTryToAcquireFastMutex(Mutex), "ExiTryToAcquireFastMutex returned"); CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL); ExiReleaseFastMutex(Mutex); CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql); #endif /* try to acquire */ ok_bool_true(ExTryToAcquireFastMutex(Mutex), "ExTryToAcquireFastMutex returned"); CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL); ExReleaseFastMutex(Mutex); CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql); /* shortcut functions with critical region */ ExEnterCriticalRegionAndAcquireFastMutexUnsafe(Mutex); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(Mutex); /* acquire/release unsafe */ if (!KmtIsCheckedBuild || OriginalIrql == APC_LEVEL) { ExAcquireFastMutexUnsafe(Mutex); CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, OriginalIrql); ExReleaseFastMutexUnsafe(Mutex); CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql); /* mismatched acquire/release */ ExAcquireFastMutex(Mutex); CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL); ExReleaseFastMutexUnsafe(Mutex); CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, APC_LEVEL); KmtSetIrql(OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql); Mutex->OldIrql = 0x55555555LU; ExAcquireFastMutexUnsafe(Mutex); CheckMutex(Mutex, 0L, Thread, 0LU, 0x55555555LU, OriginalIrql); Mutex->OldIrql = PASSIVE_LEVEL; ExReleaseFastMutex(Mutex); CheckMutex(Mutex, 1L, NULL, 0LU, PASSIVE_LEVEL, PASSIVE_LEVEL); KmtSetIrql(OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, PASSIVE_LEVEL, OriginalIrql); } if (!KmtIsCheckedBuild) { /* release without acquire */ ExReleaseFastMutexUnsafe(Mutex); CheckMutex(Mutex, 2L, NULL, 0LU, PASSIVE_LEVEL, OriginalIrql); --Mutex->Count; Mutex->OldIrql = OriginalIrql; ExReleaseFastMutex(Mutex); CheckMutex(Mutex, 2L, NULL, 0LU, OriginalIrql, OriginalIrql); ExReleaseFastMutex(Mutex); CheckMutex(Mutex, 3L, NULL, 0LU, OriginalIrql, OriginalIrql); Mutex->Count -= 2; } /* make sure we survive this in case of error */ ok_eq_long(Mutex->Count, 1L); Mutex->Count = 1; ok_irql(OriginalIrql); KmtSetIrql(OriginalIrql); }