diff --git a/src/sys/create.c b/src/sys/create.c index f829f959..9ecfa68e 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -24,7 +24,8 @@ static NTSTATUS FspFsvrtCreate( static NTSTATUS FspFsvolCreate( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static NTSTATUS FspFsvolCreateNoLock( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, + BOOLEAN MainFileOpen); FSP_IOPREP_DISPATCH FspFsvolCreatePrepare; FSP_IOCMPL_DISPATCH FspFsvolCreateComplete; static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, @@ -109,23 +110,30 @@ static NTSTATUS FspFsvolCreate( PAGED_CODE(); NTSTATUS Result = STATUS_SUCCESS; + BOOLEAN MainFileOpen = FspMainFileOpenCheck(Irp); - FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject); - try + if (!MainFileOpen) { - Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp); - } - finally - { - if (FSP_STATUS_IOQ_POST != Result) - FspFsvolDeviceFileRenameRelease(FsvolDeviceObject); + FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject); + try + { + Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, FALSE); + } + finally + { + if (FSP_STATUS_IOQ_POST != Result) + FspFsvolDeviceFileRenameRelease(FsvolDeviceObject); + } } + else + Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, TRUE); return Result; } static NTSTATUS FspFsvolCreateNoLock( - PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, + BOOLEAN MainFileOpen) { PAGED_CODE(); @@ -220,7 +228,7 @@ static NTSTATUS FspFsvolCreateNoLock( FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0)) return STATUS_OBJECT_NAME_INVALID; - /* if we have a stream part */ + /* if we have a stream part (even non-empty) */ if (0 != StreamPart.Buffer) { ASSERT( @@ -398,6 +406,9 @@ static NTSTATUS FspFsvolCreateNoLock( /* remember the main file node */ FileNode->MainFileNode = FileDesc->MainFileObject->FsContext; + ASSERT(RtlEqualUnicodeString(&MainFileName, &FileNode->MainFileNode->FileName, + !CaseSensitive)); + Result = STATUS_SUCCESS; main_stream_exit: @@ -427,8 +438,11 @@ static NTSTATUS FspFsvolCreateNoLock( FileDesc->FileNode = FileNode; FileDesc->CaseSensitive = CaseSensitive; FileDesc->HasTraversePrivilege = HasTraversePrivilege; - FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request); - FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject; + if (!MainFileOpen) + { + FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request); + FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject; + } FspIopRequestContext(Request, RequestFileDesc) = FileDesc; /* populate the Create request */ @@ -798,6 +812,8 @@ NTSTATUS FspFsvolCreateComplete( if (FileNode->IsDirectory) SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY); + PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject); + /* disassociate the FileDesc momentarily from the Request */ FspIopRequestContext(Request, RequestDeviceObject) = 0; FspIopRequestContext(Request, RequestFileDesc) = 0; @@ -806,7 +822,7 @@ NTSTATUS FspFsvolCreateComplete( Request->Kind = FspFsctlTransactOverwriteKind; RtlZeroMemory(&Request->Req.Create, sizeof Request->Req.Create); FspIopResetRequest(Request, FspFsvolCreateOverwriteRequestFini); - FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject; + FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue; FspIopRequestContext(Request, RequestFileDesc) = FileDesc; FspIopRequestContext(Request, RequestFileObject) = FileObject; FspIopRequestContext(Request, RequestState) = (PVOID)RequestPending; @@ -889,7 +905,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re if (FspFsctlTransactCreateKind == Request->Kind) { - PDEVICE_OBJECT FsvolDeviceObject = FspIopRequestContext(Request, RequestDeviceObject); + PVOID RequestDeviceObjectValue = FspIopRequestContext(Request, RequestDeviceObject); /* disassociate the FileDesc momentarily from the Request */ Request = FspIrpRequest(Irp); @@ -899,7 +915,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re /* reset the Request and reassociate the FileDesc and FileObject with it */ Request->Kind = FspFsctlTransactReservedKind; FspIopResetRequest(Request, FspFsvolCreateTryOpenRequestFini); - FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject; + FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue; FspIopRequestContext(Request, RequestFileDesc) = FileDesc; FspIopRequestContext(Request, RequestFileObject) = FileObject; FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage; diff --git a/src/sys/driver.h b/src/sys/driver.h index 5616ea31..17e611a4 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -431,17 +431,6 @@ VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE NTSTATUS FspCreateGuid(GUID *Guid); NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess, PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject); -NTSTATUS FspMainFileOpen( - PDEVICE_OBJECT DeviceObject, - PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive, - PSECURITY_DESCRIPTOR SecurityDescriptor, - ULONG FileAttributes, - ULONG Disposition, - PHANDLE PMainFileHandle, - PFILE_OBJECT *PMainFileObject); -NTSTATUS FspMainFileClose( - HANDLE MainFileHandle, - PFILE_OBJECT MainFileObject); NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length); NTSTATUS FspBufferUserBuffer(PIRP Irp, ULONG Length, LOCK_OPERATION Operation); @@ -1034,6 +1023,39 @@ NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc); VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, PUNICODE_STRING FileName, BOOLEAN Reset); +NTSTATUS FspMainFileOpen( + PDEVICE_OBJECT FsvolDeviceObject, + PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive, + PSECURITY_DESCRIPTOR SecurityDescriptor, + ULONG FileAttributes, + ULONG Disposition, + PHANDLE PMainFileHandle, + PFILE_OBJECT *PMainFileObject); +NTSTATUS FspMainFileClose( + HANDLE MainFileHandle, + PFILE_OBJECT MainFileObject); +static __forceinline +BOOLEAN FspMainFileOpenCheck(PIRP Irp) +{ + extern const GUID FspMainFileOpenEcpGuid; + NTSTATUS Result; + PECP_LIST ExtraCreateParameters = 0; + PVOID ExtraCreateParameter = 0; + + Result = FsRtlGetEcpListFromIrp(Irp, &ExtraCreateParameters); + if (!NT_SUCCESS(Result) || 0 == ExtraCreateParameters) + return FALSE; + + Result = FsRtlFindExtraCreateParameter(ExtraCreateParameters, + &FspMainFileOpenEcpGuid, &ExtraCreateParameter, 0); + if (!NT_SUCCESS(Result) || 0 == ExtraCreateParameter) + return FALSE; + + if (FsRtlIsEcpFromUserMode(ExtraCreateParameter)) + return FALSE; + + return TRUE; +} #define FspFileNodeAcquireShared(N,F) FspFileNodeAcquireSharedF(N, FspFileNodeAcquire ## F) #define FspFileNodeTryAcquireShared(N,F) FspFileNodeTryAcquireSharedF(N, FspFileNodeAcquire ## F, FALSE) #define FspFileNodeAcquireExclusive(N,F) FspFileNodeAcquireExclusiveF(N, FspFileNodeAcquire ## F) @@ -1069,6 +1091,7 @@ extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[]; extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[]; extern ERESOURCE FspDeviceGlobalResource; extern WCHAR FspFileDescDirectoryPatternMatchAll[]; +extern const GUID FspMainFileOpenEcpGuid; extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache; extern ULONG FspMvMdlMappingNoWrite; diff --git a/src/sys/file.c b/src/sys/file.c index c0b0537e..094e7512 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -70,6 +70,17 @@ NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc); VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, PUNICODE_STRING FileName, BOOLEAN Reset); +NTSTATUS FspMainFileOpen( + PDEVICE_OBJECT FsvolDeviceObject, + PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive, + PSECURITY_DESCRIPTOR SecurityDescriptor, + ULONG FileAttributes, + ULONG Disposition, + PHANDLE PMainFileHandle, + PFILE_OBJECT *PMainFileObject); +NTSTATUS FspMainFileClose( + HANDLE MainFileHandle, + PFILE_OBJECT MainFileObject); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFileNodeCopyList) @@ -112,6 +123,8 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, #pragma alloc_text(PAGE, FspFileDescCreate) #pragma alloc_text(PAGE, FspFileDescDelete) #pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern) +#pragma alloc_text(PAGE, FspMainFileOpen) +#pragma alloc_text(PAGE, FspMainFileClose) #endif #define FSP_FILE_NODE_GET_FLAGS() \ @@ -1238,4 +1251,170 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, return STATUS_SUCCESS; } +NTSTATUS FspMainFileOpen( + PDEVICE_OBJECT FsvolDeviceObject, + PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive, + PSECURITY_DESCRIPTOR SecurityDescriptor, + ULONG FileAttributes, + ULONG Disposition, + PHANDLE PMainFileHandle, + PFILE_OBJECT *PMainFileObject) +{ + PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + UNICODE_STRING FullFileName = { 0 }; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatus; + IO_DRIVER_CREATE_CONTEXT DriverCreateContext = { 0 }; + PVOID ExtraCreateParameter; + HANDLE MainFileHandle; + PFILE_OBJECT MainFileObject; + + /* assert that the supplied name is actually a main file name */ + ASSERT(FspUnicodePathIsValid(MainFileName, 0)); + + *PMainFileHandle = 0; + *PMainFileObject = 0; + + switch (Disposition) + { + case FILE_CREATE: + case FILE_OPEN_IF: + case FILE_OVERWRITE_IF: + Disposition = FILE_OPEN_IF; + break; + case FILE_OPEN: + case FILE_OVERWRITE: + case FILE_SUPERSEDE: + Disposition = FILE_OPEN; + break; + default: + IoStatus.Status = STATUS_INVALID_PARAMETER; + goto exit; + } + + FullFileName.Length = 0; + FullFileName.MaximumLength = + FsvolDeviceExtension->VolumeName.Length + + FsvolDeviceExtension->VolumePrefix.Length + + MainFileName->Length; + FullFileName.Buffer = FspAlloc(FullFileName.MaximumLength); + if (0 == FullFileName.Buffer) + { + IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + RtlAppendUnicodeStringToString(&FullFileName, &FsvolDeviceExtension->VolumeName); + RtlAppendUnicodeStringToString(&FullFileName, &FsvolDeviceExtension->VolumePrefix); + RtlAppendUnicodeStringToString(&FullFileName, MainFileName); + + InitializeObjectAttributes( + &ObjectAttributes, + &FullFileName, + OBJ_KERNEL_HANDLE | OBJ_FORCE_ACCESS_CHECK | (CaseSensitive ? 0 : OBJ_CASE_INSENSITIVE), + 0/*RootDirectory*/, + SecurityDescriptor); + + /* do not use SiloContext field as it is only available on Win10 v1607 and higher */ + DriverCreateContext.Size = + FIELD_OFFSET(IO_DRIVER_CREATE_CONTEXT, TxnParameters) + + sizeof(((PIO_DRIVER_CREATE_CONTEXT)0)->TxnParameters); + DriverCreateContext.DeviceObjectHint = FsvolDeviceObject; + + IoStatus.Status = FsRtlAllocateExtraCreateParameterList(0, + &DriverCreateContext.ExtraCreateParameter); + if (!NT_SUCCESS(IoStatus.Status)) + goto exit; + + IoStatus.Status = FsRtlAllocateExtraCreateParameter(&FspMainFileOpenEcpGuid, + sizeof(PVOID), + 0/*Flags*/, + 0/*CleanupCallback*/, + FSP_ALLOC_INTERNAL_TAG, + &ExtraCreateParameter); + if (!NT_SUCCESS(IoStatus.Status)) + goto exit; + + IoStatus.Status = FsRtlInsertExtraCreateParameter(DriverCreateContext.ExtraCreateParameter, + ExtraCreateParameter); + if (!NT_SUCCESS(IoStatus.Status)) + { + FsRtlFreeExtraCreateParameter(ExtraCreateParameter); + goto exit; + } + + IoStatus.Status = IoCreateFileEx( + &MainFileHandle, + FILE_READ_ATTRIBUTES, + &ObjectAttributes, + &IoStatus, + 0/*AllocationSize*/, + FileAttributes, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + Disposition, + FILE_OPEN_REPARSE_POINT, + 0/*EaBuffer*/, + 0/*EaLength*/, + CreateFileTypeNone, + 0/*InternalParameters*/, + IO_FORCE_ACCESS_CHECK, + &DriverCreateContext); + if (!NT_SUCCESS(IoStatus.Status)) + goto exit; + + IoStatus.Status = ObReferenceObjectByHandle( + MainFileHandle, + 0/*DesiredAccess*/, + *IoFileObjectType, + KernelMode, + &MainFileObject, + 0/*HandleInformation*/); + if (!NT_SUCCESS(IoStatus.Status)) + { + ObCloseHandle(MainFileHandle, KernelMode); + goto exit; + } + + *PMainFileHandle = MainFileHandle; + *PMainFileObject = MainFileObject; + + IoStatus.Status = STATUS_SUCCESS; + +exit: + if (0 != DriverCreateContext.ExtraCreateParameter) + FsRtlFreeExtraCreateParameterList(DriverCreateContext.ExtraCreateParameter); + + if (0 != FullFileName.Buffer) + FspFree(FullFileName.Buffer); + + return IoStatus.Status; +} + +NTSTATUS FspMainFileClose( + HANDLE MainFileHandle, + PFILE_OBJECT MainFileObject) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_SUCCESS; + + if (0 != MainFileObject) + ObDereferenceObject(MainFileObject); + + if (0 != MainFileHandle) + { + Result = ObCloseHandle(MainFileHandle, KernelMode); + if (!NT_SUCCESS(Result)) + DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result)); + } + + return Result; +} + WCHAR FspFileDescDirectoryPatternMatchAll[] = L"*"; + +// {904862B4-EB3F-461E-ACB2-4DF2B3FC898B} +const GUID FspMainFileOpenEcpGuid = + { 0x904862b4, 0xeb3f, 0x461e, { 0xac, 0xb2, 0x4d, 0xf2, 0xb3, 0xfc, 0x89, 0x8b } }; diff --git a/src/sys/util.c b/src/sys/util.c index fab43f5a..6cffe1d0 100644 --- a/src/sys/util.c +++ b/src/sys/util.c @@ -23,17 +23,6 @@ VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE NTSTATUS FspCreateGuid(GUID *Guid); NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess, PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject); -NTSTATUS FspMainFileOpen( - PDEVICE_OBJECT DeviceObject, - PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive, - PSECURITY_DESCRIPTOR SecurityDescriptor, - ULONG FileAttributes, - ULONG Disposition, - PHANDLE PMainFileHandle, - PFILE_OBJECT *PMainFileObject); -NTSTATUS FspMainFileClose( - HANDLE MainFileHandle, - PFILE_OBJECT MainFileObject); NTSTATUS FspSendSetInformationIrp(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length); static NTSTATUS FspSendSetInformationIrpCompletion( @@ -104,8 +93,6 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context); #pragma alloc_text(PAGE, FspUnicodePathSuffix) #pragma alloc_text(PAGE, FspCreateGuid) #pragma alloc_text(PAGE, FspGetDeviceObjectPointer) -#pragma alloc_text(PAGE, FspMainFileOpen) -#pragma alloc_text(PAGE, FspMainFileClose) #pragma alloc_text(PAGE, FspSendSetInformationIrp) #pragma alloc_text(PAGE, FspBufferUserBuffer) #pragma alloc_text(PAGE, FspLockUserBuffer) @@ -386,110 +373,6 @@ NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK Desir return Result; } -NTSTATUS FspMainFileOpen( - PDEVICE_OBJECT DeviceObject, - PUNICODE_STRING MainFileName, BOOLEAN CaseSensitive, - PSECURITY_DESCRIPTOR SecurityDescriptor, - ULONG FileAttributes, - ULONG Disposition, - PHANDLE PMainFileHandle, - PFILE_OBJECT *PMainFileObject) -{ - PAGED_CODE(); - - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatus; - HANDLE MainFileHandle; - PFILE_OBJECT MainFileObject; - - /* assert that the supplied name is actually a main file name */ - ASSERT(FspUnicodePathIsValid(MainFileName, 0)); - - *PMainFileHandle = 0; - *PMainFileObject = 0; - - switch (Disposition) - { - case FILE_CREATE: - case FILE_OPEN_IF: - case FILE_OVERWRITE_IF: - Disposition = FILE_OPEN_IF; - break; - case FILE_OPEN: - case FILE_OVERWRITE: - case FILE_SUPERSEDE: - Disposition = FILE_OPEN; - break; - default: - return STATUS_INVALID_PARAMETER; - } - - InitializeObjectAttributes( - &ObjectAttributes, - MainFileName, - OBJ_KERNEL_HANDLE | OBJ_FORCE_ACCESS_CHECK | (CaseSensitive ? 0 : OBJ_CASE_INSENSITIVE), - 0/*RootDirectory*/, - SecurityDescriptor); - - IoStatus.Status = IoCreateFileSpecifyDeviceObjectHint( - &MainFileHandle, - FILE_READ_ATTRIBUTES, - &ObjectAttributes, - &IoStatus, - 0/*AllocationSize*/, - FileAttributes, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - Disposition, - FILE_OPEN_REPARSE_POINT, - 0/*EaBuffer*/, - 0/*EaLength*/, - CreateFileTypeNone, - 0/*InternalParameters*/, - IO_FORCE_ACCESS_CHECK, - DeviceObject); - if (!NT_SUCCESS(IoStatus.Status)) - return IoStatus.Status; - - IoStatus.Status = ObReferenceObjectByHandle( - MainFileHandle, - 0/*DesiredAccess*/, - *IoFileObjectType, - KernelMode, - &MainFileObject, - 0/*HandleInformation*/); - if (!NT_SUCCESS(IoStatus.Status)) - { - ObCloseHandle(MainFileHandle, KernelMode); - return IoStatus.Status; - } - - *PMainFileHandle = MainFileHandle; - *PMainFileObject = MainFileObject; - - return STATUS_SUCCESS; -} - -NTSTATUS FspMainFileClose( - HANDLE MainFileHandle, - PFILE_OBJECT MainFileObject) -{ - PAGED_CODE(); - - NTSTATUS Result = STATUS_SUCCESS; - - if (0 != MainFileObject) - ObDereferenceObject(MainFileObject); - - if (0 != MainFileHandle) - { - Result = ObCloseHandle(MainFileHandle, KernelMode); - if (!NT_SUCCESS(Result)) - DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result)); - } - - return Result; -} - typedef struct { IO_STATUS_BLOCK IoStatus;