Skip to content

Commit a1a557b

Browse files
committed
Kernel - Lock Fcb during setFileInfo notify report change
1 parent eda8609 commit a1a557b

File tree

1 file changed

+138
-110
lines changed

1 file changed

+138
-110
lines changed

sys/fileinfo.c

Lines changed: 138 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -797,134 +797,162 @@ VOID DokanCompleteSetInformation(__in PREQUEST_CONTEXT RequestContext,
797797
__in PEVENT_INFORMATION EventInfo) {
798798
PDokanCCB ccb;
799799
PDokanFCB fcb = NULL;
800+
UNICODE_STRING oldFileName;
801+
BOOLEAN fcbLocked = FALSE;
802+
BOOLEAN vcbLocked = FALSE;
800803
FILE_INFORMATION_CLASS infoClass;
801804

802-
RequestContext->Irp->IoStatus.Information = EventInfo->BufferLength;
803-
RequestContext->Irp->IoStatus.Status = EventInfo->Status;
805+
__try {
806+
RequestContext->Irp->IoStatus.Information = EventInfo->BufferLength;
807+
RequestContext->Irp->IoStatus.Status = EventInfo->Status;
804808

805-
ccb = RequestContext->IrpSp->FileObject->FsContext2;
806-
ASSERT(ccb != NULL);
809+
ccb = RequestContext->IrpSp->FileObject->FsContext2;
810+
ASSERT(ccb != NULL);
807811

808-
infoClass = RequestContext->IrpSp->Parameters.SetFile.FileInformationClass;
809-
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject=%p infoClass=%s",
810-
RequestContext->IrpSp->FileObject,
811-
DokanGetFileInformationClassStr(infoClass));
812+
fcb = ccb->Fcb;
813+
ASSERT(fcb != NULL);
812814

813-
ccb->UserContext = EventInfo->Context;
815+
infoClass = RequestContext->IrpSp->Parameters.SetFile.FileInformationClass;
816+
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject=%p infoClass=%s",
817+
RequestContext->IrpSp->FileObject,
818+
DokanGetFileInformationClassStr(infoClass));
814819

815-
if (!NT_SUCCESS(RequestContext->Irp->IoStatus.Status)) {
816-
return;
817-
}
820+
ccb->UserContext = EventInfo->Context;
818821

