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