From c94f8c9b63edc756aa05ec85ed8da84ab799205c Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Mon, 5 Oct 2015 03:22:11 +0200 Subject: Windows Driver: Modify fix for CVE-2015-7358 to solve side effects on Windows mount manager while still making it hard to abuse drive letter handling. --- src/Common/Apidrvr.h | 3 ++- src/Driver/Ntdriver.c | 47 ++++++++++++++++++++++++++++++++++------------- src/Driver/Ntdriver.h | 9 +++++++-- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/Common/Apidrvr.h b/src/Common/Apidrvr.h index 4fc15767..79cf2377 100644 --- a/src/Common/Apidrvr.h +++ b/src/Common/Apidrvr.h @@ -322,7 +322,8 @@ typedef struct #define NT_MOUNT_PREFIX DRIVER_STR("\\Device\\VeraCryptVolume") #define NT_ROOT_PREFIX DRIVER_STR("\\Device\\VeraCrypt") -#define DOS_MOUNT_PREFIX DRIVER_STR("\\GLOBAL??\\") // Explicitely use Global MS-DOS device names to avoid security issues +#define DOS_MOUNT_PREFIX_DEFAULT DRIVER_STR("\\DosDevices\\") +#define DOS_MOUNT_PREFIX_GLOBAL DRIVER_STR("\\GLOBAL??\\") // Use Global MS-DOS device names for sanity checks on drive letters #define DOS_ROOT_PREFIX DRIVER_STR("\\DosDevices\\VeraCrypt") #define WIN32_ROOT_PREFIX DRIVER_STR("\\\\.\\VeraCrypt") diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c index a494c68b..2a82c5ac 100644 --- a/src/Driver/Ntdriver.c +++ b/src/Driver/Ntdriver.c @@ -586,7 +586,7 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION break; } - TCGetDosNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo); + TCGetDosNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo, DeviceNamespaceDefault); RtlInitUnicodeString (&ntUnicodeString, ntName); outLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME,Name) + ntUnicodeString.Length; @@ -1965,14 +1965,23 @@ void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo) RtlStringCbCatW (ntname, cbNtName, tmp); } -void TCGetDosNameFromNumber (LPWSTR dosname,int cbDosName, int nDriveNo) +void TCGetDosNameFromNumber (LPWSTR dosname,int cbDosName, int nDriveNo, DeviceNamespaceType namespaceType) { WCHAR tmp[3] = {0, ':', 0}; int j = nDriveNo + (WCHAR) 'A'; tmp[0] = (short) j; - RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX); + + if (DeviceNamespaceGlobal == namespaceType) + { + RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_GLOBAL); + } + else + { + RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_DEFAULT); + } + RtlStringCbCatW (dosname, cbDosName, tmp); } @@ -2538,7 +2547,7 @@ NTSTATUS CreateDriveLink (int nDosDriveNo) NTSTATUS ntStatus; TCGetNTNameFromNumber (dev, sizeof(dev),nDosDriveNo); - TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo); + TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault); RtlInitUnicodeString (&deviceName, dev); RtlInitUnicodeString (&symLink, link); @@ -2555,7 +2564,7 @@ NTSTATUS RemoveDriveLink (int nDosDriveNo) UNICODE_STRING symLink; NTSTATUS ntStatus; - TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo); + TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault); RtlInitUnicodeString (&symLink, link); ntStatus = IoDeleteSymbolicLink (&symLink); @@ -2580,7 +2589,7 @@ NTSTATUS MountManagerMount (MOUNT_STRUCT *mount) in, (ULONG) (sizeof (in->DeviceNameLength) + wcslen (arrVolume) * 2), 0, 0); memset (buf, 0, sizeof buf); - TCGetDosNameFromNumber ((PWSTR) &point[1], sizeof(buf) - sizeof(MOUNTMGR_CREATE_POINT_INPUT),mount->nDosDriveNo); + TCGetDosNameFromNumber ((PWSTR) &point[1], sizeof(buf) - sizeof(MOUNTMGR_CREATE_POINT_INPUT),mount->nDosDriveNo, DeviceNamespaceDefault); point->SymbolicLinkNameOffset = sizeof (MOUNTMGR_CREATE_POINT_INPUT); point->SymbolicLinkNameLength = (USHORT) wcslen ((PWSTR) &point[1]) * 2; @@ -2590,7 +2599,7 @@ NTSTATUS MountManagerMount (MOUNT_STRUCT *mount) point->DeviceNameLength = (USHORT) wcslen ((PWSTR) (buf + point->DeviceNameOffset)) * 2; ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_CREATE_POINT, point, - point->DeviceNameOffset + point->DeviceNameLength, 0, 0); + point->DeviceNameOffset + point->DeviceNameLength, 0, 0); return ntStatus; } @@ -2604,7 +2613,7 @@ NTSTATUS MountManagerUnmount (int nDosDriveNo) memset (buf, 0, sizeof buf); - TCGetDosNameFromNumber ((PWSTR) &in[1], sizeof(buf) - sizeof(MOUNTMGR_MOUNT_POINT),nDosDriveNo); + TCGetDosNameFromNumber ((PWSTR) &in[1], sizeof(buf) - sizeof(MOUNTMGR_MOUNT_POINT),nDosDriveNo, DeviceNamespaceDefault); // Only symbolic link can be deleted with IOCTL_MOUNTMGR_DELETE_POINTS. If any other entry is specified, the mount manager will ignore subsequent IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION for the same volume ID. in->SymbolicLinkNameOffset = sizeof (MOUNTMGR_MOUNT_POINT); @@ -2622,10 +2631,13 @@ NTSTATUS MountManagerUnmount (int nDosDriveNo) NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount) { PDEVICE_OBJECT NewDeviceObject; - NTSTATUS ntStatus; + NTSTATUS ntStatus; // Make sure the user is asking for a reasonable nDosDriveNo - if (mount->nDosDriveNo >= 0 && mount->nDosDriveNo <= 25 && IsDriveLetterAvailable (mount->nDosDriveNo)) + if (mount->nDosDriveNo >= 0 && mount->nDosDriveNo <= 25 + && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault) // drive letter must not exist both locally and globally + && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal) + ) { Dump ("Mount request looks valid\n"); } @@ -2716,6 +2728,16 @@ NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount) NewExtension->UniqueVolumeId = LastUniqueVolumeId++; + // check again that the drive letter is available globally and locally + if ( !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault) + || !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal) + ) + { + TCDeleteDeviceObject (NewDeviceObject, NewExtension); + mount->nReturnCode = ERR_DRIVE_NOT_FOUND; + return ERR_DRIVE_NOT_FOUND; + } + if (mount->bMountManager) MountManagerMount (mount); @@ -3049,8 +3071,7 @@ BOOL UserCanAccessDriveDevice () return IsAccessibleByUser (&name, FALSE); } - -BOOL IsDriveLetterAvailable (int nDosDriveNo) +BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType) { OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING objectName; @@ -3058,7 +3079,7 @@ BOOL IsDriveLetterAvailable (int nDosDriveNo) HANDLE handle; NTSTATUS ntStatus; - TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo); + TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, namespaceType); RtlInitUnicodeString (&objectName, link); InitializeObjectAttributes (&objectAttributes, &objectName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); diff --git a/src/Driver/Ntdriver.h b/src/Driver/Ntdriver.h index 8da75c69..07ae5f83 100644 --- a/src/Driver/Ntdriver.h +++ b/src/Driver/Ntdriver.h @@ -101,6 +101,11 @@ typedef enum ValidateInputOutput } ValidateIOBufferSizeType; +typedef enum +{ + DeviceNamespaceDefault, + DeviceNamespaceGlobal, +} DeviceNamespaceType; extern PDRIVER_OBJECT TCDriverObject; extern PDEVICE_OBJECT RootDeviceObject; @@ -133,7 +138,7 @@ void TCStopVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension); VOID VolumeThreadProc (PVOID Context); void TCSleep (int milliSeconds); void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo); -void TCGetDosNameFromNumber (LPWSTR dosname, int cbDosName, int nDriveNo); +void TCGetDosNameFromNumber (LPWSTR dosname, int cbDosName, int nDriveNo, DeviceNamespaceType namespaceType); LPWSTR TCTranslateCode (ULONG ulCode); void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension); VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject); @@ -161,7 +166,7 @@ BOOL UserCanAccessDriveDevice (); size_t GetCpuCount (); void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes); void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout); -BOOL IsDriveLetterAvailable (int nDosDriveNo); +BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType); NTSTATUS TCReadRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, PKEY_VALUE_PARTIAL_INFORMATION *keyData); NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize); BOOL IsVolumeClassFilterRegistered (); -- cgit v1.2.3