Skip to content

Commit

Permalink
Kernel - Lock Fcb during setFileInfo notify report change
Browse files Browse the repository at this point in the history
  • Loading branch information
Liryna committed Jan 28, 2022
1 parent eda8609 commit a1a557b
Showing 1 changed file with 138 additions and 110 deletions.
248 changes: 138 additions & 110 deletions sys/fileinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -797,134 +797,162 @@ VOID DokanCompleteSetInformation(__in PREQUEST_CONTEXT RequestContext,
__in PEVENT_INFORMATION EventInfo) {
PDokanCCB ccb;
PDokanFCB fcb = NULL;
UNICODE_STRING oldFileName;
BOOLEAN fcbLocked = FALSE;
BOOLEAN vcbLocked = FALSE;
FILE_INFORMATION_CLASS infoClass;

RequestContext->Irp->IoStatus.Information = EventInfo->BufferLength;
RequestContext->Irp->IoStatus.Status = EventInfo->Status;
__try {
RequestContext->Irp->IoStatus.Information = EventInfo->BufferLength;
RequestContext->Irp->IoStatus.Status = EventInfo->Status;

ccb = RequestContext->IrpSp->FileObject->FsContext2;
ASSERT(ccb != NULL);
ccb = RequestContext->IrpSp->FileObject->FsContext2;
ASSERT(ccb != NULL);

infoClass = RequestContext->IrpSp->Parameters.SetFile.FileInformationClass;
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject=%p infoClass=%s",
RequestContext->IrpSp->FileObject,
DokanGetFileInformationClassStr(infoClass));
fcb = ccb->Fcb;
ASSERT(fcb != NULL);

ccb->UserContext = EventInfo->Context;
infoClass = RequestContext->IrpSp->Parameters.SetFile.FileInformationClass;
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject=%p infoClass=%s",
RequestContext->IrpSp->FileObject,
DokanGetFileInformationClassStr(infoClass));

if (!NT_SUCCESS(RequestContext->Irp->IoStatus.Status)) {
return;
}
ccb->UserContext = EventInfo->Context;

fcb = ccb->Fcb;
ASSERT(fcb != NULL);

