mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 08:53:01 -05:00
sys: FspFsvrtDeleteVolume: delay delete the volume to avoid crashes in fltmgr.sys; using FspDeviceRetain() instead of ObReferenceObject() appears to completely resolve the fltmgr.sys crash
This commit is contained in:
parent
aee12e1c5f
commit
a3312ad2f1
@ -66,6 +66,10 @@ static NTSTATUS FspFsvolCreate(
|
|||||||
(0 == IrpSp->FileObject->RelatedFileObject ||
|
(0 == IrpSp->FileObject->RelatedFileObject ||
|
||||||
0 == IrpSp->FileObject->RelatedFileObject->FsContext))
|
0 == IrpSp->FileObject->RelatedFileObject->FsContext))
|
||||||
{
|
{
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
|
||||||
|
PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
|
||||||
|
|
||||||
|
IrpSp->FileObject->Vpb = FsvrtDeviceObject->Vpb;
|
||||||
Irp->IoStatus.Information = FILE_OPENED;
|
Irp->IoStatus.Information = FILE_OPENED;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -479,6 +479,17 @@ BOOLEAN FspValidRelativeSecurityDescriptor(
|
|||||||
NTSTATUS FspSecuritySubjectContextAccessCheck(
|
NTSTATUS FspSecuritySubjectContextAccessCheck(
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor, ACCESS_MASK DesiredAccess, KPROCESSOR_MODE AccessMode);
|
PSECURITY_DESCRIPTOR SecurityDescriptor, ACCESS_MASK DesiredAccess, KPROCESSOR_MODE AccessMode);
|
||||||
|
|
||||||
|
/* delayed work queue */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
KTIMER Timer;
|
||||||
|
KDPC Dpc;
|
||||||
|
WORK_QUEUE_ITEM WorkQueueItem;
|
||||||
|
} FSP_WORK_ITEM_WITH_DELAY;
|
||||||
|
VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem,
|
||||||
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||||
|
VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout);
|
||||||
|
|
||||||
/* debug */
|
/* debug */
|
||||||
#if DBG
|
#if DBG
|
||||||
BOOLEAN HasDbgBreakPoint(const char *Function);
|
BOOLEAN HasDbgBreakPoint(const char *Function);
|
||||||
|
@ -74,6 +74,7 @@ static NTSTATUS FspFsctlMountVolume(
|
|||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
static NTSTATUS FspFsvrtDeleteVolume(
|
static NTSTATUS FspFsvrtDeleteVolume(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
|
static WORKER_THREAD_ROUTINE FspFsvrtDeleteVolumeDelayed;
|
||||||
static NTSTATUS FspFsvrtTransact(
|
static NTSTATUS FspFsvrtTransact(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||||
static NTSTATUS FspFsctlFileSystemControl(
|
static NTSTATUS FspFsctlFileSystemControl(
|
||||||
@ -89,6 +90,7 @@ FSP_IOCMPL_DISPATCH FspFileSystemControlComplete;
|
|||||||
#pragma alloc_text(PAGE, FspFsctlCreateVolume)
|
#pragma alloc_text(PAGE, FspFsctlCreateVolume)
|
||||||
#pragma alloc_text(PAGE, FspFsctlMountVolume)
|
#pragma alloc_text(PAGE, FspFsctlMountVolume)
|
||||||
#pragma alloc_text(PAGE, FspFsvrtDeleteVolume)
|
#pragma alloc_text(PAGE, FspFsvrtDeleteVolume)
|
||||||
|
#pragma alloc_text(PAGE, FspFsvrtDeleteVolumeDelayed)
|
||||||
#pragma alloc_text(PAGE, FspFsvrtTransact)
|
#pragma alloc_text(PAGE, FspFsvrtTransact)
|
||||||
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
||||||
#pragma alloc_text(PAGE, FspFsvrtFileSystemControl)
|
#pragma alloc_text(PAGE, FspFsvrtFileSystemControl)
|
||||||
@ -259,6 +261,13 @@ static NTSTATUS FspFsctlMountVolume(
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject;
|
||||||
|
PVPB OldVpb;
|
||||||
|
FSP_WORK_ITEM_WITH_DELAY WorkItemWithDelay;
|
||||||
|
} FSP_FSVRT_DELETE_VOLUME_WORK_ITEM;
|
||||||
|
|
||||||
static NTSTATUS FspFsvrtDeleteVolume(
|
static NTSTATUS FspFsvrtDeleteVolume(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
{
|
{
|
||||||
@ -272,8 +281,13 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
|||||||
ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE);
|
ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
PDEVICE_OBJECT FsctlDeviceObject = FsvrtDeviceExtension->FsctlDeviceObject;
|
||||||
|
PDEVICE_OBJECT FsvolDeviceObject = FsvrtDeviceExtension->FsvolDeviceObject;
|
||||||
PVPB OldVpb;
|
PVPB OldVpb;
|
||||||
BOOLEAN FreeVpb = FALSE;
|
BOOLEAN DeleteVpb = FALSE;
|
||||||
|
BOOLEAN DeleteDelayed = FALSE;
|
||||||
|
LARGE_INTEGER DelayTimeout;
|
||||||
|
FSP_FSVRT_DELETE_VOLUME_WORK_ITEM *WorkItem = 0;
|
||||||
KIRQL Irql;
|
KIRQL Irql;
|
||||||
|
|
||||||
/* access check */
|
/* access check */
|
||||||
@ -282,6 +296,14 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
/* pre-allocate a work item in case we need it for delayed delete */
|
||||||
|
WorkItem = FspAllocNonPaged(sizeof *WorkItem);
|
||||||
|
if (0 == WorkItem)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
/* mark the virtual volume device as deleted */
|
/* mark the virtual volume device as deleted */
|
||||||
FsvrtDeviceExtension->Deleted = TRUE;
|
FsvrtDeviceExtension->Deleted = TRUE;
|
||||||
|
|
||||||
@ -302,16 +324,21 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
|||||||
DeviceObject->Vpb->RealDevice = OldVpb->RealDevice;
|
DeviceObject->Vpb->RealDevice = OldVpb->RealDevice;
|
||||||
DeviceObject->Vpb->RealDevice->Vpb = DeviceObject->Vpb;
|
DeviceObject->Vpb->RealDevice->Vpb = DeviceObject->Vpb;
|
||||||
FsvrtDeviceExtension->SwapVpb = 0;
|
FsvrtDeviceExtension->SwapVpb = 0;
|
||||||
FreeVpb = 0 == OldVpb->ReferenceCount;
|
DeleteVpb = 0 == OldVpb->ReferenceCount;
|
||||||
|
DeleteDelayed = !DeleteVpb && 0 != FsvolDeviceObject;
|
||||||
|
if (DeleteDelayed)
|
||||||
|
/* keep VPB around for delayed delete */
|
||||||
|
OldVpb->ReferenceCount++;
|
||||||
}
|
}
|
||||||
IoReleaseVpbSpinLock(Irql);
|
IoReleaseVpbSpinLock(Irql);
|
||||||
if (FreeVpb)
|
if (DeleteDelayed)
|
||||||
|
/* keep fsvol around for delayed delete */
|
||||||
|
FspDeviceRetain(FsvolDeviceObject);
|
||||||
|
else if (DeleteVpb)
|
||||||
FspFreeExternal(OldVpb);
|
FspFreeExternal(OldVpb);
|
||||||
#pragma prefast(pop)
|
#pragma prefast(pop)
|
||||||
|
|
||||||
/* release the file system device and virtual volume objects */
|
/* release the file system device and virtual volume objects */
|
||||||
PDEVICE_OBJECT FsctlDeviceObject = FsvrtDeviceExtension->FsctlDeviceObject;
|
|
||||||
PDEVICE_OBJECT FsvolDeviceObject = FsvrtDeviceExtension->FsvolDeviceObject;
|
|
||||||
FsvrtDeviceExtension->FsvolDeviceObject = 0;
|
FsvrtDeviceExtension->FsvolDeviceObject = 0;
|
||||||
if (0 != FsvolDeviceObject)
|
if (0 != FsvolDeviceObject)
|
||||||
FspDeviceRelease(FsvolDeviceObject);
|
FspDeviceRelease(FsvolDeviceObject);
|
||||||
@ -319,9 +346,23 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
|||||||
|
|
||||||
FspFsctlDeviceVolumeDeleted(FsctlDeviceObject);
|
FspFsctlDeviceVolumeDeleted(FsctlDeviceObject);
|
||||||
|
|
||||||
|
/* are we doing delayed delete of VPB and fsvol? */
|
||||||
|
if (DeleteDelayed)
|
||||||
|
{
|
||||||
|
DelayTimeout.QuadPart = 300/*ms*/ * -10000;
|
||||||
|
WorkItem->FsvolDeviceObject = FsvolDeviceObject;
|
||||||
|
WorkItem->OldVpb = OldVpb;
|
||||||
|
FspInitializeWorkItemWithDelay(&WorkItem->WorkItemWithDelay,
|
||||||
|
FspFsvrtDeleteVolumeDelayed, WorkItem);
|
||||||
|
FspQueueWorkItemWithDelay(&WorkItem->WorkItemWithDelay, DelayTimeout);
|
||||||
|
WorkItem = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Result = STATUS_SUCCESS;
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
exit:;
|
exit:
|
||||||
|
if (0 != WorkItem)
|
||||||
|
FspFree(WorkItem);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -331,6 +372,34 @@ static NTSTATUS FspFsvrtDeleteVolume(
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VOID FspFsvrtDeleteVolumeDelayed(PVOID Context)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_FSVRT_DELETE_VOLUME_WORK_ITEM *WorkItem = Context;
|
||||||
|
BOOLEAN DeleteVpb = FALSE;
|
||||||
|
LARGE_INTEGER DelayTimeout;
|
||||||
|
KIRQL Irql;
|
||||||
|
|
||||||
|
IoAcquireVpbSpinLock(&Irql);
|
||||||
|
ASSERT(0 != WorkItem->OldVpb->ReferenceCount);
|
||||||
|
DeleteVpb = 1 == WorkItem->OldVpb->ReferenceCount;
|
||||||
|
if (DeleteVpb)
|
||||||
|
WorkItem->OldVpb->ReferenceCount = 0;
|
||||||
|
IoReleaseVpbSpinLock(Irql);
|
||||||
|
if (DeleteVpb)
|
||||||
|
{
|
||||||
|
FspFreeExternal(WorkItem->OldVpb);
|
||||||
|
FspDeviceRelease(WorkItem->FsvolDeviceObject);
|
||||||
|
FspFree(WorkItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DelayTimeout.QuadPart = 300/*ms*/ * -10000;
|
||||||
|
FspQueueWorkItemWithDelay(&WorkItem->WorkItemWithDelay, DelayTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS FspFsvrtTransact(
|
static NTSTATUS FspFsvrtTransact(
|
||||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||||
{
|
{
|
||||||
|
@ -12,11 +12,17 @@ BOOLEAN FspValidRelativeSecurityDescriptor(
|
|||||||
SECURITY_INFORMATION RequiredInformation);
|
SECURITY_INFORMATION RequiredInformation);
|
||||||
NTSTATUS FspSecuritySubjectContextAccessCheck(
|
NTSTATUS FspSecuritySubjectContextAccessCheck(
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor, ACCESS_MASK DesiredAccess, KPROCESSOR_MODE AccessMode);
|
PSECURITY_DESCRIPTOR SecurityDescriptor, ACCESS_MASK DesiredAccess, KPROCESSOR_MODE AccessMode);
|
||||||
|
VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem,
|
||||||
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||||
|
VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout);
|
||||||
|
static KDEFERRED_ROUTINE FspQueueWorkItemWithDelayDPC;
|
||||||
|
|
||||||
#ifdef ALLOC_PRAGMA
|
#ifdef ALLOC_PRAGMA
|
||||||
#pragma alloc_text(PAGE, FspCreateGuid)
|
#pragma alloc_text(PAGE, FspCreateGuid)
|
||||||
#pragma alloc_text(PAGE, FspValidRelativeSecurityDescriptor)
|
#pragma alloc_text(PAGE, FspValidRelativeSecurityDescriptor)
|
||||||
#pragma alloc_text(PAGE, FspSecuritySubjectContextAccessCheck)
|
#pragma alloc_text(PAGE, FspSecuritySubjectContextAccessCheck)
|
||||||
|
#pragma alloc_text(PAGE, FspInitializeWorkItemWithDelay)
|
||||||
|
#pragma alloc_text(PAGE, FspQueueWorkItemWithDelay)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NTSTATUS FspCreateGuid(GUID *Guid)
|
NTSTATUS FspCreateGuid(GUID *Guid)
|
||||||
@ -74,3 +80,30 @@ NTSTATUS FspSecuritySubjectContextAccessCheck(
|
|||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem,
|
||||||
|
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
KeInitializeTimer(&WorkItem->Timer);
|
||||||
|
KeInitializeDpc(&WorkItem->Dpc, FspQueueWorkItemWithDelayDPC, WorkItem);
|
||||||
|
ExInitializeWorkItem(&WorkItem->WorkQueueItem, Routine, Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
KeSetTimer(&WorkItem->Timer, Timeout, &WorkItem->Dpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID FspQueueWorkItemWithDelayDPC(PKDPC Dpc,
|
||||||
|
PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
|
||||||
|
{
|
||||||
|
// !PAGED_CODE();
|
||||||
|
|
||||||
|
FSP_WORK_ITEM_WITH_DELAY *WorkItem = DeferredContext;
|
||||||
|
|
||||||
|
ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user