// Switchs the current log buffer, saves the contents of old buffer to the log // file, and prints them out as necessary. This function does not flush the log // file, so code should call LogpWriteMessageToFile() or ZwFlushBuffersFile() // later. _Use_decl_annotations_ static NTSTATUS LogpFlushLogBuffer(LogBufferInfo *info) { NT_ASSERT(info); NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); auto status = STATUS_SUCCESS; // Enter a critical section and acquire a reader lock for info in order to // write a log file safely. ExEnterCriticalRegionAndAcquireResourceExclusive(&info->resource); // Acquire a spin lock for info.log_buffer(s) in order to switch its head // safely. KLOCK_QUEUE_HANDLE lock_handle = {}; KeAcquireInStackQueuedSpinLock(&info->spin_lock, &lock_handle); const auto old_log_buffer = const_cast<char *>(info->log_buffer_head); if (old_log_buffer[0]) { info->log_buffer_head = (old_log_buffer == info->log_buffer1) ? info->log_buffer2 : info->log_buffer1; info->log_buffer_head[0] = '\0'; info->log_buffer_tail = info->log_buffer_head; } KeReleaseInStackQueuedSpinLock(&lock_handle); // Write all log entries in old log buffer. IO_STATUS_BLOCK io_status = {}; for (auto current_log_entry = old_log_buffer; current_log_entry[0]; /**/) { // Check the printed bit and clear it const auto printed_out = LogpIsPrinted(current_log_entry); LogpSetPrintedBit(current_log_entry, false); const auto current_log_entry_length = strlen(current_log_entry); status = ZwWriteFile(info->log_file_handle, nullptr, nullptr, nullptr, &io_status, current_log_entry, static_cast<ULONG>(current_log_entry_length), nullptr, nullptr); if (!NT_SUCCESS(status)) { // It could happen when you did not register IRP_SHUTDOWN and call // LogIrpShutdownHandler() and the system tried to log to a file after // a file system was unmounted. LogpDbgBreak(); } // Print it out if requested and the message is not already printed out if (!printed_out) { LogpDoDbgPrint(current_log_entry); } current_log_entry += current_log_entry_length + 1; } old_log_buffer[0] = '\0'; ExReleaseResourceAndLeaveCriticalRegion(&info->resource); return status; }
// Switch the current log buffer and save the contents of old buffer to the log // file. This function does not flush the log file, so code should call // LogpWriteMessageToFile() or ZwFlushBuffersFile() later. EXTERN_C static NTSTATUS LogpWriteLogBufferToFile( _In_opt_ LogBufferInfo *Info) { NT_ASSERT(Info); NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); auto status = STATUS_SUCCESS; // Enter a critical section and acquire a reader lock for Info in order to // write a log file safely. ExEnterCriticalRegionAndAcquireResourceExclusive(&Info->Resource); // Acquire a spin lock for Info.LogBuffer(s) in order to switch its head // safely. const auto irql = KeAcquireSpinLockRaiseToDpc(&Info->SpinLock); auto oldLogBuffer = const_cast<char *>(Info->LogBufferHead); if (oldLogBuffer[0]) { Info->LogBufferHead = (oldLogBuffer == Info->LogBuffer1) ? Info->LogBuffer2 : Info->LogBuffer1; Info->LogBufferHead[0] = '\0'; Info->LogBufferTail = Info->LogBufferHead; } KeReleaseSpinLock(&Info->SpinLock, irql); // Write all log entries in old log buffer. IO_STATUS_BLOCK ioStatus = {}; for (auto currentLogEntry = oldLogBuffer; currentLogEntry[0]; /**/) { const auto currentLogEntryLength = strlen(currentLogEntry); status = ZwWriteFile(Info->LogFileHandle, nullptr, nullptr, nullptr, &ioStatus, currentLogEntry, static_cast<ULONG>(currentLogEntryLength), nullptr, nullptr); if (!NT_SUCCESS(status)) { // It could happen when you did not register IRP_SHUTDOWN and call // LogIrpShutdownHandler() and the system tried to log to a file after // a filesystem was unmounted. DBG_BREAK(); } currentLogEntry += currentLogEntryLength + 1; } oldLogBuffer[0] = '\0'; ExReleaseResourceAndLeaveCriticalRegion(&Info->Resource); return status; }
NTSTATUS DokanDispatchDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) /*++ Routine Description: This device control dispatcher handles IOCTLs. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PDokanVCB vcb; PDokanDCB dcb; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_NOT_IMPLEMENTED; ULONG controlCode = 0; ULONG outputLength = 0; // {DCA0E0A5-D2CA-4f0f-8416-A6414657A77A} // GUID dokanGUID = { 0xdca0e0a5, 0xd2ca, 0x4f0f, { 0x84, 0x16, 0xa6, 0x41, // 0x46, 0x57, 0xa7, 0x7a } }; __try { Irp->IoStatus.Information = 0; irpSp = IoGetCurrentIrpStackLocation(Irp); outputLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; controlCode = irpSp->Parameters.DeviceIoControl.IoControlCode; if (controlCode != IOCTL_EVENT_WAIT && controlCode != IOCTL_EVENT_INFO && controlCode != IOCTL_KEEPALIVE) { DDbgPrint("==> DokanDispatchIoControl\n"); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); } if (DeviceObject->DriverObject == NULL || DeviceObject->ReferenceCount < 0) { status = STATUS_DEVICE_DOES_NOT_EXIST; __leave; } vcb = DeviceObject->DeviceExtension; PrintIdType(vcb); if (GetIdentifierType(vcb) == DGL) { status = GlobalDeviceControl(DeviceObject, Irp); __leave; } else if (GetIdentifierType(vcb) == DCB) { status = DiskDeviceControlWithLock(DeviceObject, Irp); __leave; } else if (GetIdentifierType(vcb) != VCB) { status = STATUS_INVALID_PARAMETER; __leave; } dcb = vcb->Dcb; switch (irpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_EVENT_WAIT: DDbgPrint(" IOCTL_EVENT_WAIT\n"); status = DokanRegisterPendingIrpForEvent(DeviceObject, Irp); break; case IOCTL_EVENT_INFO: // DDbgPrint(" IOCTL_EVENT_INFO\n"); status = DokanCompleteIrp(DeviceObject, Irp); break; case IOCTL_EVENT_RELEASE: DDbgPrint(" IOCTL_EVENT_RELEASE\n"); status = DokanEventRelease(DeviceObject, Irp); break; case IOCTL_EVENT_WRITE: DDbgPrint(" IOCTL_EVENT_WRITE\n"); status = DokanEventWrite(DeviceObject, Irp); break; case IOCTL_KEEPALIVE: DDbgPrint(" IOCTL_KEEPALIVE\n"); if (IsFlagOn(vcb->Flags, VCB_MOUNTED)) { ExEnterCriticalRegionAndAcquireResourceExclusive(&dcb->Resource); DokanUpdateTimeout(&dcb->TickCount, DOKAN_KEEPALIVE_TIMEOUT); ExReleaseResourceAndLeaveCriticalRegion(&dcb->Resource); status = STATUS_SUCCESS; } else { DDbgPrint(" device is not mounted\n"); status = STATUS_INSUFFICIENT_RESOURCES; } break; case IOCTL_RESET_TIMEOUT: status = DokanResetPendingIrpTimeout(DeviceObject, Irp); break; case IOCTL_GET_ACCESS_TOKEN: status = DokanGetAccessToken(DeviceObject, Irp); break; default: { ULONG baseCode = DEVICE_TYPE_FROM_CTL_CODE( irpSp->Parameters.DeviceIoControl.IoControlCode); status = STATUS_NOT_IMPLEMENTED; // In case of IOCTL_STORAGE_BASE or IOCTL_DISK_BASE OR // FILE_DEVICE_NETWORK_FILE_SYSTEM or MOUNTDEVCONTROLTYPE ioctl type, pass // to DiskDeviceControl to avoid code duplication // TODO: probably not the best way to pass down Irp... if (baseCode == IOCTL_STORAGE_BASE || baseCode == IOCTL_DISK_BASE || baseCode == FILE_DEVICE_NETWORK_FILE_SYSTEM || baseCode == MOUNTDEVCONTROLTYPE) { status = DiskDeviceControlWithLock(dcb->DeviceObject, Irp); } if (status == STATUS_NOT_IMPLEMENTED) { PrintUnknownDeviceIoctlCode( irpSp->Parameters.DeviceIoControl.IoControlCode); } } break; } // switch IoControlCode } __finally { if (status != STATUS_PENDING) { if (IsDeletePending(DeviceObject)) { DDbgPrint(" DeviceObject is invalid, so prevent BSOD"); status = STATUS_DEVICE_REMOVED; } DokanCompleteIrpRequest(Irp, status, Irp->IoStatus.Information); } if (controlCode != IOCTL_EVENT_WAIT && controlCode != IOCTL_EVENT_INFO && controlCode != IOCTL_KEEPALIVE) { DokanPrintNTStatus(status); DDbgPrint("<== DokanDispatchIoControl\n"); } } return status; }
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); }