Windows Driver: Potential memory corruption caused by integer overflow in IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES (reported by I.V. Sprundel)

This commit is contained in:
Mounir IDRASSI 2021-08-24 09:27:48 +02:00
parent f462160542
commit 09206053d5
No known key found for this signature in database
GPG Key ID: 02C30AE90FAE4A6F

View File

@ -154,6 +154,29 @@ ULONG ExDefaultMdlProtection = 0;
PDEVICE_OBJECT VirtualVolumeDeviceObjects[MAX_MOUNTED_VOLUME_DRIVE_NUMBER + 1]; PDEVICE_OBJECT VirtualVolumeDeviceObjects[MAX_MOUNTED_VOLUME_DRIVE_NUMBER + 1];
BOOL AlignValue (ULONG ulValue, ULONG ulAlignment, ULONG *pulResult)
{
BOOL bRet = FALSE;
HRESULT hr;
if (ulAlignment == 0)
{
*pulResult = ulValue;
bRet = TRUE;
}
else
{
ulAlignment -= 1;
hr = ULongAdd (ulValue, ulAlignment, &ulValue);
if (S_OK == hr)
{
*pulResult = ulValue & (~ulAlignment);
bRet = TRUE;
}
}
return bRet;
}
BOOL IsUefiBoot () BOOL IsUefiBoot ()
{ {
BOOL bStatus = FALSE; BOOL bStatus = FALSE;
@ -1690,7 +1713,7 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION
ULONG ulNewInputLength = 0; ULONG ulNewInputLength = 0;
BOOL bForwardIoctl = FALSE; BOOL bForwardIoctl = FALSE;
if (inputLength >= minSizeGeneric && inputLength >= minSizedataSet && inputLength >= minSizeParameter) if (((ULONGLONG) inputLength) >= minSizeGeneric && ((ULONGLONG) inputLength) >= minSizedataSet && ((ULONGLONG) inputLength) >= minSizeParameter)
{ {
if (bEntireSet) if (bEntireSet)
{ {
@ -1702,36 +1725,53 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION
} }
else else
{ {
DWORD dwDataSetOffset = ALIGN_VALUE (inputLength, sizeof(DEVICE_DATA_SET_RANGE)); DWORD dwDataSetOffset;
DWORD dwDataSetLength = sizeof(DEVICE_DATA_SET_RANGE); DWORD dwDataSetLength = sizeof(DEVICE_DATA_SET_RANGE);
Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE set. Setting data range to all volume.\n"); if (AlignValue (inputLength, sizeof(DEVICE_DATA_SET_RANGE), &dwDataSetOffset))
ulNewInputLength = dwDataSetOffset + dwDataSetLength;
pNewSetAttrs = (PDEVICE_MANAGE_DATA_SET_ATTRIBUTES) TCalloc (ulNewInputLength);
if (pNewSetAttrs)
{ {
PDEVICE_DATA_SET_RANGE pRange = (PDEVICE_DATA_SET_RANGE) (((unsigned char*) pNewSetAttrs) + dwDataSetOffset); Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE set. Setting data range to all volume.\n");
memcpy (pNewSetAttrs, pInputAttrs, inputLength); if (S_OK == ULongAdd(dwDataSetOffset, dwDataSetLength, &ulNewInputLength))
{
pNewSetAttrs = (PDEVICE_MANAGE_DATA_SET_ATTRIBUTES) TCalloc (ulNewInputLength);
if (pNewSetAttrs)
{
PDEVICE_DATA_SET_RANGE pRange = (PDEVICE_DATA_SET_RANGE) (((unsigned char*) pNewSetAttrs) + dwDataSetOffset);
pRange->StartingOffset = (ULONGLONG) Extension->cryptoInfo->hiddenVolume ? Extension->cryptoInfo->hiddenVolumeOffset : Extension->cryptoInfo->volDataAreaOffset; memcpy (pNewSetAttrs, pInputAttrs, inputLength);
pRange->LengthInBytes = Extension->DiskLength;
pNewSetAttrs->Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES); pRange->StartingOffset = (ULONGLONG) Extension->cryptoInfo->hiddenVolume ? Extension->cryptoInfo->hiddenVolumeOffset : Extension->cryptoInfo->volDataAreaOffset;
pNewSetAttrs->Action = action; pRange->LengthInBytes = Extension->DiskLength;
pNewSetAttrs->Flags = pInputAttrs->Flags & (~DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE);
pNewSetAttrs->ParameterBlockOffset = pInputAttrs->ParameterBlockOffset;
pNewSetAttrs->ParameterBlockLength = pInputAttrs->ParameterBlockLength;
pNewSetAttrs->DataSetRangesOffset = dwDataSetOffset;
pNewSetAttrs->DataSetRangesLength = dwDataSetLength;
bForwardIoctl = TRUE; pNewSetAttrs->Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES);
pNewSetAttrs->Action = action;
pNewSetAttrs->Flags = pInputAttrs->Flags & (~DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE);
pNewSetAttrs->ParameterBlockOffset = pInputAttrs->ParameterBlockOffset;
pNewSetAttrs->ParameterBlockLength = pInputAttrs->ParameterBlockLength;
pNewSetAttrs->DataSetRangesOffset = dwDataSetOffset;
pNewSetAttrs->DataSetRangesLength = dwDataSetLength;
bForwardIoctl = TRUE;
}
else
{
Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - Failed to allocate memory.\n");
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
}
}
else
{
Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE set but data range length computation overflowed.\n");
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
}
} }
else else
{ {
Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - Failed to allocate memory.\n"); Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE set but data set offset computation overflowed.\n");
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
} }
} }