819-
fcb = ccb->Fcb;
820-
ASSERT(fcb != NULL);
821-
822-
switch (RequestContext->IrpSp->Parameters.SetFile.FileInformationClass) {
823-
case FileAllocationInformation:
824-
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
825-
FILE_ACTION_MODIFIED);
826-
break;
827-
case FileBasicInformation:
828-
DokanNotifyReportChange(
829-
RequestContext, fcb,
830-
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE |
831-
FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION,
832-
FILE_ACTION_MODIFIED);
833-
break;
834-
case FileDispositionInformation:
835-
case FileDispositionInformationEx: {
836-
if (EventInfo->Operation.Delete.DeleteOnClose) {
837-
// Note that we do not acquire the resource for paging file
838-
// operations in order to avoid deadlock with Mm
839-
BOOLEAN fcbLocked = !(RequestContext->Irp->Flags & IRP_PAGING_IO);
840-
if (fcbLocked) {
841-
DokanFCBLockRW(fcb);
822+
if (!NT_SUCCESS(RequestContext->Irp->IoStatus.Status)) {
823+
__leave;
824+
}
825+
826+
// Note that we do not acquire the resource for paging file
827+
// operations in order to avoid deadlock with Mm
828+
if (!(RequestContext->Irp->Flags & IRP_PAGING_IO)) {
829+
// If we are going to change the FileName on the FCB, then we want the VCB
830+
// locked so that we don't race with the loop in create.c that searches
831+
// currently open FCBs for a matching name. However, we need to lock that
832+
// before the FCB so that the lock order is consistent everywhere.
833+
if (NT_SUCCESS(RequestContext->Irp->IoStatus.Status) &&
834+
infoClass == FileRenameInformation) {
835+
DokanVCBLockRW(RequestContext->Vcb);
836+
vcbLocked = TRUE;
842837
}
843-
if (!MmFlushImageSection(&fcb->SectionObjectPointers, MmFlushForDelete)) {
844-
DOKAN_LOG_FINE_IRP(RequestContext, "Cannot delete user mapped image");
845-
RequestContext->Irp->IoStatus.Status = STATUS_CANNOT_DELETE;
838+
DokanFCBLockRW(fcb);
839+
fcbLocked = TRUE;
840+
}
841+
842+
switch (infoClass) {
843+
case FileDispositionInformation:
844+
case FileDispositionInformationEx: {
845+
if (EventInfo->Operation.Delete.DeleteOnClose) {
846+
if (!MmFlushImageSection(&fcb->SectionObjectPointers,
847+
MmFlushForDelete)) {
848+
DOKAN_LOG_FINE_IRP(RequestContext, "Cannot delete user mapped image");
849+
RequestContext->Irp->IoStatus.Status = STATUS_CANNOT_DELETE;
850+
} else {
851+
DokanCCBFlagsSetBit(ccb, DOKAN_DELETE_ON_CLOSE);
852+
DokanFCBFlagsSetBit(fcb, DOKAN_DELETE_ON_CLOSE);
853+
DOKAN_LOG_FINE_IRP(RequestContext,
854+
"FileObject->DeletePending = TRUE");
855+
RequestContext->IrpSp->FileObject->DeletePending = TRUE;
856+
}
857+
846858
} else {
847-
DokanCCBFlagsSetBit(ccb, DOKAN_DELETE_ON_CLOSE);
848-
DokanFCBFlagsSetBit(fcb, DOKAN_DELETE_ON_CLOSE);
849-
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject->DeletePending = TRUE");
850-
RequestContext->IrpSp->FileObject->DeletePending = TRUE;
859+
DokanCCBFlagsClearBit(ccb, DOKAN_DELETE_ON_CLOSE);
860+
DokanFCBFlagsClearBit(fcb, DOKAN_DELETE_ON_CLOSE);
861+
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject->DeletePending = FALSE");
862+
RequestContext->IrpSp->FileObject->DeletePending = FALSE;
851863
}
852-
if (fcbLocked) {
853-
DokanFCBUnlock(fcb);
864+
break;
865+
}
866+
case FileRenameInformation:
867+
case FileRenameInformationEx: {
868+
// Process rename
869+
oldFileName =
870+
DokanWrapUnicodeString(fcb->FileName.Buffer, fcb->FileName.Length);
871+
// Copy new file name
872+
PVOID buffer = DokanAllocZero(EventInfo->BufferLength + sizeof(WCHAR));
873+
if (buffer == NULL) {
874+
RequestContext->Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
875+
__leave;
854876
}
855-
} else {
856-
DokanCCBFlagsClearBit(ccb, DOKAN_DELETE_ON_CLOSE);
857-
DokanFCBFlagsClearBit(fcb, DOKAN_DELETE_ON_CLOSE);
858-
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject->DeletePending = FALSE");
859-
RequestContext->IrpSp->FileObject->DeletePending = FALSE;
877+
RtlCopyMemory(buffer, EventInfo->Buffer, EventInfo->BufferLength);
878+
DokanRenameFcb(RequestContext, fcb, buffer,
879+
(USHORT)EventInfo->BufferLength);
880+
DOKAN_LOG_FINE_IRP(RequestContext, "Fcb=%p renamed \"%wZ\"", fcb,
881+
&fcb->FileName);
882+
break;
883+
}
860884
}
861-
if (RequestContext->IrpSp->FileObject->DeletePending) {
862-
if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
885+
886+
switch (infoClass) {
887+
case FileAllocationInformation:
888+
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
889+
FILE_ACTION_MODIFIED);
890+
break;
891+
case FileBasicInformation:
892+
DokanNotifyReportChange(
893+
RequestContext, fcb,
894+
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE |
895+
FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION,
896+
FILE_ACTION_MODIFIED);
897+
break;
898+
case FileDispositionInformation:
899+
case FileDispositionInformationEx:
900+
if (RequestContext->IrpSp->FileObject->DeletePending) {
901+
if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
902+
DokanNotifyReportChange(RequestContext, fcb,
903+
FILE_NOTIFY_CHANGE_DIR_NAME,
904+
FILE_ACTION_REMOVED);
905+
} else {
906+
DokanNotifyReportChange(RequestContext, fcb,
907+
FILE_NOTIFY_CHANGE_FILE_NAME,
908+
FILE_ACTION_REMOVED);
909+
}
910+
}
911+
break;
912+
case FileEndOfFileInformation:
913+
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
914+
FILE_ACTION_MODIFIED);
915+
break;
916+
case FileRenameInformation:
917+
case FileRenameInformationEx: {
918+
if (IsInSameDirectory(&oldFileName, &fcb->FileName)) {
919+
DokanNotifyReportChange0(RequestContext, fcb, &oldFileName,
920+
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
921+
? FILE_NOTIFY_CHANGE_DIR_NAME
922+
: FILE_NOTIFY_CHANGE_FILE_NAME,
923+
FILE_ACTION_RENAMED_OLD_NAME);
863924
DokanNotifyReportChange(RequestContext, fcb,
864-
FILE_NOTIFY_CHANGE_DIR_NAME,
865-
FILE_ACTION_REMOVED);
925+
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
926+
? FILE_NOTIFY_CHANGE_DIR_NAME
927+
: FILE_NOTIFY_CHANGE_FILE_NAME,
928+
FILE_ACTION_RENAMED_NEW_NAME);
866929
} else {
930+
DokanNotifyReportChange0(RequestContext, fcb, &oldFileName,
931+
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
932+
? FILE_NOTIFY_CHANGE_DIR_NAME
933+
: FILE_NOTIFY_CHANGE_FILE_NAME,
934+
FILE_ACTION_REMOVED);
867935
DokanNotifyReportChange(RequestContext, fcb,
868-
FILE_NOTIFY_CHANGE_FILE_NAME,
869-
FILE_ACTION_REMOVED);
936+
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
937+
? FILE_NOTIFY_CHANGE_DIR_NAME
938+
: FILE_NOTIFY_CHANGE_FILE_NAME,
939+
FILE_ACTION_ADDED);
870940
}
941+
// free old file name
942+
ExFreePool(oldFileName.Buffer);
943+
} break;
944+
case FileValidDataLengthInformation:
945+
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
946+
FILE_ACTION_MODIFIED);
947+
break;
871948
}
872-
} break;
873-
case FileEndOfFileInformation:
874-
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
875-
FILE_ACTION_MODIFIED);
876-
break;
877-
case FileRenameInformationEx:
878-
case FileRenameInformation: {
879-
DokanFCBLockRW(fcb);
880-
// Process rename
881-
UNICODE_STRING oldFileName =
882-
DokanWrapUnicodeString(fcb->FileName.Buffer, fcb->FileName.Length);
883-
// Copy new file name
884-
PVOID buffer = DokanAllocZero(EventInfo->BufferLength + sizeof(WCHAR));
885-
if (buffer == NULL) {
886-
RequestContext->Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
949+
950+
} __finally {
951+
if (fcbLocked) {
887952
DokanFCBUnlock(fcb);
888-
return;
889953
}
890-
RtlCopyMemory(buffer, EventInfo->Buffer, EventInfo->BufferLength);
891-
DokanVCBLockRW(RequestContext->Vcb);
892-
DokanRenameFcb(RequestContext, fcb, buffer,
893-
(USHORT)EventInfo->BufferLength);
894-
DokanVCBUnlock(RequestContext->Vcb);
895-
DOKAN_LOG_FINE_IRP(RequestContext, "Fcb=%p renamed \"%wZ\"", fcb,
896-
&fcb->FileName);
897-
DokanFCBUnlock(fcb);
898-
// Notify rename
899-
if (IsInSameDirectory(&oldFileName, &fcb->FileName)) {
900-
DokanNotifyReportChange0(RequestContext, fcb, &oldFileName,
901-
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
902-
? FILE_NOTIFY_CHANGE_DIR_NAME
903-
: FILE_NOTIFY_CHANGE_FILE_NAME,
904-
FILE_ACTION_RENAMED_OLD_NAME);
905-
DokanNotifyReportChange(RequestContext, fcb,
906-
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
907-
? FILE_NOTIFY_CHANGE_DIR_NAME
908-
: FILE_NOTIFY_CHANGE_FILE_NAME,
909-
FILE_ACTION_RENAMED_NEW_NAME);
910-
} else {
911-
DokanNotifyReportChange0(RequestContext, fcb, &oldFileName,
912-
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
913-
? FILE_NOTIFY_CHANGE_DIR_NAME
914-
: FILE_NOTIFY_CHANGE_FILE_NAME,
915-
FILE_ACTION_REMOVED);
916-
DokanNotifyReportChange(RequestContext, fcb,
917-
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
918-
? FILE_NOTIFY_CHANGE_DIR_NAME
919-
: FILE_NOTIFY_CHANGE_FILE_NAME,
920-
FILE_ACTION_ADDED);
954+
if (vcbLocked) {
955+
DokanVCBUnlock(RequestContext->Vcb);
921956
}
922-
// free old file name
923-
ExFreePool(oldFileName.Buffer);
924-
} break;
925-
case FileValidDataLengthInformation:
926-
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
927-
FILE_ACTION_MODIFIED);
928-
break;
929957
}
930-
}
958+
}

0 commit comments

Comments
 (0)