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.

This commit is contained in:
Mounir IDRASSI 2015-10-05 03:22:11 +02:00
parent ea451c7241
commit c94f8c9b63
3 changed files with 43 additions and 16 deletions

View File

@ -322,7 +322,8 @@ typedef struct
#define NT_MOUNT_PREFIX DRIVER_STR("\\Device\\VeraCryptVolume") #define NT_MOUNT_PREFIX DRIVER_STR("\\Device\\VeraCryptVolume")
#define NT_ROOT_PREFIX DRIVER_STR("\\Device\\VeraCrypt") #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 DOS_ROOT_PREFIX DRIVER_STR("\\DosDevices\\VeraCrypt")
#define WIN32_ROOT_PREFIX DRIVER_STR("\\\\.\\VeraCrypt") #define WIN32_ROOT_PREFIX DRIVER_STR("\\\\.\\VeraCrypt")

View File

@ -586,7 +586,7 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION
break; break;
} }
TCGetDosNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo); TCGetDosNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo, DeviceNamespaceDefault);
RtlInitUnicodeString (&ntUnicodeString, ntName); RtlInitUnicodeString (&ntUnicodeString, ntName);
outLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME,Name) + ntUnicodeString.Length; 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); 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] = WCHAR tmp[3] =
{0, ':', 0}; {0, ':', 0};
int j = nDriveNo + (WCHAR) 'A'; int j = nDriveNo + (WCHAR) 'A';
tmp[0] = (short) j; 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); RtlStringCbCatW (dosname, cbDosName, tmp);
} }
@ -2538,7 +2547,7 @@ NTSTATUS CreateDriveLink (int nDosDriveNo)
NTSTATUS ntStatus; NTSTATUS ntStatus;
TCGetNTNameFromNumber (dev, sizeof(dev),nDosDriveNo); TCGetNTNameFromNumber (dev, sizeof(dev),nDosDriveNo);
TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo); TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault);
RtlInitUnicodeString (&deviceName, dev); RtlInitUnicodeString (&deviceName, dev);
RtlInitUnicodeString (&symLink, link); RtlInitUnicodeString (&symLink, link);
@ -2555,7 +2564,7 @@ NTSTATUS RemoveDriveLink (int nDosDriveNo)
UNICODE_STRING symLink; UNICODE_STRING symLink;
NTSTATUS ntStatus; NTSTATUS ntStatus;
TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo); TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault);
RtlInitUnicodeString (&symLink, link); RtlInitUnicodeString (&symLink, link);
ntStatus = IoDeleteSymbolicLink (&symLink); ntStatus = IoDeleteSymbolicLink (&symLink);
@ -2580,7 +2589,7 @@ NTSTATUS MountManagerMount (MOUNT_STRUCT *mount)
in, (ULONG) (sizeof (in->DeviceNameLength) + wcslen (arrVolume) * 2), 0, 0); in, (ULONG) (sizeof (in->DeviceNameLength) + wcslen (arrVolume) * 2), 0, 0);
memset (buf, 0, sizeof buf); 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->SymbolicLinkNameOffset = sizeof (MOUNTMGR_CREATE_POINT_INPUT);
point->SymbolicLinkNameLength = (USHORT) wcslen ((PWSTR) &point[1]) * 2; point->SymbolicLinkNameLength = (USHORT) wcslen ((PWSTR) &point[1]) * 2;
@ -2604,7 +2613,7 @@ NTSTATUS MountManagerUnmount (int nDosDriveNo)
memset (buf, 0, sizeof buf); 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. // 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); in->SymbolicLinkNameOffset = sizeof (MOUNTMGR_MOUNT_POINT);
@ -2625,7 +2634,10 @@ NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount)
NTSTATUS ntStatus; NTSTATUS ntStatus;
// Make sure the user is asking for a reasonable nDosDriveNo // 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"); Dump ("Mount request looks valid\n");
} }
@ -2716,6 +2728,16 @@ NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount)
NewExtension->UniqueVolumeId = LastUniqueVolumeId++; 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) if (mount->bMountManager)
MountManagerMount (mount); MountManagerMount (mount);
@ -3049,8 +3071,7 @@ BOOL UserCanAccessDriveDevice ()
return IsAccessibleByUser (&name, FALSE); return IsAccessibleByUser (&name, FALSE);
} }
BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType)
BOOL IsDriveLetterAvailable (int nDosDriveNo)
{ {
OBJECT_ATTRIBUTES objectAttributes; OBJECT_ATTRIBUTES objectAttributes;
UNICODE_STRING objectName; UNICODE_STRING objectName;
@ -3058,7 +3079,7 @@ BOOL IsDriveLetterAvailable (int nDosDriveNo)
HANDLE handle; HANDLE handle;
NTSTATUS ntStatus; NTSTATUS ntStatus;
TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo); TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, namespaceType);
RtlInitUnicodeString (&objectName, link); RtlInitUnicodeString (&objectName, link);
InitializeObjectAttributes (&objectAttributes, &objectName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); InitializeObjectAttributes (&objectAttributes, &objectName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);

View File

@ -101,6 +101,11 @@ typedef enum
ValidateInputOutput ValidateInputOutput
} ValidateIOBufferSizeType; } ValidateIOBufferSizeType;
typedef enum
{
DeviceNamespaceDefault,
DeviceNamespaceGlobal,
} DeviceNamespaceType;
extern PDRIVER_OBJECT TCDriverObject; extern PDRIVER_OBJECT TCDriverObject;
extern PDEVICE_OBJECT RootDeviceObject; extern PDEVICE_OBJECT RootDeviceObject;
@ -133,7 +138,7 @@ void TCStopVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension);
VOID VolumeThreadProc (PVOID Context); VOID VolumeThreadProc (PVOID Context);
void TCSleep (int milliSeconds); void TCSleep (int milliSeconds);
void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo); 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); LPWSTR TCTranslateCode (ULONG ulCode);
void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension); void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension);
VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject); VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject);
@ -161,7 +166,7 @@ BOOL UserCanAccessDriveDevice ();
size_t GetCpuCount (); size_t GetCpuCount ();
void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes); void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes);
void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout); 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 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); NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize);
BOOL IsVolumeClassFilterRegistered (); BOOL IsVolumeClassFilterRegistered ();