Author: pschweitzer Date: Sun Apr 5 20:02:30 2015 New Revision: 67067
URL: http://svn.reactos.org/svn/reactos?rev=67067&view=rev Log: [NTOSKRNL] Implement the reparse points loop in IopParseDevice().
Reviewed by Thomas
Modified: trunk/reactos/ntoskrnl/include/internal/io.h trunk/reactos/ntoskrnl/io/iomgr/file.c
Modified: trunk/reactos/ntoskrnl/include/internal/io.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/i... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/io.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/io.h [iso-8859-1] Sun Apr 5 20:02:30 2015 @@ -79,6 +79,11 @@ // Unable to create symbolic link pointing to the RAM disk device // #define RD_SYMLINK_CREATE_FAILED 5 + +// +// Max traversal of reparse points for a single open in IoParseDevice +// +#define IOP_MAX_REPARSE_TRAVERSAL 0x20
// // We can call the Ob Inlined API, it's the same thing
Modified: trunk/reactos/ntoskrnl/io/iomgr/file.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/file.c?re... ============================================================================== --- trunk/reactos/ntoskrnl/io/iomgr/file.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/io/iomgr/file.c [iso-8859-1] Sun Apr 5 20:02:30 2015 @@ -300,751 +300,760 @@ BOOLEAN AccessGranted, LockHeld = FALSE; PPRIVILEGE_SET Privileges = NULL; UNICODE_STRING FileString; + USHORT Attempt; IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n", ParseObject, RemainingName);
- /* Assume failure */ - *Object = NULL; - - /* Validate the open packet */ - if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH; - - /* Valide reparse point in case we traversed a mountpoint */ - if (OpenPacket->TraversedMountPoint) - { - /* This is a reparse point we understand */ - ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT); - - /* Make sure we're dealing with correct DO */ - if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK && - OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM && - OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK && - OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE) - { - OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID; - return STATUS_IO_REPARSE_DATA_INVALID; - } - } - - /* Check if we have a related file object */ - if (OpenPacket->RelatedFileObject) - { - /* Use the related file object's device object */ - OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject; - } - - /* Validate device status */ - Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject); - if (!NT_SUCCESS(Status)) - { - /* We failed, return status */ - OpenPacket->FinalStatus = Status; - return Status; - } - - /* Map the generic mask and set the new mapping in the access state */ - RtlMapGenericMask(&AccessState->RemainingDesiredAccess, - &IoFileObjectType->TypeInfo.GenericMapping); - RtlMapGenericMask(&AccessState->OriginalDesiredAccess, - &IoFileObjectType->TypeInfo.GenericMapping); - SeSetAccessStateGenericMapping(AccessState, - &IoFileObjectType->TypeInfo.GenericMapping); - DesiredAccess = AccessState->RemainingDesiredAccess; - - /* Check what kind of access checks to do */ - if ((AccessMode != KernelMode) || - (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) - { - /* Call is from user-mode or kernel is forcing checks */ - CheckMode = UserMode; - } - else - { - /* Call is from the kernel */ - CheckMode = KernelMode; - } - - /* Check privilege for backup or restore operation */ - IopCheckBackupRestorePrivilege(AccessState, - &OpenPacket->CreateOptions, - CheckMode, - OpenPacket->Disposition); - - /* Check if we are re-parsing */ - if (((OpenPacket->Override) && !(RemainingName->Length)) || - (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED)) - { - /* Get granted access from the last call */ - DesiredAccess |= AccessState->PreviouslyGrantedAccess; - } - - /* Check if this is a volume open */ - if ((OpenPacket->RelatedFileObject) && - (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) && - !(RemainingName->Length)) - { - /* It is */ - VolumeOpen = TRUE; - } - - /* Now check if we need access checks */ - if (((AccessMode != KernelMode) || - (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) && - (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) && - !(OpenPacket->Override)) - { - KeEnterCriticalRegion(); - ExAcquireResourceSharedLite(&IopSecurityResource, TRUE); - - /* Check if a device object is being parsed */ - if (!RemainingName->Length) - { - /* Lock the subject context */ - SeLockSubjectContext(&AccessState->SubjectSecurityContext); - LockHeld = TRUE; - - /* Do access check */ - AccessGranted = SeAccessCheck(OriginalDeviceObject-> - SecurityDescriptor, - &AccessState->SubjectSecurityContext, - LockHeld, - DesiredAccess, - 0, - &Privileges, - &IoFileObjectType-> - TypeInfo.GenericMapping, - UserMode, - &GrantedAccess, - &Status); - if (Privileges) - { - /* Append and free the privileges */ - SeAppendPrivileges(AccessState, Privileges); - SeFreePrivileges(Privileges); - } - - /* Check if we got access */ - if (AccessGranted) - { - /* Update access state */ - AccessState->PreviouslyGrantedAccess |= GrantedAccess; - AccessState->RemainingDesiredAccess &= ~(GrantedAccess & - MAXIMUM_ALLOWED); - OpenPacket->Override= TRUE; - } - - FileString.Length = 8; - FileString.MaximumLength = 8; - FileString.Buffer = L"File"; - - /* Do Audit/Alarm for open operation */ - SeOpenObjectAuditAlarm(&FileString, - OriginalDeviceObject, - CompleteName, - OriginalDeviceObject->SecurityDescriptor, - AccessState, - FALSE, - AccessGranted, - UserMode, - &AccessState->GenerateOnClose); + for (Attempt = 0; Attempt < IOP_MAX_REPARSE_TRAVERSAL; ++Attempt) + { + /* Assume failure */ + *Object = NULL; + + /* Validate the open packet */ + if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH; + + /* Valide reparse point in case we traversed a mountpoint */ + if (OpenPacket->TraversedMountPoint) + { + /* This is a reparse point we understand */ + ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT); + + /* Make sure we're dealing with correct DO */ + if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK && + OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM && + OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK && + OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE) + { + OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID; + return STATUS_IO_REPARSE_DATA_INVALID; + } + } + + /* Check if we have a related file object */ + if (OpenPacket->RelatedFileObject) + { + /* Use the related file object's device object */ + OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject; + } + + /* Validate device status */ + Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject); + if (!NT_SUCCESS(Status)) + { + /* We failed, return status */ + OpenPacket->FinalStatus = Status; + return Status; + } + + /* Map the generic mask and set the new mapping in the access state */ + RtlMapGenericMask(&AccessState->RemainingDesiredAccess, + &IoFileObjectType->TypeInfo.GenericMapping); + RtlMapGenericMask(&AccessState->OriginalDesiredAccess, + &IoFileObjectType->TypeInfo.GenericMapping); + SeSetAccessStateGenericMapping(AccessState, + &IoFileObjectType->TypeInfo.GenericMapping); + DesiredAccess = AccessState->RemainingDesiredAccess; + + /* Check what kind of access checks to do */ + if ((AccessMode != KernelMode) || + (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) + { + /* Call is from user-mode or kernel is forcing checks */ + CheckMode = UserMode; } else { - /* Check if we need to do traverse validation */ - if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) || - ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) || - (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM))) - { - /* Check if this is a restricted token */ - if (!(AccessState->Flags & TOKEN_IS_RESTRICTED)) + /* Call is from the kernel */ + CheckMode = KernelMode; + } + + /* Check privilege for backup or restore operation */ + IopCheckBackupRestorePrivilege(AccessState, + &OpenPacket->CreateOptions, + CheckMode, + OpenPacket->Disposition); + + /* Check if we are re-parsing */ + if (((OpenPacket->Override) && !(RemainingName->Length)) || + (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED)) + { + /* Get granted access from the last call */ + DesiredAccess |= AccessState->PreviouslyGrantedAccess; + } + + /* Check if this is a volume open */ + if ((OpenPacket->RelatedFileObject) && + (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) && + !(RemainingName->Length)) + { + /* It is */ + VolumeOpen = TRUE; + } + + /* Now check if we need access checks */ + if (((AccessMode != KernelMode) || + (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) && + (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) && + !(OpenPacket->Override)) + { + KeEnterCriticalRegion(); + ExAcquireResourceSharedLite(&IopSecurityResource, TRUE); + + /* Check if a device object is being parsed */ + if (!RemainingName->Length) + { + /* Lock the subject context */ + SeLockSubjectContext(&AccessState->SubjectSecurityContext); + LockHeld = TRUE; + + /* Do access check */ + AccessGranted = SeAccessCheck(OriginalDeviceObject-> + SecurityDescriptor, + &AccessState->SubjectSecurityContext, + LockHeld, + DesiredAccess, + 0, + &Privileges, + &IoFileObjectType-> + TypeInfo.GenericMapping, + UserMode, + &GrantedAccess, + &Status); + if (Privileges) { - /* Do the FAST traverse check */ - AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor, - AccessState, - FILE_TRAVERSE, - UserMode); + /* Append and free the privileges */ + SeAppendPrivileges(AccessState, Privileges); + SeFreePrivileges(Privileges); + } + + /* Check if we got access */ + if (AccessGranted) + { + /* Update access state */ + AccessState->PreviouslyGrantedAccess |= GrantedAccess; + AccessState->RemainingDesiredAccess &= ~(GrantedAccess & + MAXIMUM_ALLOWED); + OpenPacket->Override= TRUE; + } + + FileString.Length = 8; + FileString.MaximumLength = 8; + FileString.Buffer = L"File"; + + /* Do Audit/Alarm for open operation */ + SeOpenObjectAuditAlarm(&FileString, + OriginalDeviceObject, + CompleteName, + OriginalDeviceObject->SecurityDescriptor, + AccessState, + FALSE, + AccessGranted, + UserMode, + &AccessState->GenerateOnClose); + } + else + { + /* Check if we need to do traverse validation */ + if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) || + ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) || + (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM))) + { + /* Check if this is a restricted token */ + if (!(AccessState->Flags & TOKEN_IS_RESTRICTED)) + { + /* Do the FAST traverse check */ + AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor, + AccessState, + FILE_TRAVERSE, + UserMode); + } + else + { + /* Fail */ + AccessGranted = FALSE; + } + + /* Check if we failed to get access */ + if (!AccessGranted) + { + /* Lock the subject context */ + SeLockSubjectContext(&AccessState->SubjectSecurityContext); + LockHeld = TRUE; + + /* Do access check */ + AccessGranted = SeAccessCheck(OriginalDeviceObject-> + SecurityDescriptor, + &AccessState->SubjectSecurityContext, + LockHeld, + FILE_TRAVERSE, + 0, + &Privileges, + &IoFileObjectType-> + TypeInfo.GenericMapping, + UserMode, + &GrantedAccess, + &Status); + if (Privileges) + { + /* Append and free the privileges */ + SeAppendPrivileges(AccessState, Privileges); + SeFreePrivileges(Privileges); + } + } + + /* FIXME: Do Audit/Alarm for traverse check */ } else { - /* Fail */ - AccessGranted = FALSE; + /* Access automatically granted */ + AccessGranted = TRUE; } - - /* Check if we failed to get access */ - if (!AccessGranted) - { - /* Lock the subject context */ - SeLockSubjectContext(&AccessState->SubjectSecurityContext); - LockHeld = TRUE; - - /* Do access check */ - AccessGranted = SeAccessCheck(OriginalDeviceObject-> - SecurityDescriptor, - &AccessState->SubjectSecurityContext, - LockHeld, - FILE_TRAVERSE, - 0, - &Privileges, - &IoFileObjectType-> - TypeInfo.GenericMapping, - UserMode, - &GrantedAccess, - &Status); - if (Privileges) - { - /* Append and free the privileges */ - SeAppendPrivileges(AccessState, Privileges); - SeFreePrivileges(Privileges); - } - } - - /* FIXME: Do Audit/Alarm for traverse check */ - } - else - { - /* Access automatically granted */ - AccessGranted = TRUE; - } - } - - ExReleaseResourceLite(&IopSecurityResource); - KeLeaveCriticalRegion(); - - /* Check if we hold the lock */ - if (LockHeld) - { - /* Release it */ - SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); - } - - /* Check if access failed */ - if (!AccessGranted) - { - /* Dereference the device and fail */ - DPRINT1("Traverse access failed!\n"); - IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); - return STATUS_ACCESS_DENIED; - } - } - - /* Check if we can simply use a dummy file */ - UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly)); + } + + ExReleaseResourceLite(&IopSecurityResource); + KeLeaveCriticalRegion(); + + /* Check if we hold the lock */ + if (LockHeld) + { + /* Release it */ + SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); + } + + /* Check if access failed */ + if (!AccessGranted) + { + /* Dereference the device and fail */ + DPRINT1("Traverse access failed!\n"); + IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); + return STATUS_ACCESS_DENIED; + } + } + + /* Check if we can simply use a dummy file */ + UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
#if 1 - /* FIXME: Small hack still exists, have to check why... - * This is triggered multiple times by usetup and then once per boot. - */ - if (ExpInTextModeSetup && - !(DirectOpen) && - !(RemainingName->Length) && - !(OpenPacket->RelatedFileObject) && - ((wcsstr(CompleteName->Buffer, L"Harddisk")) || - (wcsstr(CompleteName->Buffer, L"Floppy"))) && - !(UseDummyFile)) - { - DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n", - DesiredAccess & ~(SYNCHRONIZE | - FILE_READ_ATTRIBUTES | - READ_CONTROL | - ACCESS_SYSTEM_SECURITY | - WRITE_OWNER | - WRITE_DAC)); - DirectOpen = TRUE; - } + /* FIXME: Small hack still exists, have to check why... + * This is triggered multiple times by usetup and then once per boot. + */ + if (ExpInTextModeSetup && + !(DirectOpen) && + !(RemainingName->Length) && + !(OpenPacket->RelatedFileObject) && + ((wcsstr(CompleteName->Buffer, L"Harddisk")) || + (wcsstr(CompleteName->Buffer, L"Floppy"))) && + !(UseDummyFile)) + { + DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n", + DesiredAccess & ~(SYNCHRONIZE | + FILE_READ_ATTRIBUTES | + READ_CONTROL | + ACCESS_SYSTEM_SECURITY | + WRITE_OWNER | + WRITE_DAC)); + DirectOpen = TRUE; + } #endif
- /* Check if this is a direct open */ - if (!(RemainingName->Length) && - !(OpenPacket->RelatedFileObject) && - ((DesiredAccess & ~(SYNCHRONIZE | - FILE_READ_ATTRIBUTES | - READ_CONTROL | - ACCESS_SYSTEM_SECURITY | - WRITE_OWNER | - WRITE_DAC)) == 0) && - !(UseDummyFile)) - { - /* Remember this for later */ - DirectOpen = TRUE; - } - - /* Check if we have a related FO that wasn't a direct open */ - if ((OpenPacket->RelatedFileObject) && - !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN)) - { - /* The device object is the one we were given */ - DeviceObject = ParseObject; - - /* Check if the related FO had a VPB */ - if (OpenPacket->RelatedFileObject->Vpb) - { - /* Yes, remember it */ - Vpb = OpenPacket->RelatedFileObject->Vpb; - - /* Reference it */ - InterlockedIncrement((PLONG)&Vpb->ReferenceCount); - } - } - else - { - /* The device object is the one we were given */ - DeviceObject = OriginalDeviceObject; - - /* Check if it has a VPB */ - if ((OriginalDeviceObject->Vpb) && !(DirectOpen)) - { - /* Check if the VPB is mounted, and mount it */ - Vpb = IopCheckVpbMounted(OpenPacket, - OriginalDeviceObject, - RemainingName, - &Status); - if (!Vpb) return Status; - - /* Get the VPB's device object */ - DeviceObject = Vpb->DeviceObject; - } - - /* Check if there's an attached device */ - if (DeviceObject->AttachedDevice) - { - /* Get the attached device */ - DeviceObject = IoGetAttachedDevice(DeviceObject); - } - } - - /* If we traversed a mount point, reset the information */ - if (OpenPacket->TraversedMountPoint) - { - OpenPacket->TraversedMountPoint = FALSE; - } - - /* Check if this is a secure FSD */ - if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) && - ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) && - (!VolumeOpen)) - { - DPRINT("Fix Secure FSD support!!!\n"); - } - - /* Allocate the IRP */ - Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); - if (!Irp) - { - /* Dereference the device and VPB, then fail */ - IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); - if (Vpb) IopDereferenceVpbAndFree(Vpb); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Now set the IRP data */ - Irp->RequestorMode = AccessMode; - Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION; - Irp->Tail.Overlay.Thread = PsGetCurrentThread(); - Irp->UserIosb = &IoStatusBlock; - Irp->MdlAddress = NULL; - Irp->PendingReturned = FALSE; - Irp->UserEvent = NULL; - Irp->Cancel = FALSE; - Irp->CancelRoutine = NULL; - Irp->Tail.Overlay.AuxiliaryBuffer = NULL; - - /* Setup the security context */ - SecurityContext.SecurityQos = SecurityQos; - SecurityContext.AccessState = AccessState; - SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess; - SecurityContext.FullCreateOptions = OpenPacket->CreateOptions; - - /* Get the I/O Stack location */ - StackLoc = (PEXTENDED_IO_STACK_LOCATION)IoGetNextIrpStackLocation(Irp); - StackLoc->Control = 0; - - /* Check what kind of file this is */ - switch (OpenPacket->CreateFileType) - { - /* Normal file */ - case CreateFileTypeNone: - - /* Set the major function and EA Length */ - StackLoc->MajorFunction = IRP_MJ_CREATE; - StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength; - - /* Set the flags */ - StackLoc->Flags = (UCHAR)OpenPacket->Options; - StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0; - break; - - /* Named pipe */ - case CreateFileTypeNamedPipe: - - /* Set the named pipe MJ and set the parameters */ - StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE; - StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters; - break; - - /* Mailslot */ - case CreateFileTypeMailslot: - - /* Set the mailslot MJ and set the parameters */ - StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT; - StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters; - break; - } - - /* Set the common data */ - Irp->Overlay.AllocationSize = OpenPacket->AllocationSize; - Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer; - StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) | - (OpenPacket->CreateOptions & - 0xFFFFFF); - StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes; - StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess; - StackLoc->Parameters.Create.SecurityContext = &SecurityContext; - - /* Check if we really need to create an object */ - if (!UseDummyFile) - { - /* Create the actual file object */ - InitializeObjectAttributes(&ObjectAttributes, - NULL, - Attributes, - NULL, - NULL); - Status = ObCreateObject(KernelMode, - IoFileObjectType, - &ObjectAttributes, - AccessMode, - NULL, - sizeof(FILE_OBJECT), - 0, - 0, - (PVOID*)&FileObject); - if (!NT_SUCCESS(Status)) - { - /* Create failed, free the IRP */ - IoFreeIrp(Irp); - - /* Dereference the device and VPB */ + /* Check if this is a direct open */ + if (!(RemainingName->Length) && + !(OpenPacket->RelatedFileObject) && + ((DesiredAccess & ~(SYNCHRONIZE | + FILE_READ_ATTRIBUTES | + READ_CONTROL | + ACCESS_SYSTEM_SECURITY | + WRITE_OWNER | + WRITE_DAC)) == 0) && + !(UseDummyFile)) + { + /* Remember this for later */ + DirectOpen = TRUE; + } + + /* Check if we have a related FO that wasn't a direct open */ + if ((OpenPacket->RelatedFileObject) && + !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN)) + { + /* The device object is the one we were given */ + DeviceObject = ParseObject; + + /* Check if the related FO had a VPB */ + if (OpenPacket->RelatedFileObject->Vpb) + { + /* Yes, remember it */ + Vpb = OpenPacket->RelatedFileObject->Vpb; + + /* Reference it */ + InterlockedIncrement((PLONG)&Vpb->ReferenceCount); + } + } + else + { + /* The device object is the one we were given */ + DeviceObject = OriginalDeviceObject; + + /* Check if it has a VPB */ + if ((OriginalDeviceObject->Vpb) && !(DirectOpen)) + { + /* Check if the VPB is mounted, and mount it */ + Vpb = IopCheckVpbMounted(OpenPacket, + OriginalDeviceObject, + RemainingName, + &Status); + if (!Vpb) return Status; + + /* Get the VPB's device object */ + DeviceObject = Vpb->DeviceObject; + } + + /* Check if there's an attached device */ + if (DeviceObject->AttachedDevice) + { + /* Get the attached device */ + DeviceObject = IoGetAttachedDevice(DeviceObject); + } + } + + /* If we traversed a mount point, reset the information */ + if (OpenPacket->TraversedMountPoint) + { + OpenPacket->TraversedMountPoint = FALSE; + } + + /* Check if this is a secure FSD */ + if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) && + ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) && + (!VolumeOpen)) + { + DPRINT("Fix Secure FSD support!!!\n"); + } + + /* Allocate the IRP */ + Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); + if (!Irp) + { + /* Dereference the device and VPB, then fail */ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); if (Vpb) IopDereferenceVpbAndFree(Vpb); - - /* We failed, return status */ + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Now set the IRP data */ + Irp->RequestorMode = AccessMode; + Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + Irp->UserIosb = &IoStatusBlock; + Irp->MdlAddress = NULL; + Irp->PendingReturned = FALSE; + Irp->UserEvent = NULL; + Irp->Cancel = FALSE; + Irp->CancelRoutine = NULL; + Irp->Tail.Overlay.AuxiliaryBuffer = NULL; + + /* Setup the security context */ + SecurityContext.SecurityQos = SecurityQos; + SecurityContext.AccessState = AccessState; + SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess; + SecurityContext.FullCreateOptions = OpenPacket->CreateOptions; + + /* Get the I/O Stack location */ + StackLoc = (PEXTENDED_IO_STACK_LOCATION)IoGetNextIrpStackLocation(Irp); + StackLoc->Control = 0; + + /* Check what kind of file this is */ + switch (OpenPacket->CreateFileType) + { + /* Normal file */ + case CreateFileTypeNone: + + /* Set the major function and EA Length */ + StackLoc->MajorFunction = IRP_MJ_CREATE; + StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength; + + /* Set the flags */ + StackLoc->Flags = (UCHAR)OpenPacket->Options; + StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0; + break; + + /* Named pipe */ + case CreateFileTypeNamedPipe: + + /* Set the named pipe MJ and set the parameters */ + StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE; + StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters; + break; + + /* Mailslot */ + case CreateFileTypeMailslot: + + /* Set the mailslot MJ and set the parameters */ + StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT; + StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters; + break; + } + + /* Set the common data */ + Irp->Overlay.AllocationSize = OpenPacket->AllocationSize; + Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer; + StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) | + (OpenPacket->CreateOptions & + 0xFFFFFF); + StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes; + StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess; + StackLoc->Parameters.Create.SecurityContext = &SecurityContext; + + /* Check if we really need to create an object */ + if (!UseDummyFile) + { + /* Create the actual file object */ + InitializeObjectAttributes(&ObjectAttributes, + NULL, + Attributes, + NULL, + NULL); + Status = ObCreateObject(KernelMode, + IoFileObjectType, + &ObjectAttributes, + AccessMode, + NULL, + sizeof(FILE_OBJECT), + 0, + 0, + (PVOID*)&FileObject); + if (!NT_SUCCESS(Status)) + { + /* Create failed, free the IRP */ + IoFreeIrp(Irp); + + /* Dereference the device and VPB */ + IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); + if (Vpb) IopDereferenceVpbAndFree(Vpb); + + /* We failed, return status */ + OpenPacket->FinalStatus = Status; + return Status; + } + + /* Clear the file object */ + RtlZeroMemory(FileObject, sizeof(FILE_OBJECT)); + + /* Check if this is Synch I/O */ + if (OpenPacket->CreateOptions & + (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) + { + /* Set the synch flag */ + FileObject->Flags |= FO_SYNCHRONOUS_IO; + + /* Check if it's also alertable */ + if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) + { + /* It is, set the alertable flag */ + FileObject->Flags |= FO_ALERTABLE_IO; + } + } + + /* Check if this is synch I/O */ + if (FileObject->Flags & FO_SYNCHRONOUS_IO) + { + /* Initialize the event */ + KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE); + } + + /* Check if the caller requested no intermediate buffering */ + if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) + { + /* Set the correct flag for the FSD to read */ + FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; + } + + /* Check if the caller requested write through support */ + if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH) + { + /* Set the correct flag for the FSD to read */ + FileObject->Flags |= FO_WRITE_THROUGH; + } + + /* Check if the caller says the file will be only read sequentially */ + if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY) + { + /* Set the correct flag for the FSD to read */ + FileObject->Flags |= FO_SEQUENTIAL_ONLY; + } + + /* Check if the caller believes the file will be only read randomly */ + if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS) + { + /* Set the correct flag for the FSD to read */ + FileObject->Flags |= FO_RANDOM_ACCESS; + } + } + else + { + /* Use the dummy object instead */ + LocalFileObject = OpenPacket->LocalFileObject; + RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT)); + + /* Set it up */ + FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body; + LocalFileObject->ObjectHeader.Type = IoFileObjectType; + LocalFileObject->ObjectHeader.PointerCount = 1; + } + + /* Setup the file header */ + FileObject->Type = IO_TYPE_FILE; + FileObject->Size = sizeof(FILE_OBJECT); + FileObject->RelatedFileObject = OpenPacket->RelatedFileObject; + FileObject->DeviceObject = OriginalDeviceObject; + + /* Check if this is a direct device open */ + if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN; + + /* Check if the caller wants case sensitivity */ + if (!(Attributes & OBJ_CASE_INSENSITIVE)) + { + /* Tell the driver about it */ + FileObject->Flags |= FO_OPENED_CASE_SENSITIVE; + } + + /* Now set the file object */ + Irp->Tail.Overlay.OriginalFileObject = FileObject; + StackLoc->FileObject = FileObject; + + /* Check if the file object has a name */ + if (RemainingName->Length) + { + /* Setup the unicode string */ + FileObject->FileName.MaximumLength = RemainingName->Length + + sizeof(WCHAR); + FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool, + FileObject-> + FileName. + MaximumLength, + TAG_IO_NAME); + if (!FileObject->FileName.Buffer) + { + /* Failed to allocate the name, free the IRP */ + IoFreeIrp(Irp); + + /* Dereference the device object and VPB */ + IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); + if (Vpb) IopDereferenceVpbAndFree(Vpb); + + /* Clear the FO and dereference it */ + FileObject->DeviceObject = NULL; + if (!UseDummyFile) ObDereferenceObject(FileObject); + + /* Fail */ + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + /* Copy the name */ + RtlCopyUnicodeString(&FileObject->FileName, RemainingName); + + /* Initialize the File Object event and set the FO */ + KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE); + OpenPacket->FileObject = FileObject; + + /* Queue the IRP and call the driver */ + IopQueueIrpToThread(Irp); + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + /* Wait for the driver to complete the create */ + KeWaitForSingleObject(&FileObject->Event, + Executive, + KernelMode, + FALSE, + NULL); + + /* Get the new status */ + Status = IoStatusBlock.Status; + } + else + { + /* We'll have to complete it ourselves */ + ASSERT(!Irp->PendingReturned); + ASSERT(!Irp->MdlAddress); + + /* Handle name change if required */ + if (Status == STATUS_REPARSE) + { + /* Check this is a mount point */ + if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT) + { + PREPARSE_DATA_BUFFER ReparseData; + + /* Reparse point attributes were passed by the driver in the auxiliary buffer */ + ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL); + ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer; + + ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT); + ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + + IopDoNameTransmogrify(Irp, FileObject, ReparseData); + } + } + + /* Completion happens at APC_LEVEL */ + KeRaiseIrql(APC_LEVEL, &OldIrql); + + /* Get the new I/O Status block ourselves */ + IoStatusBlock = Irp->IoStatus; + Status = IoStatusBlock.Status; + + /* Manually signal the even, we can't have any waiters */ + FileObject->Event.Header.SignalState = 1; + + /* Now that we've signaled the events, de-associate the IRP */ + IopUnQueueIrpFromThread(Irp); + + /* Check if the IRP had an input buffer */ + if ((Irp->Flags & IRP_BUFFERED_IO) && + (Irp->Flags & IRP_DEALLOCATE_BUFFER)) + { + /* Free it. A driver might've tacked one on */ + ExFreePool(Irp->AssociatedIrp.SystemBuffer); + } + + /* Free the IRP and bring the IRQL back down */ + IoFreeIrp(Irp); + KeLowerIrql(OldIrql); + } + + /* Copy the I/O Status */ + OpenPacket->Information = IoStatusBlock.Information; + + /* The driver failed to create the file */ + if (!NT_SUCCESS(Status)) + { + /* Check if we have a name */ + if (FileObject->FileName.Length) + { + /* Free it */ + ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME); + FileObject->FileName.Length = 0; + } + + /* Clear its device object */ + FileObject->DeviceObject = NULL; + + /* Save this now because the FO might go away */ + OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ? + TRUE : FALSE; + + /* Clear the file object in the open packet */ + OpenPacket->FileObject = NULL; + + /* Dereference the file object */ + if (!UseDummyFile) ObDereferenceObject(FileObject); + + /* Dereference the device object */ + IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); + + /* Unless the driver cancelled the open, dereference the VPB */ + if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb); + + /* Set the status and return */ OpenPacket->FinalStatus = Status; return Status; } - - /* Clear the file object */ - RtlZeroMemory(FileObject, sizeof(FILE_OBJECT)); - - /* Check if this is Synch I/O */ - if (OpenPacket->CreateOptions & - (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) - { - /* Set the synch flag */ - FileObject->Flags |= FO_SYNCHRONOUS_IO; - - /* Check if it's also alertable */ - if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) - { - /* It is, set the alertable flag */ - FileObject->Flags |= FO_ALERTABLE_IO; - } - } - - /* Check if this is synch I/O */ - if (FileObject->Flags & FO_SYNCHRONOUS_IO) - { - /* Initialize the event */ - KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE); - } - - /* Check if the caller requested no intermediate buffering */ - if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) - { - /* Set the correct flag for the FSD to read */ - FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; - } - - /* Check if the caller requested write through support */ - if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH) - { - /* Set the correct flag for the FSD to read */ - FileObject->Flags |= FO_WRITE_THROUGH; - } - - /* Check if the caller says the file will be only read sequentially */ - if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY) - { - /* Set the correct flag for the FSD to read */ - FileObject->Flags |= FO_SEQUENTIAL_ONLY; - } - - /* Check if the caller believes the file will be only read randomly */ - if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS) - { - /* Set the correct flag for the FSD to read */ - FileObject->Flags |= FO_RANDOM_ACCESS; - } - } - else - { - /* Use the dummy object instead */ - LocalFileObject = OpenPacket->LocalFileObject; - RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT)); - - /* Set it up */ - FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body; - LocalFileObject->ObjectHeader.Type = IoFileObjectType; - LocalFileObject->ObjectHeader.PointerCount = 1; - } - - /* Setup the file header */ - FileObject->Type = IO_TYPE_FILE; - FileObject->Size = sizeof(FILE_OBJECT); - FileObject->RelatedFileObject = OpenPacket->RelatedFileObject; - FileObject->DeviceObject = OriginalDeviceObject; - - /* Check if this is a direct device open */ - if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN; - - /* Check if the caller wants case sensitivity */ - if (!(Attributes & OBJ_CASE_INSENSITIVE)) - { - /* Tell the driver about it */ - FileObject->Flags |= FO_OPENED_CASE_SENSITIVE; - } - - /* Now set the file object */ - Irp->Tail.Overlay.OriginalFileObject = FileObject; - StackLoc->FileObject = FileObject; - - /* Check if the file object has a name */ - if (RemainingName->Length) - { - /* Setup the unicode string */ - FileObject->FileName.MaximumLength = RemainingName->Length + - sizeof(WCHAR); - FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool, - FileObject-> - FileName. - MaximumLength, - TAG_IO_NAME); - if (!FileObject->FileName.Buffer) - { - /* Failed to allocate the name, free the IRP */ - IoFreeIrp(Irp); - - /* Dereference the device object and VPB */ + else if (Status == STATUS_REPARSE) + { + if (OpenPacket->Information == IO_REPARSE || + OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT) + { + /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */ + if (CompleteName->MaximumLength < FileObject->FileName.Length) + { + PWSTR NewCompleteName; + + /* Allocate a new buffer for the string */ + NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME); + if (NewCompleteName == NULL) + { + OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES; + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Release the old one */ + if (CompleteName->Buffer != NULL) + { + ExFreePoolWithTag(CompleteName->Buffer, TAG_IO_NAME); + } + + /* And setup the new one */ + CompleteName->Buffer = NewCompleteName; + CompleteName->MaximumLength = FileObject->FileName.Length; + } + + /* Copy our new complete name */ + RtlCopyUnicodeString(CompleteName, &FileObject->FileName); + + if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT) + { + OpenPacket->RelatedFileObject = NULL; + } + } + + /* Check if we have a name */ + if (FileObject->FileName.Length) + { + /* Free it */ + ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME); + FileObject->FileName.Length = 0; + } + + /* Clear its device object */ + FileObject->DeviceObject = NULL; + + /* Clear the file object in the open packet */ + OpenPacket->FileObject = NULL; + + /* Dereference the file object */ + if (!UseDummyFile) ObDereferenceObject(FileObject); + + /* Dereference the device object */ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); - if (Vpb) IopDereferenceVpbAndFree(Vpb); - - /* Clear the FO and dereference it */ - FileObject->DeviceObject = NULL; - if (!UseDummyFile) ObDereferenceObject(FileObject); - - /* Fail */ - return STATUS_INSUFFICIENT_RESOURCES; - } - } - - /* Copy the name */ - RtlCopyUnicodeString(&FileObject->FileName, RemainingName); - - /* Initialize the File Object event and set the FO */ - KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE); - OpenPacket->FileObject = FileObject; - - /* Queue the IRP and call the driver */ - IopQueueIrpToThread(Irp); - Status = IoCallDriver(DeviceObject, Irp); - if (Status == STATUS_PENDING) - { - /* Wait for the driver to complete the create */ - KeWaitForSingleObject(&FileObject->Event, - Executive, - KernelMode, - FALSE, - NULL); - - /* Get the new status */ - Status = IoStatusBlock.Status; - } - else - { - /* We'll have to complete it ourselves */ - ASSERT(!Irp->PendingReturned); - ASSERT(!Irp->MdlAddress); - - /* Handle name change if required */ - if (Status == STATUS_REPARSE) - { - /* Check this is a mount point */ - if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT) - { - PREPARSE_DATA_BUFFER ReparseData; - - /* Reparse point attributes were passed by the driver in the auxiliary buffer */ - ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL); - ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer; - - ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT); - ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - - IopDoNameTransmogrify(Irp, FileObject, ReparseData); - } - } - - /* Completion happens at APC_LEVEL */ - KeRaiseIrql(APC_LEVEL, &OldIrql); - - /* Get the new I/O Status block ourselves */ - IoStatusBlock = Irp->IoStatus; - Status = IoStatusBlock.Status; - - /* Manually signal the even, we can't have any waiters */ - FileObject->Event.Header.SignalState = 1; - - /* Now that we've signaled the events, de-associate the IRP */ - IopUnQueueIrpFromThread(Irp); - - /* Check if the IRP had an input buffer */ - if ((Irp->Flags & IRP_BUFFERED_IO) && - (Irp->Flags & IRP_DEALLOCATE_BUFFER)) - { - /* Free it. A driver might've tacked one on */ - ExFreePool(Irp->AssociatedIrp.SystemBuffer); - } - - /* Free the IRP and bring the IRQL back down */ - IoFreeIrp(Irp); - KeLowerIrql(OldIrql); - } - - /* Copy the I/O Status */ - OpenPacket->Information = IoStatusBlock.Information; - - /* The driver failed to create the file */ - if (!NT_SUCCESS(Status)) - { - /* Check if we have a name */ - if (FileObject->FileName.Length) - { - /* Free it */ - ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME); - FileObject->FileName.Length = 0; - } - - /* Clear its device object */ - FileObject->DeviceObject = NULL; - - /* Save this now because the FO might go away */ - OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ? - TRUE : FALSE; - - /* Clear the file object in the open packet */ - OpenPacket->FileObject = NULL; - - /* Dereference the file object */ - if (!UseDummyFile) ObDereferenceObject(FileObject); - - /* Dereference the device object */ - IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); - - /* Unless the driver cancelled the open, dereference the VPB */ - if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb); - - /* Set the status and return */ - OpenPacket->FinalStatus = Status; - return Status; - } - else if (Status == STATUS_REPARSE) - { - if (OpenPacket->Information == IO_REPARSE || - OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT) - { - /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */ - if (CompleteName->MaximumLength < FileObject->FileName.Length) - { - PWSTR NewCompleteName; - - /* Allocate a new buffer for the string */ - NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME); - if (NewCompleteName == NULL) + + /* Unless the driver cancelled the open, dereference the VPB */ + if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb); + + if (OpenPacket->Information != IO_REMOUNT) + { + OpenPacket->RelatedFileObject = NULL; + + /* Inform we traversed a mount point for later attempt */ + if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT) { - OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES; - return STATUS_INSUFFICIENT_RESOURCES; + OpenPacket->TraversedMountPoint = 1; }
- /* Release the old one */ - if (CompleteName->Buffer != NULL) + /* In case we override checks, but got this on volume open, fail hard */ + if (OpenPacket->Override) { - ExFreePoolWithTag(CompleteName->Buffer, TAG_IO_NAME); + KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN, + (ULONG_PTR)OriginalDeviceObject, + (ULONG_PTR)DeviceObject, + (ULONG_PTR)CompleteName, + OpenPacket->Information); }
- /* And setup the new one */ - CompleteName->Buffer = NewCompleteName; - CompleteName->MaximumLength = FileObject->FileName.Length; - } - - /* Copy our new complete name */ - RtlCopyUnicodeString(CompleteName, &FileObject->FileName); - - if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT) - { - OpenPacket->RelatedFileObject = NULL; - } - } - - /* Check if we have a name */ - if (FileObject->FileName.Length) - { - /* Free it */ - ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME); - FileObject->FileName.Length = 0; - } - - /* Clear its device object */ - FileObject->DeviceObject = NULL; - - /* Clear the file object in the open packet */ - OpenPacket->FileObject = NULL; - - /* Dereference the file object */ - if (!UseDummyFile) ObDereferenceObject(FileObject); - - /* Dereference the device object */ - IopDereferenceDeviceObject(OriginalDeviceObject, FALSE); - - /* Unless the driver cancelled the open, dereference the VPB */ - if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb); - - if (OpenPacket->Information != IO_REMOUNT) - { - OpenPacket->RelatedFileObject = NULL; - - /* Inform we traversed a mount point for later attempt */ - if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT) - { - OpenPacket->TraversedMountPoint = 1; - } - - /* In case we override checks, but got this on volume open, fail hard */ - if (OpenPacket->Override) - { - KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN, - (ULONG_PTR)OriginalDeviceObject, - (ULONG_PTR)DeviceObject, - (ULONG_PTR)CompleteName, - OpenPacket->Information); - } - - /* Return to IO/OB so that information can be upgraded */ - return STATUS_REPARSE; - } - - /* FIXME: At that point, we should loop again and reattempt an opening */ - ASSERT(FALSE); - } + /* Return to IO/OB so that information can be upgraded */ + return STATUS_REPARSE; + } + + /* Loop again and reattempt an opening */ + continue; + } + + break; + } + + if (Attempt == IOP_MAX_REPARSE_TRAVERSAL) + return STATUS_UNSUCCESSFUL;
/* Get the owner of the File Object */ OwnerDevice = IoGetRelatedDeviceObject(FileObject);