mirror of
https://github.com/winfsp/winfsp.git
synced 2026-03-06 23:59:26 -06:00
sys: FspFastIoDeviceControl: fix exploit reported by Tay Kiat Loong
The WinFsp "transact" protocol is used by user mode file systems to interface with the FSD. This protocol works via the DeviceIoControl API and uses the FSP_IOCTL_TRANSACT control code. The FSP_IOCTL_TRANSACT code is marked as METHOD_BUFFERED. When the DeviceIoControl call is forwarded as an IRP, the METHOD_BUFFERED flag instructs the kernel to copy user mode buffers to kernel mode buffers (and vice-versa). However when the DeviceIoControl call is forwarded via the FastIO mechanism the METHOD_BUFFERED flag is ignored. This means that when WinFsp added support for DeviceIoControl FastIO, the FSD started accessing user mode buffers directly. This means that a malicious file system could attempt exploits like changing or freeing a buffer while the FSD is reading it. Tay Kiat Loong developed a POC exploit which demonstrated this vulnerability. This commit fixes the problem by patching FspFastIoDeviceControl to add the missing METHOD_BUFFERED handling.
This commit is contained in:
@@ -72,15 +72,24 @@ BOOLEAN FspFastIoDeviceControl(
|
|||||||
if (!Result)
|
if (!Result)
|
||||||
FSP_RETURN();
|
FSP_RETURN();
|
||||||
|
|
||||||
#if 0
|
PVOID SystemBuffer = 0;
|
||||||
PDEVICE_OBJECT FsctlDeviceObject = DeviceObject;
|
if (0 != InputBufferLength || 0 != OutputBufferLength)
|
||||||
if (!FspDeviceReference(FsctlDeviceObject))
|
|
||||||
{
|
{
|
||||||
IoStatus->Status = STATUS_CANCELLED;
|
SystemBuffer = FspAllocNonPaged(
|
||||||
IoStatus->Information = 0;
|
InputBufferLength > OutputBufferLength ? InputBufferLength : OutputBufferLength);
|
||||||
FSP_RETURN();
|
if (0 == SystemBuffer)
|
||||||
|
FSP_RETURN(Result = FALSE);
|
||||||
|
if (0 != InputBuffer)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RtlCopyMemory(SystemBuffer, InputBuffer, InputBufferLength);
|
||||||
|
}
|
||||||
|
except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
FspFree(SystemBuffer);
|
||||||
|
FSP_RETURN(Result = FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
ASSERT(0 == IoGetTopLevelIrp());
|
ASSERT(0 == IoGetTopLevelIrp());
|
||||||
IoSetTopLevelIrp((PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP);
|
IoSetTopLevelIrp((PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP);
|
||||||
@@ -88,18 +97,28 @@ BOOLEAN FspFastIoDeviceControl(
|
|||||||
IoStatus->Status = FspVolumeFastTransact(
|
IoStatus->Status = FspVolumeFastTransact(
|
||||||
FileObject->FsContext2,
|
FileObject->FsContext2,
|
||||||
IoControlCode,
|
IoControlCode,
|
||||||
InputBuffer,
|
SystemBuffer,
|
||||||
InputBufferLength,
|
InputBufferLength,
|
||||||
OutputBuffer,
|
0 != OutputBufferLength ? SystemBuffer : 0,
|
||||||
OutputBufferLength,
|
OutputBufferLength,
|
||||||
IoStatus,
|
IoStatus,
|
||||||
(PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP);
|
(PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP);
|
||||||
|
|
||||||
IoSetTopLevelIrp(0);
|
IoSetTopLevelIrp(0);
|
||||||
|
|
||||||
#if 0
|
if (0 != SystemBuffer)
|
||||||
FspDeviceDereference(FsctlDeviceObject);
|
{
|
||||||
#endif
|
if (0 != OutputBuffer)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RtlCopyMemory(OutputBuffer, SystemBuffer, OutputBufferLength);
|
||||||
|
}
|
||||||
|
except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
IoStatus->Status = GetExceptionCode();
|
||||||
|
}
|
||||||
|
FspFree(SystemBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
FSP_LEAVE_BOOL(
|
FSP_LEAVE_BOOL(
|
||||||
"%s, FileObject=%p",
|
"%s, FileObject=%p",
|
||||||
|
|||||||
Reference in New Issue
Block a user