|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.