switch (RequestContext->IrpSp->Parameters.SetFile.FileInformationClass) {
case FileAllocationInformation:
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED);
break;
case FileBasicInformation:
DokanNotifyReportChange(
RequestContext, fcb,
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION,
FILE_ACTION_MODIFIED);
break;
case FileDispositionInformation:
case FileDispositionInformationEx: {
if (EventInfo->Operation.Delete.DeleteOnClose) {
// Note that we do not acquire the resource for paging file
// operations in order to avoid deadlock with Mm
BOOLEAN fcbLocked = !(RequestContext->Irp->Flags & IRP_PAGING_IO);
if (fcbLocked) {
DokanFCBLockRW(fcb);
if (!NT_SUCCESS(RequestContext->Irp->IoStatus.Status)) {
__leave;
}

// Note that we do not acquire the resource for paging file
// operations in order to avoid deadlock with Mm
if (!(RequestContext->Irp->Flags & IRP_PAGING_IO)) {
// If we are going to change the FileName on the FCB, then we want the VCB
// locked so that we don't race with the loop in create.c that searches
// currently open FCBs for a matching name. However, we need to lock that
// before the FCB so that the lock order is consistent everywhere.
if (NT_SUCCESS(RequestContext->Irp->IoStatus.Status) &&
infoClass == FileRenameInformation) {
DokanVCBLockRW(RequestContext->Vcb);
vcbLocked = TRUE;
}
if (!MmFlushImageSection(&fcb->SectionObjectPointers, MmFlushForDelete)) {
DOKAN_LOG_FINE_IRP(RequestContext, "Cannot delete user mapped image");
RequestContext->Irp->IoStatus.Status = STATUS_CANNOT_DELETE;
DokanFCBLockRW(fcb);
fcbLocked = TRUE;
}

switch (infoClass) {
case FileDispositionInformation:
case FileDispositionInformationEx: {
if (EventInfo->Operation.Delete.DeleteOnClose) {
if (!MmFlushImageSection(&fcb->SectionObjectPointers,
MmFlushForDelete)) {
DOKAN_LOG_FINE_IRP(RequestContext, "Cannot delete user mapped image");
RequestContext->Irp->IoStatus.Status = STATUS_CANNOT_DELETE;
} else {
DokanCCBFlagsSetBit(ccb, DOKAN_DELETE_ON_CLOSE);
DokanFCBFlagsSetBit(fcb, DOKAN_DELETE_ON_CLOSE);
DOKAN_LOG_FINE_IRP(RequestContext,
"FileObject->DeletePending = TRUE");
RequestContext->IrpSp->FileObject->DeletePending = TRUE;
}

} else {
DokanCCBFlagsSetBit(ccb, DOKAN_DELETE_ON_CLOSE);
DokanFCBFlagsSetBit(fcb, DOKAN_DELETE_ON_CLOSE);
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject->DeletePending = TRUE");
RequestContext->IrpSp->FileObject->DeletePending = TRUE;
DokanCCBFlagsClearBit(ccb, DOKAN_DELETE_ON_CLOSE);
DokanFCBFlagsClearBit(fcb, DOKAN_DELETE_ON_CLOSE);
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject->DeletePending = FALSE");
RequestContext->IrpSp->FileObject->DeletePending = FALSE;
}
if (fcbLocked) {
DokanFCBUnlock(fcb);
break;
}
case FileRenameInformation:
case FileRenameInformationEx: {
// Process rename
oldFileName =
DokanWrapUnicodeString(fcb->FileName.Buffer, fcb->FileName.Length);
// Copy new file name
PVOID buffer = DokanAllocZero(EventInfo->BufferLength + sizeof(WCHAR));
if (buffer == NULL) {
RequestContext->Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
} else {
DokanCCBFlagsClearBit(ccb, DOKAN_DELETE_ON_CLOSE);
DokanFCBFlagsClearBit(fcb, DOKAN_DELETE_ON_CLOSE);
DOKAN_LOG_FINE_IRP(RequestContext, "FileObject->DeletePending = FALSE");
RequestContext->IrpSp->FileObject->DeletePending = FALSE;
RtlCopyMemory(buffer, EventInfo->Buffer, EventInfo->BufferLength);
DokanRenameFcb(RequestContext, fcb, buffer,
(USHORT)EventInfo->BufferLength);
DOKAN_LOG_FINE_IRP(RequestContext, "Fcb=%p renamed \"%wZ\"", fcb,
&fcb->FileName);
break;
}
}
if (RequestContext->IrpSp->FileObject->DeletePending) {
if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {

switch (infoClass) {
case FileAllocationInformation:
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED);
break;
case FileBasicInformation:
DokanNotifyReportChange(
RequestContext, fcb,
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION,
FILE_ACTION_MODIFIED);
break;
case FileDispositionInformation:
case FileDispositionInformationEx:
if (RequestContext->IrpSp->FileObject->DeletePending) {
if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
DokanNotifyReportChange(RequestContext, fcb,
FILE_NOTIFY_CHANGE_DIR_NAME,
FILE_ACTION_REMOVED);
} else {
DokanNotifyReportChange(RequestContext, fcb,
FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_REMOVED);
}
}
break;
case FileEndOfFileInformation:
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED);
break;
case FileRenameInformation:
case FileRenameInformationEx: {
if (IsInSameDirectory(&oldFileName, &fcb->FileName)) {
DokanNotifyReportChange0(RequestContext, fcb, &oldFileName,
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_RENAMED_OLD_NAME);
DokanNotifyReportChange(RequestContext, fcb,
FILE_NOTIFY_CHANGE_DIR_NAME,
FILE_ACTION_REMOVED);
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_RENAMED_NEW_NAME);
} else {
DokanNotifyReportChange0(RequestContext, fcb, &oldFileName,
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_REMOVED);
DokanNotifyReportChange(RequestContext, fcb,
FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_REMOVED);
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_ADDED);
}
// free old file name
ExFreePool(oldFileName.Buffer);
} break;
case FileValidDataLengthInformation:
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED);
break;
}
} break;
case FileEndOfFileInformation:
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED);
break;
case FileRenameInformationEx:
case FileRenameInformation: {
DokanFCBLockRW(fcb);
// Process rename
UNICODE_STRING oldFileName =
DokanWrapUnicodeString(fcb->FileName.Buffer, fcb->FileName.Length);
// Copy new file name
PVOID buffer = DokanAllocZero(EventInfo->BufferLength + sizeof(WCHAR));
if (buffer == NULL) {
RequestContext->Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

} __finally {
if (fcbLocked) {
DokanFCBUnlock(fcb);
return;
}
RtlCopyMemory(buffer, EventInfo->Buffer, EventInfo->BufferLength);
DokanVCBLockRW(RequestContext->Vcb);
DokanRenameFcb(RequestContext, fcb, buffer,
(USHORT)EventInfo->BufferLength);
DokanVCBUnlock(RequestContext->Vcb);
DOKAN_LOG_FINE_IRP(RequestContext, "Fcb=%p renamed \"%wZ\"", fcb,
&fcb->FileName);
DokanFCBUnlock(fcb);
// Notify rename
if (IsInSameDirectory(&oldFileName, &fcb->FileName)) {
DokanNotifyReportChange0(RequestContext, fcb, &oldFileName,
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_RENAMED_OLD_NAME);
DokanNotifyReportChange(RequestContext, fcb,
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_RENAMED_NEW_NAME);
} else {
DokanNotifyReportChange0(RequestContext, fcb, &oldFileName,
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_REMOVED);
DokanNotifyReportChange(RequestContext, fcb,
DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_ACTION_ADDED);
if (vcbLocked) {
DokanVCBUnlock(RequestContext->Vcb);
}
// free old file name
ExFreePool(oldFileName.Buffer);
} break;
case FileValidDataLengthInformation:
DokanNotifyReportChange(RequestContext, fcb, FILE_NOTIFY_CHANGE_SIZE,
FILE_ACTION_MODIFIED);
break;
}
}
}

0 comments on commit a1a557b

Please sign in to comment.