|
|
1.1.1.10 root 1: /*
1.1.1.12 root 2: Legal Notice: Some portions of the source code contained in this file were
3: derived from the source code of Encryption for the Masses 2.02a, which is
4: Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
5: Agreement for Encryption for the Masses'. Modifications and additions to
6: the original source code (contained in this file) and all other portions of
7: this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
1.1.1.15! root 8: by the TrueCrypt License 2.6 the full text of which is contained in the
1.1.1.12 root 9: file License.txt included in TrueCrypt binary and source code distribution
1.1.1.10 root 10: packages. */
1.1 root 11:
12: #include "TCdefs.h"
1.1.1.15! root 13: #include <wchar.h>
1.1.1.6 root 14: #include "Crypto.h"
15: #include "Volumes.h"
1.1 root 16:
1.1.1.6 root 17: #include "Apidrvr.h"
1.1.1.14 root 18: #include "DriveFilter.h"
1.1.1.6 root 19: #include "Ntdriver.h"
20: #include "Ntvol.h"
1.1.1.14 root 21: #include "VolumeFilter.h"
1.1 root 22:
1.1.1.13 root 23: #include "Boot/Windows/BootCommon.h"
24:
1.1.1.6 root 25: #include "Cache.h"
1.1 root 26:
1.1.1.10 root 27: #if 0 && _DEBUG
28: #define EXTRA_INFO 1
29: #endif
1.1 root 30:
31: #pragma warning( disable : 4127 )
32:
1.1.1.14 root 33: volatile BOOL ProbingHostDeviceForWrite = FALSE;
34:
35:
1.1.1.15! root 36: NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
1.1 root 37: PEXTENSION Extension,
1.1.1.6 root 38: MOUNT_STRUCT *mount,
1.1 root 39: PWSTR pwszMountVolume,
40: BOOL bRawDevice)
41: {
42: FILE_STANDARD_INFORMATION FileStandardInfo;
43: FILE_BASIC_INFORMATION FileBasicInfo;
44: OBJECT_ATTRIBUTES oaFileAttributes;
45: UNICODE_STRING FullFileName;
46: IO_STATUS_BLOCK IoStatusBlock;
1.1.1.6 root 47: PCRYPTO_INFO cryptoInfoPtr = NULL;
48: PCRYPTO_INFO tmpCryptoInfo = NULL;
1.1 root 49: LARGE_INTEGER lDiskLength;
1.1.1.15! root 50: __int64 partitionStartingOffset = 0;
1.1.1.6 root 51: int volumeType;
1.1.1.4 root 52: char *readBuffer = 0;
1.1.1.5 root 53: NTSTATUS ntStatus = 0;
1.1.1.15! root 54: BOOL forceAccessCheck = (!bRawDevice && !(OsMajorVersion == 5 &&OsMinorVersion == 0)); // Windows 2000 does not support OBJ_FORCE_ACCESS_CHECK attribute
1.1 root 55:
56: Extension->pfoDeviceFile = NULL;
57: Extension->hDeviceFile = NULL;
1.1.1.6 root 58: Extension->bTimeStampValid = FALSE;
1.1 root 59:
1.1.1.4 root 60: RtlInitUnicodeString (&FullFileName, pwszMountVolume);
1.1.1.15! root 61: InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | (forceAccessCheck ? OBJ_FORCE_ACCESS_CHECK : 0), NULL, NULL);
1.1.1.4 root 62: KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE);
63:
1.1.1.15! root 64: if (Extension->SecurityClientContextValid)
! 65: {
! 66: ntStatus = SeImpersonateClientEx (&Extension->SecurityClientContext, NULL);
! 67: if (!NT_SUCCESS (ntStatus))
! 68: goto error;
! 69: }
! 70:
1.1.1.4 root 71: // If we are opening a device, query its size first
72: if (bRawDevice)
1.1 root 73: {
1.1.1.5 root 74: PARTITION_INFORMATION pi;
1.1.1.10 root 75: PARTITION_INFORMATION_EX pix;
1.1.1.15! root 76: LARGE_INTEGER diskLengthInfo;
1.1.1.4 root 77: DISK_GEOMETRY dg;
1.1 root 78:
1.1.1.4 root 79: ntStatus = IoGetDeviceObjectPointer (&FullFileName,
80: FILE_READ_DATA,
81: &Extension->pfoDeviceFile,
82: &Extension->pFsdDevice);
83:
84: if (!NT_SUCCESS (ntStatus))
85: goto error;
86:
1.1.1.12 root 87: if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY, (char *) &dg, sizeof (dg))))
1.1.1.4 root 88: {
1.1.1.10 root 89: lDiskLength.QuadPart = dg.Cylinders.QuadPart * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.BytesPerSector;
90: mount->BytesPerSector = dg.BytesPerSector;
1.1.1.4 root 91: }
1.1.1.5 root 92: else
1.1.1.10 root 93: lDiskLength.QuadPart = 0;
1.1.1.4 root 94:
1.1.1.10 root 95: // Drive geometry is used only when IOCTL_DISK_GET_PARTITION_INFO fails
1.1.1.12 root 96: if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO_EX, (char *) &pix, sizeof (pix))))
1.1.1.13 root 97: {
1.1.1.10 root 98: lDiskLength.QuadPart = pix.PartitionLength.QuadPart;
1.1.1.13 root 99: partitionStartingOffset = pix.StartingOffset.QuadPart;
100: }
1.1.1.10 root 101: // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
1.1.1.12 root 102: else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO, (char *) &pi, sizeof (pi))))
1.1.1.13 root 103: {
1.1.1.10 root 104: lDiskLength.QuadPart = pi.PartitionLength.QuadPart;
1.1.1.13 root 105: partitionStartingOffset = pi.StartingOffset.QuadPart;
106: }
1.1.1.15! root 107: else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_LENGTH_INFO, &diskLengthInfo, sizeof (diskLengthInfo))))
! 108: {
! 109: lDiskLength = diskLengthInfo;
! 110: }
1.1 root 111:
1.1.1.14 root 112: ProbingHostDeviceForWrite = TRUE;
113:
114: if (!mount->bMountReadOnly
115: && TCSendHostDeviceIoControlRequest (DeviceObject, Extension,
116: IsHiddenSystemRunning() ? TC_IOCTL_DISK_IS_WRITABLE : IOCTL_DISK_IS_WRITABLE, NULL, 0) == STATUS_MEDIA_WRITE_PROTECTED)
1.1.1.10 root 117: {
118: mount->bMountReadOnly = TRUE;
119: DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
1.1.1.4 root 120: }
1.1.1.14 root 121:
122: ProbingHostDeviceForWrite = FALSE;
1.1.1.4 root 123: }
1.1 root 124:
1.1.1.10 root 125: if (mount->BytesPerSector == 0)
126: mount->BytesPerSector = SECTOR_SIZE;
127:
128: Extension->HostBytesPerSector = mount->BytesPerSector;
129:
1.1.1.4 root 130: // Open the volume hosting file/device
131: if (!mount->bMountReadOnly)
132: {
133: ntStatus = ZwCreateFile (&Extension->hDeviceFile,
134: GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
135: &oaFileAttributes,
136: &IoStatusBlock,
137: NULL,
138: FILE_ATTRIBUTE_NORMAL |
139: FILE_ATTRIBUTE_SYSTEM,
140: mount->bExclusiveAccess ? 0 : FILE_SHARE_READ | FILE_SHARE_WRITE,
141: FILE_OPEN,
1.1.1.10 root 142: FILE_RANDOM_ACCESS |
1.1.1.4 root 143: FILE_WRITE_THROUGH |
1.1.1.10 root 144: (Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
1.1.1.4 root 145: FILE_SYNCHRONOUS_IO_NONALERT,
146: NULL,
147: 0);
148: }
1.1 root 149:
1.1.1.10 root 150: /* 26-4-99 NT for some partitions returns this code, it is really a access denied */
1.1 root 151: if (ntStatus == 0xc000001b)
152: ntStatus = STATUS_ACCESS_DENIED;
1.1.1.6 root 153:
1.1.1.4 root 154: if (mount->bMountReadOnly || ntStatus == STATUS_ACCESS_DENIED)
1.1 root 155: {
156: ntStatus = ZwCreateFile (&Extension->hDeviceFile,
1.1.1.4 root 157: GENERIC_READ | SYNCHRONIZE,
158: &oaFileAttributes,
159: &IoStatusBlock,
160: NULL,
161: FILE_ATTRIBUTE_NORMAL |
162: FILE_ATTRIBUTE_SYSTEM,
1.1.1.8 root 163: mount->bExclusiveAccess ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE,
1.1.1.4 root 164: FILE_OPEN,
1.1.1.10 root 165: FILE_RANDOM_ACCESS |
1.1.1.4 root 166: FILE_WRITE_THROUGH |
1.1.1.11 root 167: (Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
1.1.1.4 root 168: FILE_SYNCHRONOUS_IO_NONALERT,
169: NULL,
170: 0);
1.1.1.11 root 171:
1.1 root 172: Extension->bReadOnly = TRUE;
1.1.1.11 root 173: DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
1.1 root 174: }
175: else
176: Extension->bReadOnly = FALSE;
177:
178: /* 26-4-99 NT for some partitions returns this code, it is really a
1.1.1.4 root 179: access denied */
1.1 root 180: if (ntStatus == 0xc000001b)
181: {
182: /* Partitions which return this code can still be opened with
1.1.1.4 root 183: FILE_SHARE_READ but this causes NT problems elsewhere in
184: particular if you do FILE_SHARE_READ NT will die later if
1.1.1.12 root 185: anyone even tries to open the partition (or file for that
1.1.1.4 root 186: matter...) */
1.1 root 187: ntStatus = STATUS_SHARING_VIOLATION;
188: }
189:
190: if (!NT_SUCCESS (ntStatus))
191: {
192: goto error;
193: }
194:
1.1.1.4 root 195: // If we have opened a file, query its size now
1.1 root 196: if (bRawDevice == FALSE)
197: {
198: ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
1.1.1.4 root 199: &IoStatusBlock,
200: &FileBasicInfo,
201: sizeof (FileBasicInfo),
202: FileBasicInformation);
1.1 root 203:
204: if (NT_SUCCESS (ntStatus))
1.1.1.4 root 205: {
1.1.1.6 root 206: if (mount->bPreserveTimestamp)
207: {
208: /* Remember the container timestamp. (Used to reset access/modification file date/time
209: of file-hosted volumes upon dismount or after unsuccessful mount attempt to preserve
210: plausible deniability of hidden volumes.) */
211: Extension->fileCreationTime = FileBasicInfo.CreationTime;
212: Extension->fileLastAccessTime = FileBasicInfo.LastAccessTime;
213: Extension->fileLastWriteTime = FileBasicInfo.LastWriteTime;
214: Extension->fileLastChangeTime = FileBasicInfo.ChangeTime;
215: Extension->bTimeStampValid = TRUE;
216: }
1.1.1.4 root 217:
1.1 root 218: ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
1.1.1.4 root 219: &IoStatusBlock,
220: &FileStandardInfo,
221: sizeof (FileStandardInfo),
222: FileStandardInformation);
223: }
1.1 root 224:
225: if (!NT_SUCCESS (ntStatus))
226: {
227: Dump ("ZwQueryInformationFile failed while opening file: NTSTATUS 0x%08x\n",
1.1.1.4 root 228: ntStatus);
1.1 root 229: goto error;
230: }
1.1.1.4 root 231:
232: lDiskLength.QuadPart = FileStandardInfo.EndOfFile.QuadPart;
1.1 root 233:
234: if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED)
235: {
236: Dump ("File \"%ls\" is marked as compressed - not supported!\n", pwszMountVolume);
237: mount->nReturnCode = ERR_COMPRESSION_NOT_SUPPORTED;
238: ntStatus = STATUS_SUCCESS;
239: goto error;
240: }
241:
242: ntStatus = ObReferenceObjectByHandle (Extension->hDeviceFile,
1.1.1.4 root 243: FILE_ALL_ACCESS,
244: *IoFileObjectType,
245: KernelMode,
246: &Extension->pfoDeviceFile,
247: 0);
1.1 root 248:
249: if (!NT_SUCCESS (ntStatus))
250: {
251: goto error;
252: }
253:
1.1.1.4 root 254: /* Get the FSD device for the file (probably either NTFS or FAT) */
1.1 root 255: Extension->pFsdDevice = IoGetRelatedDeviceObject (Extension->pfoDeviceFile);
256: }
1.1.1.15! root 257: else
! 258: {
! 259: // Try to gain "raw" access to the partition in case there is a live filesystem on it (otherwise,
! 260: // the NTFS driver guards hidden sectors and prevents mounting using a backup header e.g. after the user
! 261: // accidentally quick-formats a dismounted partition-hosted TrueCrypt volume as NTFS).
! 262:
! 263: PFILE_OBJECT pfoTmpDeviceFile = NULL;
! 264:
! 265: if (NT_SUCCESS (ObReferenceObjectByHandle (Extension->hDeviceFile, FILE_ALL_ACCESS, *IoFileObjectType, KernelMode, &pfoTmpDeviceFile, NULL))
! 266: && pfoTmpDeviceFile != NULL)
! 267: {
! 268: TCFsctlCall (pfoTmpDeviceFile, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0);
! 269: ObDereferenceObject (pfoTmpDeviceFile);
! 270: }
! 271: }
1.1 root 272:
1.1.1.4 root 273: // Check volume size
1.1.1.14 root 274: if (lDiskLength.QuadPart < TC_MIN_VOLUME_SIZE_LEGACY || lDiskLength.QuadPart > TC_MAX_VOLUME_SIZE)
1.1.1.4 root 275: {
276: mount->nReturnCode = ERR_VOL_SIZE_WRONG;
277: ntStatus = STATUS_SUCCESS;
278: goto error;
279: }
1.1.1.6 root 280:
1.1.1.4 root 281: Extension->DiskLength = lDiskLength.QuadPart;
1.1 root 282:
1.1.1.15! root 283: readBuffer = TCalloc (max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, PAGE_SIZE));
1.1.1.4 root 284: if (readBuffer == NULL)
285: {
286: ntStatus = STATUS_INSUFFICIENT_RESOURCES;
287: goto error;
288: }
1.1 root 289:
1.1.1.6 root 290: // Go through all volume types (e.g., normal, hidden)
1.1.1.14 root 291: for (volumeType = TC_VOLUME_TYPE_NORMAL;
292: volumeType < TC_VOLUME_TYPE_COUNT;
1.1.1.6 root 293: volumeType++)
1.1.1.4 root 294: {
1.1.1.14 root 295: Dump ("Trying to open volume type %d\n", volumeType);
296:
1.1.1.13 root 297: if (mount->bPartitionInInactiveSysEncScope
1.1.1.14 root 298: && volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
1.1.1.13 root 299: continue;
300:
1.1.1.6 root 301: /* Read the volume header */
1.1 root 302:
1.1.1.14 root 303: if (!mount->bPartitionInInactiveSysEncScope
304: || (mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_HIDDEN))
1.1.1.13 root 305: {
1.1.1.14 root 306: // Header of a volume that is not within the scope of system encryption, or
307: // header of a system hidden volume (containing a hidden OS)
308:
309: LARGE_INTEGER headerOffset;
310:
311: if (mount->UseBackupHeader && lDiskLength.QuadPart <= TC_TOTAL_VOLUME_HEADERS_SIZE)
312: continue;
313:
314: switch (volumeType)
315: {
316: case TC_VOLUME_TYPE_NORMAL:
317: headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
318: break;
319:
320: case TC_VOLUME_TYPE_HIDDEN:
321: if (lDiskLength.QuadPart <= TC_VOLUME_HEADER_GROUP_SIZE)
322: continue;
323:
324: headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_HIDDEN_VOLUME_HEADER_OFFSET : TC_HIDDEN_VOLUME_HEADER_OFFSET;
325: break;
326:
327: case TC_VOLUME_TYPE_HIDDEN_LEGACY:
328: if (mount->UseBackupHeader)
329: continue;
330:
331: headerOffset.QuadPart = lDiskLength.QuadPart - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY;
332: break;
333: }
334:
335: Dump ("Reading volume header at %I64d\n", headerOffset.QuadPart);
1.1.1.13 root 336:
337: ntStatus = ZwReadFile (Extension->hDeviceFile,
1.1.1.6 root 338: NULL,
339: NULL,
340: NULL,
341: &IoStatusBlock,
342: readBuffer,
1.1.1.14 root 343: TC_VOLUME_HEADER_EFFECTIVE_SIZE,
344: &headerOffset,
1.1.1.6 root 345: NULL);
1.1.1.13 root 346: }
347: else
348: {
349: // Header of a partition that is within the scope of system encryption
350:
351: WCHAR parentDrivePath [47+1] = {0};
352: HANDLE hParentDeviceFile = NULL;
353: UNICODE_STRING FullParentPath;
354: OBJECT_ATTRIBUTES oaParentFileAttributes;
355: LARGE_INTEGER parentKeyDataOffset;
356:
357: _snwprintf (parentDrivePath,
358: sizeof (parentDrivePath) / sizeof (WCHAR) - 1,
359: WIDE ("\\Device\\Harddisk%d\\Partition0"),
360: mount->nPartitionInInactiveSysEncScopeDriveNo);
361:
362: Dump ("Mounting partition within scope of system encryption (reading key data from: %ls)\n", parentDrivePath);
363:
364: RtlInitUnicodeString (&FullParentPath, parentDrivePath);
365: InitializeObjectAttributes (&oaParentFileAttributes, &FullParentPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
366:
367: ntStatus = ZwCreateFile (&hParentDeviceFile,
368: GENERIC_READ | SYNCHRONIZE,
369: &oaParentFileAttributes,
370: &IoStatusBlock,
371: NULL,
372: FILE_ATTRIBUTE_NORMAL |
373: FILE_ATTRIBUTE_SYSTEM,
374: FILE_SHARE_READ | FILE_SHARE_WRITE,
375: FILE_OPEN,
376: FILE_RANDOM_ACCESS |
377: FILE_WRITE_THROUGH |
378: (Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
379: FILE_SYNCHRONOUS_IO_NONALERT,
380: NULL,
381: 0);
382:
383: if (!NT_SUCCESS (ntStatus))
384: {
385: if (hParentDeviceFile != NULL)
386: ZwClose (hParentDeviceFile);
387:
388: Dump ("Cannot open %ls\n", parentDrivePath);
389:
390: goto error;
391: }
392:
1.1.1.14 root 393: parentKeyDataOffset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
1.1.1.13 root 394:
395: ntStatus = ZwReadFile (hParentDeviceFile,
396: NULL,
397: NULL,
398: NULL,
399: &IoStatusBlock,
400: readBuffer,
1.1.1.14 root 401: TC_VOLUME_HEADER_EFFECTIVE_SIZE,
1.1.1.13 root 402: &parentKeyDataOffset,
403: NULL);
404:
405: if (hParentDeviceFile != NULL)
406: ZwClose (hParentDeviceFile);
407: }
1.1.1.6 root 408:
1.1.1.15! root 409: if (!NT_SUCCESS (ntStatus) && ntStatus != STATUS_END_OF_FILE)
1.1 root 410: {
1.1.1.6 root 411: Dump ("Read failed: NTSTATUS 0x%08x\n", ntStatus);
1.1.1.14 root 412: goto error;
1.1 root 413: }
414:
1.1.1.15! root 415: if (ntStatus == STATUS_END_OF_FILE || IoStatusBlock.Information != TC_VOLUME_HEADER_EFFECTIVE_SIZE)
1.1.1.6 root 416: {
1.1.1.14 root 417: Dump ("Read didn't read enough data\n");
1.1.1.15! root 418:
! 419: // If FSCTL_ALLOW_EXTENDED_DASD_IO failed and there is a live filesystem on the partition, then the
! 420: // filesystem driver may report EOF when we are reading hidden sectors (when the filesystem is
! 421: // shorter than the partition). This can happen for example after the user quick-formats a dismounted
! 422: // partition-hosted TrueCrypt volume and then tries to mount the volume using the embedded backup header.
! 423: memset (readBuffer, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1.1.1.6 root 424: }
1.1 root 425:
1.1.1.6 root 426: /* Attempt to recognize the volume (decrypt the header) */
1.1 root 427:
1.1.1.15! root 428: ReadVolumeHeaderRecoveryMode = mount->RecoveryMode;
! 429:
1.1.1.14 root 430: if ((volumeType == TC_VOLUME_TYPE_HIDDEN || volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY) && mount->bProtectHiddenVolume)
1.1.1.6 root 431: {
1.1.1.15! root 432: mount->nReturnCode = ReadVolumeHeaderWCache (
1.1.1.14 root 433: FALSE,
1.1.1.6 root 434: mount->bCache,
435: readBuffer,
436: &mount->ProtectedHidVolPassword,
437: &tmpCryptoInfo);
438: }
439: else
440: {
1.1.1.15! root 441: mount->nReturnCode = ReadVolumeHeaderWCache (
1.1.1.14 root 442: mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_NORMAL,
1.1.1.6 root 443: mount->bCache,
444: readBuffer,
445: &mount->VolumePassword,
446: &Extension->cryptoInfo);
447: }
1.1.1.4 root 448:
1.1.1.15! root 449: ReadVolumeHeaderRecoveryMode = FALSE;
! 450:
1.1.1.6 root 451: if (mount->nReturnCode == 0 || mount->nReturnCode == ERR_CIPHER_INIT_WEAK_KEY)
452: {
453: /* Volume header successfully decrypted */
1.1 root 454:
1.1.1.14 root 455: Dump ("Volume header decrypted\n");
456: Dump ("Required program version = %x\n", (int) Extension->cryptoInfo->RequiredProgramVersion);
457: Dump ("Legacy volume = %d\n", (int) Extension->cryptoInfo->LegacyVolume);
458:
459: if (IsHiddenSystemRunning() && !Extension->cryptoInfo->hiddenVolume)
460: {
461: Extension->bReadOnly = mount->bMountReadOnly = TRUE;
462: HiddenSysLeakProtectionCount++;
463: }
464:
1.1.1.6 root 465: Extension->cryptoInfo->bProtectHiddenVolume = FALSE;
466: Extension->cryptoInfo->bHiddenVolProtectionAction = FALSE;
1.1 root 467:
1.1.1.13 root 468: Extension->cryptoInfo->bPartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
469:
1.1.1.15! root 470: if (volumeType == TC_VOLUME_TYPE_NORMAL)
1.1.1.13 root 471: {
1.1.1.15! root 472: if (mount->bPartitionInInactiveSysEncScope)
1.1.1.13 root 473: {
1.1.1.15! root 474: if (Extension->cryptoInfo->EncryptedAreaStart.Value > (unsigned __int64) partitionStartingOffset
! 475: || Extension->cryptoInfo->EncryptedAreaStart.Value + Extension->cryptoInfo->VolumeSize.Value <= (unsigned __int64) partitionStartingOffset)
! 476: {
! 477: // The partition is not within the key scope of system encryption
! 478: mount->nReturnCode = ERR_PASSWORD_WRONG;
! 479: ntStatus = STATUS_SUCCESS;
! 480: goto error;
! 481: }
! 482:
! 483: if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
! 484: {
! 485: // Partial encryption is not supported for volumes mounted as regular
! 486: mount->nReturnCode = ERR_ENCRYPTION_NOT_COMPLETED;
! 487: ntStatus = STATUS_SUCCESS;
! 488: goto error;
! 489: }
! 490: }
! 491: else if (Extension->cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC)
! 492: {
! 493: if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
! 494: {
! 495: // Non-system in-place encryption process has not been completed on this volume
! 496: mount->nReturnCode = ERR_NONSYS_INPLACE_ENC_INCOMPLETE;
! 497: ntStatus = STATUS_SUCCESS;
! 498: goto error;
! 499: }
1.1.1.13 root 500: }
501: }
502:
1.1.1.14 root 503: Extension->cryptoInfo->FirstDataUnitNo.Value = 0;
1.1 root 504:
1.1.1.14 root 505: if (Extension->cryptoInfo->hiddenVolume && IsHiddenSystemRunning())
506: {
507: // Prevent mount of a hidden system partition if the system hosted on it is currently running
508: if (memcmp (Extension->cryptoInfo->master_keydata, GetSystemDriveCryptoInfo()->master_keydata, EAGetKeySize (Extension->cryptoInfo->ea)) == 0)
1.1.1.13 root 509: {
1.1.1.14 root 510: mount->nReturnCode = ERR_VOL_ALREADY_MOUNTED;
511: ntStatus = STATUS_SUCCESS;
512: goto error;
1.1.1.13 root 513: }
1.1.1.14 root 514: }
515:
516: switch (volumeType)
517: {
518: case TC_VOLUME_TYPE_NORMAL:
1.1.1.13 root 519:
1.1.1.6 root 520: Extension->cryptoInfo->hiddenVolume = FALSE;
1.1.1.13 root 521:
1.1.1.14 root 522: if (mount->bPartitionInInactiveSysEncScope)
523: {
524: Extension->cryptoInfo->volDataAreaOffset = 0;
525: Extension->DiskLength = lDiskLength.QuadPart;
526: Extension->cryptoInfo->FirstDataUnitNo.Value = partitionStartingOffset / ENCRYPTION_DATA_UNIT_SIZE;
527: }
528: else if (Extension->cryptoInfo->LegacyVolume)
529: {
530: Extension->cryptoInfo->volDataAreaOffset = TC_VOLUME_HEADER_SIZE_LEGACY;
531: Extension->DiskLength = lDiskLength.QuadPart - TC_VOLUME_HEADER_SIZE_LEGACY;
532: }
533: else
534: {
535: Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->EncryptedAreaStart.Value;
536: Extension->DiskLength = Extension->cryptoInfo->VolumeSize.Value;
537: }
1.1.1.6 root 538:
539: break;
540:
1.1.1.14 root 541: case TC_VOLUME_TYPE_HIDDEN:
542: case TC_VOLUME_TYPE_HIDDEN_LEGACY:
1.1.1.6 root 543:
544: cryptoInfoPtr = mount->bProtectHiddenVolume ? tmpCryptoInfo : Extension->cryptoInfo;
545:
1.1.1.14 root 546: if (volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
547: Extension->cryptoInfo->hiddenVolumeOffset = lDiskLength.QuadPart - cryptoInfoPtr->hiddenVolumeSize - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY;
548: else
549: Extension->cryptoInfo->hiddenVolumeOffset = cryptoInfoPtr->EncryptedAreaStart.Value;
1.1.1.6 root 550:
1.1.1.14 root 551: Dump ("Hidden volume offset = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset);
552: Dump ("Hidden volume size = %I64d\n", cryptoInfoPtr->hiddenVolumeSize);
553: Dump ("Hidden volume end = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset + cryptoInfoPtr->hiddenVolumeSize - 1);
1.1.1.6 root 554:
555: // Validate the offset
1.1.1.12 root 556: if (Extension->cryptoInfo->hiddenVolumeOffset % ENCRYPTION_DATA_UNIT_SIZE != 0)
1.1.1.6 root 557: {
558: mount->nReturnCode = ERR_VOL_SIZE_WRONG;
559: ntStatus = STATUS_SUCCESS;
560: goto error;
561: }
562:
563: // If we are supposed to actually mount the hidden volume (not just to protect it)
564: if (!mount->bProtectHiddenVolume)
565: {
566: Extension->DiskLength = cryptoInfoPtr->hiddenVolumeSize;
567: Extension->cryptoInfo->hiddenVolume = TRUE;
1.1.1.13 root 568: Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->hiddenVolumeOffset;
1.1.1.6 root 569: }
570: else
571: {
572: // Hidden volume protection
573: Extension->cryptoInfo->hiddenVolume = FALSE;
574: Extension->cryptoInfo->bProtectHiddenVolume = TRUE;
1.1.1.14 root 575:
576: Extension->cryptoInfo->hiddenVolumeProtectedSize = tmpCryptoInfo->hiddenVolumeSize;
1.1.1.13 root 577:
1.1.1.14 root 578: if (volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
579: Extension->cryptoInfo->hiddenVolumeProtectedSize += TC_VOLUME_HEADER_SIZE_LEGACY;
1.1.1.13 root 580:
1.1.1.14 root 581: Dump ("Hidden volume protection active: %I64d-%I64d (%I64d)\n", Extension->cryptoInfo->hiddenVolumeOffset, Extension->cryptoInfo->hiddenVolumeProtectedSize + Extension->cryptoInfo->hiddenVolumeOffset - 1, Extension->cryptoInfo->hiddenVolumeProtectedSize);
1.1.1.6 root 582: }
1.1.1.4 root 583:
1.1.1.6 root 584: break;
585: }
1.1.1.4 root 586:
1.1.1.14 root 587: Dump ("Volume data offset = %I64d\n", Extension->cryptoInfo->volDataAreaOffset);
588: Dump ("Volume data size = %I64d\n", Extension->DiskLength);
589: Dump ("Volume data end = %I64d\n", Extension->cryptoInfo->volDataAreaOffset + Extension->DiskLength - 1);
590:
1.1.1.15! root 591: if (Extension->DiskLength == 0)
! 592: {
! 593: Dump ("Incorrect volume size\n");
! 594: continue;
! 595: }
! 596:
1.1.1.6 root 597: // If this is a hidden volume, make sure we are supposed to actually
598: // mount it (i.e. not just to protect it)
1.1.1.14 root 599: if (volumeType == TC_VOLUME_TYPE_NORMAL || !mount->bProtectHiddenVolume)
1.1.1.4 root 600: {
1.1.1.6 root 601: // Calculate virtual volume geometry
602: Extension->TracksPerCylinder = 1;
603: Extension->SectorsPerTrack = 1;
1.1.1.10 root 604: Extension->BytesPerSector = SECTOR_SIZE;
605: Extension->NumberOfCylinders = Extension->DiskLength / SECTOR_SIZE;
1.1.1.6 root 606: Extension->PartitionType = 0;
607:
608: Extension->bRawDevice = bRawDevice;
1.1.1.7 root 609:
1.1.1.8 root 610: memset (Extension->wszVolume, 0, sizeof (Extension->wszVolume));
1.1.1.7 root 611: if (wcsstr (pwszMountVolume, WIDE ("\\??\\UNC\\")) == pwszMountVolume)
612: {
613: /* UNC path */
614: _snwprintf (Extension->wszVolume,
615: sizeof (Extension->wszVolume) / sizeof (WCHAR) - 1,
616: WIDE ("\\??\\\\%s"),
617: pwszMountVolume + 7);
618: }
1.1.1.6 root 619: else
620: {
1.1.1.7 root 621: wcsncpy (Extension->wszVolume, pwszMountVolume, sizeof (Extension->wszVolume) / sizeof (WCHAR) - 1);
1.1.1.6 root 622: }
1.1.1.4 root 623: }
624:
1.1.1.6 root 625: // If we are to protect a hidden volume we cannot exit yet, for we must also
626: // decrypt the hidden volume header.
1.1.1.14 root 627: if (!(volumeType == TC_VOLUME_TYPE_NORMAL && mount->bProtectHiddenVolume))
1.1.1.4 root 628: {
1.1.1.6 root 629: TCfree (readBuffer);
1.1.1.4 root 630:
1.1.1.6 root 631: if (tmpCryptoInfo != NULL)
1.1.1.14 root 632: {
1.1.1.6 root 633: crypto_close (tmpCryptoInfo);
1.1.1.14 root 634: tmpCryptoInfo = NULL;
635: }
1.1.1.6 root 636:
637: return STATUS_SUCCESS;
638: }
1.1.1.4 root 639: }
1.1.1.14 root 640: else if ((mount->bProtectHiddenVolume && volumeType == TC_VOLUME_TYPE_NORMAL)
1.1.1.6 root 641: || mount->nReturnCode != ERR_PASSWORD_WRONG)
1.1.1.4 root 642: {
1.1.1.6 root 643: /* If we are not supposed to protect a hidden volume, the only error that is
644: tolerated is ERR_PASSWORD_WRONG (to allow mounting a possible hidden volume).
1.1.1.4 root 645:
1.1.1.6 root 646: If we _are_ supposed to protect a hidden volume, we do not tolerate any error
647: (both volume headers must be successfully decrypted). */
1.1 root 648:
1.1.1.6 root 649: break;
1.1 root 650: }
651: }
652:
653: /* Failed due to some non-OS reason so we drop through and return NT
654: SUCCESS then nReturnCode is checked later in user-mode */
655:
656: if (mount->nReturnCode == ERR_OUTOFMEMORY)
657: ntStatus = STATUS_INSUFFICIENT_RESOURCES;
658: else
659: ntStatus = STATUS_SUCCESS;
660:
1.1.1.4 root 661: error:
1.1.1.14 root 662: if (mount->nReturnCode == ERR_SUCCESS)
663: mount->nReturnCode = ERR_PASSWORD_WRONG;
664:
665: if (tmpCryptoInfo != NULL)
666: {
667: crypto_close (tmpCryptoInfo);
668: tmpCryptoInfo = NULL;
669: }
670:
671: if (Extension->cryptoInfo)
672: {
673: crypto_close (Extension->cryptoInfo);
674: Extension->cryptoInfo = NULL;
675: }
676:
1.1.1.6 root 677: if (Extension->bTimeStampValid)
1.1.1.4 root 678: {
679: /* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
680: RestoreTimeStamp (Extension);
681: }
1.1 root 682:
683: /* Close the hDeviceFile */
684: if (Extension->hDeviceFile != NULL)
685: ZwClose (Extension->hDeviceFile);
686:
687: /* The cryptoInfo pointer is deallocated if the readheader routines
688: fail so there is no need to deallocate here */
689:
690: /* Dereference the user-mode file object */
691: if (Extension->pfoDeviceFile != NULL)
692: ObDereferenceObject (Extension->pfoDeviceFile);
693:
1.1.1.4 root 694: /* Free the tmp IO buffers */
1.1 root 695: if (readBuffer != NULL)
696: TCfree (readBuffer);
697:
698: return ntStatus;
699: }
700:
1.1.1.14 root 701: void TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
1.1 root 702: {
703: if (DeviceObject); /* Remove compiler warning */
704:
705: if (Extension->hDeviceFile != NULL)
1.1.1.4 root 706: {
1.1.1.6 root 707: if (Extension->bRawDevice == FALSE
708: && Extension->bTimeStampValid)
1.1.1.4 root 709: {
710: /* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
711: RestoreTimeStamp (Extension);
712: }
1.1.1.6 root 713: ZwClose (Extension->hDeviceFile);
1.1.1.4 root 714: }
1.1 root 715: ObDereferenceObject (Extension->pfoDeviceFile);
716: crypto_close (Extension->cryptoInfo);
717: }
718:
719:
1.1.1.14 root 720: NTSTATUS TCSendHostDeviceIoControlRequest (PDEVICE_OBJECT DeviceObject,
1.1 root 721: PEXTENSION Extension,
722: ULONG IoControlCode,
1.1.1.15! root 723: void *OutputBuffer,
! 724: ULONG OutputBufferSize)
1.1 root 725: {
726: IO_STATUS_BLOCK IoStatusBlock;
727: NTSTATUS ntStatus;
728: PIRP Irp;
729:
730: if (DeviceObject); /* Remove compiler warning */
731:
732: KeClearEvent (&Extension->keVolumeEvent);
733:
734: Irp = IoBuildDeviceIoControlRequest (IoControlCode,
735: Extension->pFsdDevice,
736: NULL, 0,
737: OutputBuffer, OutputBufferSize,
738: FALSE,
739: &Extension->keVolumeEvent,
740: &IoStatusBlock);
741:
742: if (Irp == NULL)
743: {
744: Dump ("IRP allocation failed\n");
745: return STATUS_INSUFFICIENT_RESOURCES;
746: }
747:
1.1.1.5 root 748: // Disk device may be used by filesystem driver which needs file object
749: IoGetNextIrpStackLocation (Irp) -> FileObject = Extension->pfoDeviceFile;
750:
1.1 root 751: ntStatus = IoCallDriver (Extension->pFsdDevice, Irp);
752: if (ntStatus == STATUS_PENDING)
753: {
1.1.1.12 root 754: KeWaitForSingleObject (&Extension->keVolumeEvent, Executive, KernelMode, FALSE, NULL);
1.1 root 755: ntStatus = IoStatusBlock.Status;
756: }
757:
758: return ntStatus;
759: }
760:
1.1.1.14 root 761: NTSTATUS COMPLETE_IRP (PDEVICE_OBJECT DeviceObject,
1.1 root 762: PIRP Irp,
763: NTSTATUS IrpStatus,
1.1.1.4 root 764: ULONG_PTR IrpInformation)
1.1 root 765: {
766: Irp->IoStatus.Status = IrpStatus;
767: Irp->IoStatus.Information = IrpInformation;
768:
769: if (DeviceObject); /* Remove compiler warning */
770:
1.1.1.10 root 771: #if EXTRA_INFO
772: if (!NT_SUCCESS (IrpStatus))
773: {
774: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
775: Dump ("COMPLETE_IRP FAILING IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
776: (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
777: }
778: else
779: {
780: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
781: Dump ("COMPLETE_IRP SUCCESS IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
782: (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
783: }
1.1 root 784: #endif
785: IoCompleteRequest (Irp, IO_NO_INCREMENT);
786: return IrpStatus;
787: }
1.1.1.4 root 788:
789: // Restores the container timestamp to preserve plausible deniability of possible hidden volume.
790: static void RestoreTimeStamp (PEXTENSION Extension)
791: {
792: NTSTATUS ntStatus;
793: FILE_BASIC_INFORMATION FileBasicInfo;
794: IO_STATUS_BLOCK IoStatusBlock;
795:
1.1.1.6 root 796: if (Extension->hDeviceFile != NULL
797: && Extension->bRawDevice == FALSE
798: && Extension->bReadOnly == FALSE
799: && Extension->bTimeStampValid)
1.1.1.4 root 800: {
801: ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
802: &IoStatusBlock,
803: &FileBasicInfo,
804: sizeof (FileBasicInfo),
805: FileBasicInformation);
806:
807: if (!NT_SUCCESS (ntStatus))
808: {
809: Dump ("ZwQueryInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",
810: ntStatus);
811: }
812: else
813: {
814: FileBasicInfo.CreationTime = Extension->fileCreationTime;
815: FileBasicInfo.LastAccessTime = Extension->fileLastAccessTime;
816: FileBasicInfo.LastWriteTime = Extension->fileLastWriteTime;
817: FileBasicInfo.ChangeTime = Extension->fileLastChangeTime;
818:
819: ntStatus = ZwSetInformationFile(
820: Extension->hDeviceFile,
821: &IoStatusBlock,
822: &FileBasicInfo,
823: sizeof (FileBasicInfo),
824: FileBasicInformation);
825:
826: if (!NT_SUCCESS (ntStatus))
827: Dump ("ZwSetInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",ntStatus);
828: }
829: }
830: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.