diff --git a/ntoskrnl/io/iomgr/file.c b/ntoskrnl/io/iomgr/file.c index 548c7f28db..0e3151877c 100644 --- a/ntoskrnl/io/iomgr/file.c +++ b/ntoskrnl/io/iomgr/file.c @@ -2574,6 +2574,8 @@ IopCreateFile(OUT PHANDLE FileHandle, PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters; POPEN_PACKET OpenPacket; ULONG EaErrorOffset; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + PEPROCESS SourceProcess; PAGED_CODE(); IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName); @@ -2721,6 +2723,95 @@ IopCreateFile(OUT PHANDLE FileHandle, } } + /* Handle Cygwin edge case of re-opening FileObject by handle by passing in only + * existing Handle. We re-route the call to ObDuplicateObject because we don't + * need OpenPacket or other calls in this case. We have all we need for this already. + * The caller provided a handle and no ObjectName in ObjectAttributes. + * We detect this combination and execute a different code path. + */ + if ((ObjectAttributes->ObjectName->Length <= 1 || (!ObjectAttributes->ObjectName->Length) || + (!ObjectAttributes->ObjectName) || (!ObjectAttributes->ObjectName->Buffer)) && + (ObjectAttributes->RootDirectory != 0) && (ObjectAttributes->RootDirectory != NULL)) + { + Status = ObReferenceObjectByHandle(NtCurrentProcess(), + PROCESS_DUP_HANDLE, + PsProcessType, + PreviousMode, + (PVOID*)&SourceProcess, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("(PID %lx) IopCreateFile call to ObReferenceObjectByHandle for Source Process failed - status: %lx\n", + PsGetCurrentProcessId(), Status); + return Status; + } + + Status = ObDuplicateObject(SourceProcess, + ObjectAttributes->RootDirectory, + SourceProcess, + &LocalHandle, + DesiredAccess, + ObjectAttributes->Attributes, + CreateOptions, + PreviousMode); + if (!NT_SUCCESS(Status)) + { + DPRINT("(PID %lx) IopCreateFile call to ObDuplicateObject failed - status: %lx\n", PsGetCurrentProcessId(), Status); + ObDereferenceObject(SourceProcess); + return Status; + } + + ObDereferenceObject(SourceProcess); + + if (AccessMode != KernelMode) + { /* probe for write access for non-kernel mode */ + _SEH2_TRY + { + /* Probe the output parameters */ + ProbeForWriteHandle(FileHandle); + ProbeForWriteIoStatusBlock(IoStatusBlock); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Get the exception status */ + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; + } + + /* perform write back of handle and status information */ + _SEH2_TRY + { + *FileHandle = LocalHandle; + /* since we do not use Io for this calling mode set up 'fake' Io status + * and final status if we didn't crash before this point we succeeded + */ + IoStatusBlock->Status = STATUS_SUCCESS; + Status = STATUS_SUCCESS; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Get the exception status */ + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; + + if (!NT_SUCCESS(Status)) + { + if (LocalHandle != 0) + { + DPRINT("(PID %lx) IopCreateFile Completed status != NT_SUCCESS - returning status: 0x%lx handle: %p FileName: %wZ \n", + PsGetCurrentProcessId(), Status, LocalHandle, ObjectAttributes->ObjectName ); + } + else + { + DPRINT("(PID %lx) IopCreateFile Completed status != NT_SUCCESS - returning status: 0x%lx handle: 0x0 FileName: %wZ \n", + PsGetCurrentProcessId(), Status, ObjectAttributes->ObjectName ); + } + } + return Status; + } /* Cygwin edge case code path ends here */ + /* Allocate the open packet */ OpenPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*OpenPacket), 'pOoI'); if (!OpenPacket) return STATUS_INSUFFICIENT_RESOURCES;