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:
Bill Zissimopoulos 2015-12-14 15:56:44 -08:00
parent aee12e1c5f
commit a3312ad2f1
4 changed files with 123 additions and 6 deletions

View File

@ -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;
} }

View File

@ -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);

View File

@ -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)
{ {

View File

@ -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);
}