Annotation of truecrypt/driver/encryptedioqueue.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
                      3: 
1.1.1.5 ! root        4:  Governed by the TrueCrypt License 2.5 the full text of which is contained
1.1       root        5:  in the file License.txt included in TrueCrypt binary and source code
                      6:  distribution packages.
                      7: */
                      8: 
                      9: #include "TCdefs.h"
                     10: #include "Apidrvr.h"
                     11: #include "Ntdriver.h"
                     12: #include "EncryptedIoQueue.h"
1.1.1.5 ! root       13: #include "EncryptionThreadPool.h"
        !            14: #include "Volumes.h"
1.1       root       15: 
                     16: 
                     17: static void DecrementOutstandingIoCount (EncryptedIoQueue *queue)
                     18: {
                     19:        if (InterlockedDecrement (&queue->OutstandingIoCount) == 0 && (queue->SuspendPending || queue->StopPending))
1.1.1.3   root       20:                KeSetEvent (&queue->NoOutstandingIoEvent, IO_DISK_INCREMENT, FALSE);
1.1       root       21: }
                     22: 
                     23: 
1.1.1.5 ! root       24: static void OnItemCompleted (EncryptedIoQueueItem *item, BOOL freeItem)
1.1       root       25: {
                     26:        DecrementOutstandingIoCount (item->Queue);
                     27:        
                     28:        if (item->Queue->IsFilterDevice)
                     29:                IoReleaseRemoveLock (&item->Queue->RemoveLock, item->OriginalIrp);
                     30: 
                     31:        if (NT_SUCCESS (item->Status))
                     32:        {
                     33:                if (item->Write)
                     34:                        item->Queue->TotalBytesWritten += item->OriginalLength;
                     35:                else
                     36:                        item->Queue->TotalBytesRead += item->OriginalLength;
                     37:        }
                     38: 
1.1.1.5 ! root       39:        if (freeItem)
        !            40:                TCfree (item);
1.1       root       41: }
                     42: 
                     43: 
                     44: static NTSTATUS CompleteOriginalIrp (EncryptedIoQueueItem *item, NTSTATUS status, ULONG_PTR information)
                     45: {
                     46:        //Dump ("Queue comp  offset=%I64d  status=%x  info=%p  out=%d\n", item->OriginalOffset, status, information, item->Queue->OutstandingIoCount - 1);
1.1.1.5 ! root       47:        
1.1       root       48:        TCCompleteDiskIrp (item->OriginalIrp, status, information);
1.1.1.5 ! root       49: 
        !            50:        item->Status = status;
        !            51:        OnItemCompleted (item, TRUE);
        !            52: 
1.1       root       53:        return status;
                     54: }
                     55: 
                     56: 
                     57: static void AcquireFragmentBuffer (EncryptedIoQueue *queue, byte *buffer)
                     58: {
                     59:        NTSTATUS status = STATUS_INVALID_PARAMETER;
                     60: 
                     61:        if (buffer == queue->FragmentBufferA)
                     62:        {
                     63:                status = KeWaitForSingleObject (&queue->FragmentBufferAFreeEvent, Executive, KernelMode, FALSE, NULL);
                     64:        }
                     65:        else if (buffer == queue->FragmentBufferB)
                     66:        {
                     67:                status = KeWaitForSingleObject (&queue->FragmentBufferBFreeEvent, Executive, KernelMode, FALSE, NULL);
                     68:        }
                     69: 
                     70:        if (!NT_SUCCESS (status))
                     71:                TC_BUG_CHECK (status);
                     72: }
                     73: 
                     74: 
                     75: static void ReleaseFragmentBuffer (EncryptedIoQueue *queue, byte *buffer)
                     76: {
                     77:        if (buffer == queue->FragmentBufferA)
                     78:        {
1.1.1.3   root       79:                KeSetEvent (&queue->FragmentBufferAFreeEvent, IO_DISK_INCREMENT, FALSE);
1.1       root       80:        }
                     81:        else if (buffer == queue->FragmentBufferB)
                     82:        {
1.1.1.3   root       83:                KeSetEvent (&queue->FragmentBufferBFreeEvent, IO_DISK_INCREMENT, FALSE);
1.1       root       84:        }
                     85:        else
                     86:        {
                     87:                TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
                     88:        }
                     89: }
                     90: 
                     91: 
                     92: static VOID CompletionThreadProc (PVOID threadArg)
                     93: {
                     94:        EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
                     95:        PLIST_ENTRY listEntry;
                     96:        EncryptedIoRequest *request;
                     97:        UINT64_STRUCT dataUnit;
                     98: 
1.1.1.5 ! root       99:        if (IsEncryptionThreadPoolRunning())
        !           100:                KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
        !           101: 
1.1       root      102:        while (!queue->ThreadExitRequested)
                    103:        {
                    104:                if (!NT_SUCCESS (KeWaitForSingleObject (&queue->CompletionThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
                    105:                        continue;
                    106: 
                    107:                if (queue->ThreadExitRequested)
                    108:                        break;
                    109: 
                    110:                while ((listEntry = ExInterlockedRemoveHeadList (&queue->CompletionThreadQueue, &queue->CompletionThreadQueueLock)))
                    111:                {
                    112:                        request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, CompletionListEntry);
                    113: 
1.1.1.3   root      114:                        if (request->EncryptedLength > 0 && NT_SUCCESS (request->Item->Status))
1.1       root      115:                        {
                    116:                                ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length);
                    117:                                dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE;
1.1.1.3   root      118: 
                    119:                                if (queue->CryptoInfo->bPartitionInInactiveSysEncScope)
                    120:                                        dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value;
1.1.1.5 ! root      121:                                else if (queue->RemapEncryptedArea)
        !           122:                                        dataUnit.Value += queue->RemappedAreaDataUnitOffset;
1.1.1.3   root      123: 
1.1       root      124:                                DecryptDataUnits (request->Data + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
                    125:                        }
                    126: 
                    127:                        if (request->CompleteOriginalIrp)
                    128:                        {
                    129:                                CompleteOriginalIrp (request->Item, request->Item->Status,
                    130:                                        NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0);
                    131:                        }
1.1.1.3   root      132:                        else
                    133:                        {
                    134:                                InterlockedDecrement (&request->Item->OutstandingRequestCount);
                    135:                                KeSetEvent (&queue->RequestCompletedEvent, IO_DISK_INCREMENT, FALSE);
                    136:                        }
1.1       root      137: 
                    138:                        TCfree (request);
                    139:                }
                    140:        }
                    141: 
                    142:        PsTerminateSystemThread (STATUS_SUCCESS);
                    143: }
                    144: 
                    145: 
                    146: static VOID IoThreadProc (PVOID threadArg)
                    147: {
                    148:        EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
                    149:        PLIST_ENTRY listEntry;
                    150:        EncryptedIoRequest *request;
                    151: 
1.1.1.4   root      152:        KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
                    153: 
1.1       root      154:        while (!queue->ThreadExitRequested)
                    155:        {
                    156:                if (!NT_SUCCESS (KeWaitForSingleObject (&queue->IoThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
                    157:                        continue;
                    158: 
                    159:                if (queue->ThreadExitRequested)
                    160:                        break;
                    161: 
                    162:                while ((listEntry = ExInterlockedRemoveHeadList (&queue->IoThreadQueue, &queue->IoThreadQueueLock)))
                    163:                {
                    164:                        request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, ListEntry);
1.1.1.3   root      165:                        
                    166:                        // Perform IO request if no preceding request of the item failed
                    167:                        if (NT_SUCCESS (request->Item->Status))
1.1       root      168:                        {
1.1.1.3   root      169:                                if (queue->IsFilterDevice)
                    170:                                {
1.1.1.5 ! root      171:                                        if (queue->RemapEncryptedArea && request->EncryptedLength > 0)
        !           172:                                        {
        !           173:                                                if (request->EncryptedLength != request->Length)
        !           174:                                                {
        !           175:                                                        // Up to three subfragments may be required to handle a partially remapped fragment
        !           176:                                                        int subFragment;
        !           177:                                                        byte *subFragmentData = request->Data;
        !           178: 
        !           179:                                                        for (subFragment = 0 ; subFragment < 3; ++subFragment)
        !           180:                                                        {
        !           181:                                                                LARGE_INTEGER subFragmentOffset;
        !           182:                                                                ULONG subFragmentLength;
        !           183:                                                                subFragmentOffset.QuadPart = request->Offset.QuadPart;
        !           184: 
        !           185:                                                                switch (subFragment)
        !           186:                                                                {
        !           187:                                                                case 0:
        !           188:                                                                        subFragmentLength = (ULONG) request->EncryptedOffset;
        !           189:                                                                        break;
        !           190: 
        !           191:                                                                case 1:
        !           192:                                                                        subFragmentOffset.QuadPart += request->EncryptedOffset + queue->RemappedAreaOffset;
        !           193:                                                                        subFragmentLength = request->EncryptedLength;
        !           194:                                                                        break;
        !           195: 
        !           196:                                                                case 2:
        !           197:                                                                        subFragmentOffset.QuadPart += request->EncryptedOffset + request->EncryptedLength;
        !           198:                                                                        subFragmentLength = (ULONG) (request->Length - (request->EncryptedOffset + request->EncryptedLength));
        !           199:                                                                        break;
        !           200:                                                                }
        !           201: 
        !           202:                                                                if (subFragmentLength > 0)
        !           203:                                                                {
        !           204:                                                                        if (request->Item->Write)
        !           205:                                                                                request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, subFragmentData, subFragmentOffset, subFragmentLength);
        !           206:                                                                        else
        !           207:                                                                                request->Item->Status = TCReadDevice (queue->LowerDeviceObject, subFragmentData, subFragmentOffset, subFragmentLength);
        !           208: 
        !           209:                                                                        subFragmentData += subFragmentLength;
        !           210:                                                                }
        !           211:                                                        }
        !           212:                                                }
        !           213:                                                else
        !           214:                                                {
        !           215:                                                        // Remap the fragment
        !           216:                                                        LARGE_INTEGER remappedOffset;
        !           217:                                                        remappedOffset.QuadPart = request->Offset.QuadPart + queue->RemappedAreaOffset;
        !           218: 
        !           219:                                                        if (request->Item->Write)
        !           220:                                                                request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, request->Data, remappedOffset, request->Length);
        !           221:                                                        else
        !           222:                                                                request->Item->Status = TCReadDevice (queue->LowerDeviceObject, request->Data, remappedOffset, request->Length);
        !           223:                                                }
        !           224:                                        }
1.1.1.3   root      225:                                        else
1.1.1.5 ! root      226:                                        {
        !           227:                                                if (request->Item->Write)
        !           228:                                                        request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, request->Data, request->Offset, request->Length);
        !           229:                                                else
        !           230:                                                        request->Item->Status = TCReadDevice (queue->LowerDeviceObject, request->Data, request->Offset, request->Length);
        !           231:                                        }
1.1.1.3   root      232:                                }
1.1       root      233:                                else
1.1.1.3   root      234:                                {
                    235:                                        IO_STATUS_BLOCK ioStatus;
1.1       root      236: 
1.1.1.3   root      237:                                        if (request->Item->Write)
                    238:                                                request->Item->Status = ZwWriteFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, request->Data, request->Length, &request->Offset, NULL);
                    239:                                        else
                    240:                                                request->Item->Status = ZwReadFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, request->Data, request->Length, &request->Offset, NULL);
1.1.1.5 ! root      241: 
        !           242:                                        if (NT_SUCCESS (request->Item->Status) && ioStatus.Information != request->Length)
        !           243:                                                request->Item->Status = STATUS_END_OF_FILE;
1.1.1.3   root      244:                                }
1.1       root      245:                        }
                    246: 
1.1.1.3   root      247:                        if (request->Item->Write)
1.1       root      248:                        {
                    249:                                ReleaseFragmentBuffer (queue, request->Data);
                    250: 
                    251:                                if (request->CompleteOriginalIrp)
                    252:                                {
                    253:                                        CompleteOriginalIrp (request->Item, request->Item->Status,
                    254:                                                NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0);
                    255:                                }
                    256:                                else
                    257:                                {
1.1.1.3   root      258:                                        InterlockedDecrement (&request->Item->OutstandingRequestCount);
                    259:                                        KeSetEvent (&queue->RequestCompletedEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      260:                                }
                    261: 
                    262:                                TCfree (request);
                    263:                        }
1.1.1.3   root      264:                        else
                    265:                        {
                    266:                                if (NT_SUCCESS (request->Item->Status))
                    267:                                        memcpy (request->OrigDataBufferFragment, request->Data, request->Length);
                    268: 
                    269:                                ReleaseFragmentBuffer (queue, request->Data);
                    270:                                request->Data = request->OrigDataBufferFragment;
                    271: 
                    272:                                ExInterlockedInsertTailList (&queue->CompletionThreadQueue, &request->CompletionListEntry, &queue->CompletionThreadQueueLock);
                    273:                                KeSetEvent (&queue->CompletionThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
                    274:                        }
1.1       root      275:                }
                    276:        }
                    277: 
                    278:        PsTerminateSystemThread (STATUS_SUCCESS);
                    279: }
                    280: 
                    281: 
                    282: static NTSTATUS OnPassedIrpCompleted (PDEVICE_OBJECT filterDeviceObject, PIRP irp, EncryptedIoQueueItem *item)
                    283: {
                    284:        if (irp->PendingReturned)
                    285:                IoMarkIrpPending (irp);
                    286: 
1.1.1.5 ! root      287:        OnItemCompleted (item, TRUE);
1.1       root      288:        return STATUS_CONTINUE_COMPLETION;
                    289: }
                    290: 
                    291: 
                    292: static VOID MainThreadProc (PVOID threadArg)
                    293: {
                    294:        EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
                    295:        PLIST_ENTRY listEntry;
                    296:        EncryptedIoQueueItem *item;
                    297: 
                    298:        LARGE_INTEGER fragmentOffset;
                    299:        ULONG dataRemaining;
                    300:        PUCHAR activeFragmentBuffer = queue->FragmentBufferA;
                    301:        PUCHAR dataBuffer;
                    302:        EncryptedIoRequest *request;
                    303:        uint64 intersectStart;
                    304:        uint32 intersectLength;
                    305: 
1.1.1.5 ! root      306:        int mdlWaitTime;
        !           307:        LARGE_INTEGER mdlWaitInterval;
        !           308:        mdlWaitInterval.QuadPart = TC_ENC_IO_QUEUE_MEM_ALLOC_RETRY_DELAY * -10000;
        !           309: 
        !           310:        if (IsEncryptionThreadPoolRunning())
        !           311:                KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
        !           312: 
1.1       root      313:        while (!queue->ThreadExitRequested)
                    314:        {
                    315:                if (!NT_SUCCESS (KeWaitForSingleObject (&queue->MainThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
                    316:                        continue;
                    317: 
                    318:                while ((listEntry = ExInterlockedRemoveHeadList (&queue->MainThreadQueue, &queue->MainThreadQueueLock)))
                    319:                {
1.1.1.5 ! root      320:                        PIRP irp = CONTAINING_RECORD (listEntry, IRP, Tail.Overlay.ListEntry);
        !           321:                        PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
        !           322:                        
1.1       root      323:                        if (queue->Suspended)
                    324:                                KeWaitForSingleObject (&queue->QueueResumedEvent, Executive, KernelMode, FALSE, NULL);
1.1.1.5 ! root      325: 
        !           326:                        item = AllocateMemoryWithTimeout (sizeof (EncryptedIoQueueItem), TC_ENC_IO_QUEUE_MEM_ALLOC_RETRY_DELAY, TC_ENC_IO_QUEUE_MEM_ALLOC_TIMEOUT);
        !           327:                        if (!item)
        !           328:                        {
        !           329:                                EncryptedIoQueueItem stackItem;
        !           330:                                stackItem.Queue = queue;
        !           331:                                stackItem.OriginalIrp = irp;
        !           332:                                stackItem.Status = STATUS_INSUFFICIENT_RESOURCES;
        !           333: 
        !           334:                                TCCompleteDiskIrp (irp, STATUS_INSUFFICIENT_RESOURCES, 0);
        !           335:                                OnItemCompleted (&stackItem, FALSE);
        !           336:                                continue;
1.1       root      337:                        }
1.1.1.5 ! root      338: 
        !           339:                        item->Queue = queue;
        !           340:                        item->OriginalIrp = irp;
        !           341:                        item->OutstandingRequestCount = 0;
        !           342:                        item->Status = STATUS_SUCCESS;
        !           343: 
        !           344:                        IoSetCancelRoutine (irp, NULL);
        !           345:                        if (irp->Cancel)
1.1       root      346:                        {
                    347:                                CompleteOriginalIrp (item, STATUS_CANCELLED, 0);
                    348:                                continue;
                    349:                        }
                    350: 
1.1.1.5 ! root      351:                        switch (irpSp->MajorFunction)
        !           352:                        {
        !           353:                        case IRP_MJ_READ:
        !           354:                                item->Write = FALSE;
        !           355:                                item->OriginalOffset = irpSp->Parameters.Read.ByteOffset;
        !           356:                                item->OriginalLength = irpSp->Parameters.Read.Length;
        !           357:                                break;
        !           358: 
        !           359:                        case IRP_MJ_WRITE:
        !           360:                                item->Write = TRUE;
        !           361:                                item->OriginalOffset = irpSp->Parameters.Write.ByteOffset;
        !           362:                                item->OriginalLength = irpSp->Parameters.Write.Length;
        !           363:                                break;
        !           364: 
        !           365:                        default:
        !           366:                                CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
        !           367:                                continue;
        !           368:                        }
        !           369: 
1.1       root      370:                        // Pass the IRP if the drive is not encrypted
                    371:                        if (queue->IsFilterDevice && (queue->EncryptedAreaStart == -1 || queue->EncryptedAreaEnd == -1))
                    372:                        {
1.1.1.5 ! root      373:                                IoCopyCurrentIrpStackLocationToNext (irp);
        !           374:                                IoSetCompletionRoutine (irp, OnPassedIrpCompleted, item, TRUE, TRUE, TRUE);
        !           375:                                IoCallDriver (queue->LowerDeviceObject, irp);
1.1       root      376:                                continue;
                    377:                        }
                    378: 
                    379:                        // Validate offset and length
1.1.1.3   root      380:                        if (item->OriginalLength == 0
                    381:                                || (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
                    382:                                || (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
1.1       root      383:                                || (!queue->IsFilterDevice && item->OriginalOffset.QuadPart + item->OriginalLength > queue->VirtualDeviceLength))
                    384:                        {
                    385:                                CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
                    386:                                continue;
                    387:                        }
                    388: 
1.1.1.5 ! root      389:                        //Dump ("--- Queue %c %I64d  (%I64d)  %d  out=%d\n", item->Write ? 'W' : 'R', item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart / 1024 / 1024, item->OriginalLength, queue->OutstandingIoCount);
        !           390: 
1.1       root      391:                        if (!queue->IsFilterDevice)
                    392:                        {
1.1.1.3   root      393:                                // Adjust the offset for host file or device
                    394:                                if (queue->CryptoInfo->hiddenVolume)
                    395:                                        item->OriginalOffset.QuadPart += queue->CryptoInfo->hiddenVolumeOffset;
                    396:                                else
                    397:                                        item->OriginalOffset.QuadPart += queue->CryptoInfo->volDataAreaOffset; 
                    398: 
1.1       root      399:                                // Hidden volume protection
                    400:                                if (item->Write && queue->CryptoInfo->bProtectHiddenVolume)
                    401:                                {
                    402:                                        // If there has already been a write operation denied in order to protect the
                    403:                                        // hidden volume (since the volume mount time)
                    404:                                        if (queue->CryptoInfo->bHiddenVolProtectionAction)      
                    405:                                        {
                    406:                                                // Do not allow writing to this volume anymore. This is to fake a complete volume
                    407:                                                // or system failure (otherwise certain kinds of inconsistency within the file
                    408:                                                // system could indicate that this volume has used hidden volume protection).
                    409:                                                CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
                    410:                                                continue;
                    411:                                        }
                    412: 
                    413:                                        // Verify that no byte is going to be written to the hidden volume area
1.1.1.3   root      414:                                        if (RegionsOverlap ((unsigned __int64) item->OriginalOffset.QuadPart,
                    415:                                                (unsigned __int64) item->OriginalOffset.QuadPart + item->OriginalLength - 1,
1.1       root      416:                                                queue->CryptoInfo->hiddenVolumeOffset,
1.1.1.5 ! root      417:                                                (unsigned __int64) queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1))
1.1       root      418:                                        {
1.1.1.5 ! root      419:                                                Dump ("Hidden volume protection triggered: write %I64d-%I64d (protected %I64d-%I64d)\n", item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, queue->CryptoInfo->hiddenVolumeOffset, queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1);
1.1       root      420:                                                queue->CryptoInfo->bHiddenVolProtectionAction = TRUE;
                    421: 
                    422:                                                // Deny this write operation to prevent the hidden volume from being overwritten
                    423:                                                CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
                    424:                                                continue;
                    425:                                        }
                    426:                                }
                    427:                        }
                    428: 
                    429:                        // Original IRP data buffer
1.1.1.5 ! root      430:                        mdlWaitTime = 0;
        !           431:                        while (TRUE)
        !           432:                        {
        !           433:                                dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority);
        !           434: 
        !           435:                                if (dataBuffer || mdlWaitTime >= TC_ENC_IO_QUEUE_MEM_ALLOC_TIMEOUT)
        !           436:                                        break;
        !           437: 
        !           438:                                KeDelayExecutionThread (KernelMode, FALSE, &mdlWaitInterval);
        !           439:                                mdlWaitTime += TC_ENC_IO_QUEUE_MEM_ALLOC_RETRY_DELAY;
        !           440:                        }
        !           441: 
1.1       root      442:                        if (dataBuffer == NULL)
                    443:                        {
                    444:                                CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
                    445:                                continue;
                    446:                        }
                    447: 
                    448:                        // Divide data block to fragments to enable efficient overlapping of encryption and IO operations
                    449: 
                    450:                        dataRemaining = item->OriginalLength;
                    451:                        fragmentOffset = item->OriginalOffset;
                    452: 
                    453:                        while (dataRemaining > 0)
                    454:                        {
                    455:                                BOOL isLastFragment = dataRemaining <= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    456:                                
                    457:                                ULONG dataFragmentLength = isLastFragment ? dataRemaining : TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    458:                                activeFragmentBuffer = (activeFragmentBuffer == queue->FragmentBufferA ? queue->FragmentBufferB : queue->FragmentBufferA);
                    459: 
                    460:                                // Create IO request
1.1.1.5 ! root      461:                                request = (EncryptedIoRequest *) AllocateMemoryWithTimeout (sizeof (EncryptedIoRequest), TC_ENC_IO_QUEUE_MEM_ALLOC_RETRY_DELAY, TC_ENC_IO_QUEUE_MEM_ALLOC_TIMEOUT);
1.1       root      462:                                if (!request)
                    463:                                {
1.1.1.3   root      464:                                        while (InterlockedExchangeAdd (&item->OutstandingRequestCount, 0) > 0)
                    465:                                                KeWaitForSingleObject (&queue->RequestCompletedEvent, Executive, KernelMode, FALSE, NULL);
                    466: 
1.1       root      467:                                        CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
                    468:                                        break;
                    469:                                }
                    470: 
                    471:                                request->Item = item;
                    472:                                request->CompleteOriginalIrp = isLastFragment;
                    473:                                request->Offset = fragmentOffset;
                    474:                                request->Data = activeFragmentBuffer;
                    475:                                request->OrigDataBufferFragment = dataBuffer;
                    476:                                request->Length = dataFragmentLength;
                    477: 
                    478:                                if (queue->IsFilterDevice)
                    479:                                {
                    480:                                        // Get intersection of data fragment with encrypted area
                    481:                                        GetIntersection (fragmentOffset.QuadPart, dataFragmentLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength);
                    482: 
                    483:                                        request->EncryptedOffset = intersectStart - fragmentOffset.QuadPart;
                    484:                                        request->EncryptedLength = intersectLength;
                    485:                                }
                    486:                                else
                    487:                                {
                    488:                                        request->EncryptedOffset = 0;
                    489:                                        request->EncryptedLength = dataFragmentLength;
                    490:                                }
                    491: 
                    492:                                AcquireFragmentBuffer (queue, activeFragmentBuffer);
                    493: 
                    494:                                if (item->Write)
                    495:                                {
                    496:                                        // Encrypt data
                    497:                                        memcpy (activeFragmentBuffer, dataBuffer, dataFragmentLength);
                    498: 
                    499:                                        if (request->EncryptedLength > 0)
                    500:                                        {
                    501:                                                UINT64_STRUCT dataUnit;
                    502:                                                ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length);
                    503: 
                    504:                                                dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE;
                    505: 
1.1.1.3   root      506:                                                if (queue->CryptoInfo->bPartitionInInactiveSysEncScope)
                    507:                                                        dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value;
1.1.1.5 ! root      508:                                                else if (queue->RemapEncryptedArea)
        !           509:                                                        dataUnit.Value += queue->RemappedAreaDataUnitOffset;
        !           510:                                                                
1.1.1.3   root      511:                                                EncryptDataUnits (activeFragmentBuffer + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
1.1       root      512:                                        }
                    513:                                }
                    514: 
                    515:                                // Queue IO request
1.1.1.3   root      516:                                InterlockedIncrement (&item->OutstandingRequestCount);
                    517: 
1.1       root      518:                                ExInterlockedInsertTailList (&queue->IoThreadQueue, &request->ListEntry, &queue->IoThreadQueueLock);
1.1.1.3   root      519:                                KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      520: 
                    521:                                if (isLastFragment)
                    522:                                        break;
                    523: 
                    524:                                dataRemaining -= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    525:                                dataBuffer += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    526:                                fragmentOffset.QuadPart += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    527:                        }
                    528:                }
                    529:        }
                    530: 
                    531:        PsTerminateSystemThread (STATUS_SUCCESS);
                    532: }
                    533: 
                    534: 
                    535: NTSTATUS EncryptedIoQueueAddIrp (EncryptedIoQueue *queue, PIRP irp)
                    536: {
                    537:        NTSTATUS status;
                    538: 
                    539:        InterlockedIncrement (&queue->OutstandingIoCount);
                    540:        if (queue->StopPending)
                    541:        {
                    542:                Dump ("STATUS_DEVICE_NOT_READY  out=%d\n", queue->OutstandingIoCount);
                    543:                status = STATUS_DEVICE_NOT_READY;
                    544:                goto err;
                    545:        }
                    546: 
                    547:        if (queue->IsFilterDevice)
                    548:        {
                    549:                status = IoAcquireRemoveLock (&queue->RemoveLock, irp);
                    550:                if (!NT_SUCCESS (status))
                    551:                        goto err;
                    552:        }
                    553: 
1.1.1.5 ! root      554:        //Dump ("Queue irp %p  out=%d\n", irp, queue->OutstandingIoCount);
1.1       root      555:        IoMarkIrpPending (irp);
                    556: 
1.1.1.5 ! root      557:        ExInterlockedInsertTailList (&queue->MainThreadQueue, &irp->Tail.Overlay.ListEntry, &queue->MainThreadQueueLock);
1.1.1.3   root      558:        KeSetEvent (&queue->MainThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      559:        
                    560:        return STATUS_PENDING;
                    561: 
                    562: err:
                    563:        DecrementOutstandingIoCount (queue);
                    564:        return status;
                    565: }
                    566: 
                    567: 
                    568: NTSTATUS EncryptedIoQueueHoldWhenIdle (EncryptedIoQueue *queue, int64 timeout)
                    569: {
                    570:        NTSTATUS status;
                    571:        ASSERT (!queue->Suspended);
                    572: 
                    573:        queue->SuspendPending = TRUE;
                    574:        
                    575:        while (TRUE)
                    576:        {
                    577:                while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
                    578:                {
                    579:                        LARGE_INTEGER waitTimeout;
                    580: 
                    581:                        waitTimeout.QuadPart = timeout * -10000;
                    582:                        status = KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, timeout != 0 ? &waitTimeout : NULL);
                    583: 
                    584:                        if (status == STATUS_TIMEOUT)
                    585:                                status = STATUS_UNSUCCESSFUL;
                    586: 
                    587:                        if (!NT_SUCCESS (status))
                    588:                                return status;
                    589:                }
                    590: 
                    591:                KeClearEvent (&queue->QueueResumedEvent);
                    592:                queue->Suspended = TRUE;
                    593: 
                    594:                if (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) == 0)
                    595:                        break;
                    596: 
                    597:                queue->Suspended = FALSE;
1.1.1.3   root      598:                KeSetEvent (&queue->QueueResumedEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      599: 
                    600:        }
                    601: 
                    602:        queue->SuspendPending = FALSE;
                    603:        //Dump ("Queue suspended  out=%d\n", queue->OutstandingIoCount);
                    604: 
                    605:        return STATUS_SUCCESS;
                    606: }
                    607: 
                    608: 
                    609: BOOL EncryptedIoQueueIsSuspended (EncryptedIoQueue *queue)
                    610: {
                    611:        return queue->Suspended;
                    612: }
                    613: 
                    614: 
                    615: BOOL EncryptedIoQueueIsRunning (EncryptedIoQueue *queue)
                    616: {
                    617:        return !queue->StopPending;
                    618: }
                    619: 
                    620: 
                    621: NTSTATUS EncryptedIoQueueResumeFromHold (EncryptedIoQueue *queue)
                    622: {
                    623:        ASSERT (queue->Suspended);
                    624:        
                    625:        queue->Suspended = FALSE;
1.1.1.3   root      626:        KeSetEvent (&queue->QueueResumedEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      627: 
                    628:        //Dump ("Queue resumed  out=%d\n", queue->OutstandingIoCount);
                    629: 
                    630:        return STATUS_SUCCESS;
                    631: }
                    632: 
                    633: 
1.1.1.2   root      634: NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue, PEPROCESS process)
1.1       root      635: {
                    636:        NTSTATUS status;
                    637:        queue->ThreadExitRequested = FALSE;
                    638: 
                    639:        KeInitializeEvent (&queue->NoOutstandingIoEvent, SynchronizationEvent, FALSE);
1.1.1.3   root      640:        KeInitializeEvent (&queue->RequestCompletedEvent, SynchronizationEvent, FALSE);
1.1       root      641:        KeInitializeEvent (&queue->QueueResumedEvent, SynchronizationEvent, FALSE);
                    642: 
                    643:        queue->FragmentBufferA = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
                    644:        if (!queue->FragmentBufferA)
                    645:                goto noMemory;
                    646: 
                    647:        queue->FragmentBufferB = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
                    648:        if (!queue->FragmentBufferB)
                    649:                goto noMemory;
                    650: 
                    651:        KeInitializeEvent (&queue->FragmentBufferAFreeEvent, SynchronizationEvent, TRUE);
                    652:        KeInitializeEvent (&queue->FragmentBufferBFreeEvent, SynchronizationEvent, TRUE);
                    653: 
                    654:        // Main thread
                    655:        InitializeListHead (&queue->MainThreadQueue);
                    656:        KeInitializeSpinLock (&queue->MainThreadQueueLock);
                    657:        KeInitializeEvent (&queue->MainThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
                    658: 
                    659:        status = TCStartThread (MainThreadProc, queue, &queue->MainThread);
                    660:        if (!NT_SUCCESS (status))
                    661:                goto err;
                    662: 
                    663:        // IO thread
                    664:        InitializeListHead (&queue->IoThreadQueue);
                    665:        KeInitializeSpinLock (&queue->IoThreadQueueLock);
                    666:        KeInitializeEvent (&queue->IoThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
                    667: 
1.1.1.2   root      668:        status = TCStartThreadInProcess (IoThreadProc, queue, &queue->IoThread, process);
1.1       root      669:        if (!NT_SUCCESS (status))
                    670:        {
                    671:                queue->ThreadExitRequested = TRUE;
                    672:                TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
                    673:                goto err;
                    674:        }
                    675: 
                    676:        // Completion thread
                    677:        InitializeListHead (&queue->CompletionThreadQueue);
                    678:        KeInitializeSpinLock (&queue->CompletionThreadQueueLock);
                    679:        KeInitializeEvent (&queue->CompletionThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
                    680: 
                    681:        status = TCStartThread (CompletionThreadProc, queue, &queue->CompletionThread);
                    682:        if (!NT_SUCCESS (status))
                    683:        {
                    684:                queue->ThreadExitRequested = TRUE;
                    685:                TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
                    686:                TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent);
                    687:                goto err;
                    688:        }
                    689: 
                    690:        queue->StopPending = FALSE;
                    691:        Dump ("Queue started\n");
                    692:        return STATUS_SUCCESS;
                    693: 
                    694: noMemory:
                    695:        status = STATUS_INSUFFICIENT_RESOURCES;
                    696: 
                    697: err:
                    698:        if (queue->FragmentBufferA)
                    699:                TCfree (queue->FragmentBufferA);
                    700:        if (queue->FragmentBufferB)
                    701:                TCfree (queue->FragmentBufferB);
                    702: 
                    703:        return status;
                    704: }
                    705: 
                    706: 
                    707: NTSTATUS EncryptedIoQueueStop (EncryptedIoQueue *queue)
                    708: {
                    709:        ASSERT (!queue->StopPending);
                    710:        queue->StopPending = TRUE;
                    711:        
                    712:        while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
                    713:        {
                    714:                KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, NULL);
                    715:        }
                    716: 
                    717:        Dump ("Queue stopping  out=%d\n", queue->OutstandingIoCount);
                    718: 
                    719:        queue->ThreadExitRequested = TRUE;
                    720: 
                    721:        TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
                    722:        TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent);
                    723:        TCStopThread (queue->CompletionThread, &queue->CompletionThreadQueueNotEmptyEvent);
                    724: 
                    725:        TCfree (queue->FragmentBufferA);
                    726:        TCfree (queue->FragmentBufferB);
                    727: 
                    728:        Dump ("Queue stopped  out=%d\n", queue->OutstandingIoCount);
                    729:        return STATUS_SUCCESS;
                    730: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.