[NTOS:IO] Implement IopAcquireFileObjectLock and use it to fix IopLockFileObject

This commit is contained in:
Thomas Faber 2018-10-02 09:55:07 +02:00 committed by Pierre Schweitzer
parent c6142174af
commit 8fbc488050
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
4 changed files with 167 additions and 25 deletions

View file

@ -1238,6 +1238,15 @@ IopCloseFile(
IN ULONG SystemHandleCount
);
NTSTATUS
NTAPI
IopAcquireFileObjectLock(
_In_ PFILE_OBJECT FileObject,
_In_ KPROCESSOR_MODE AccessMode,
_In_ BOOLEAN Alertable,
_Out_ PBOOLEAN LockFailed
);
PVOID
NTAPI
IoGetFileObjectFilterContext(

View file

@ -8,16 +8,26 @@
static
__inline
VOID
IopLockFileObject(IN PFILE_OBJECT FileObject)
NTSTATUS
IopLockFileObject(
_In_ PFILE_OBJECT FileObject,
_In_ KPROCESSOR_MODE WaitMode)
{
BOOLEAN LockFailed;
/* Lock the FO and check for contention */
InterlockedIncrement((PLONG)&FileObject->Waiters);
while (InterlockedCompareExchange((PLONG)&FileObject->Busy, TRUE, FALSE) != FALSE)
if (InterlockedExchange((PLONG)&FileObject->Busy, TRUE) == FALSE)
{
/* FIXME - pause for a little while? */
ObReferenceObject(FileObject);
return STATUS_SUCCESS;
}
else
{
return IopAcquireFileObjectLock(FileObject,
WaitMode,
BooleanFlagOn(FileObject->Flags, FO_ALERTABLE_IO),
&LockFailed);
}
InterlockedDecrement((PLONG)&FileObject->Waiters);
}
static
@ -26,8 +36,12 @@ VOID
IopUnlockFileObject(IN PFILE_OBJECT FileObject)
{
/* Unlock the FO and wake any waiters up */
InterlockedExchange((PLONG)&FileObject->Busy, FALSE);
if (FileObject->Waiters) KeSetEvent(&FileObject->Lock, 0, FALSE);
NT_VERIFY(InterlockedExchange((PLONG)&FileObject->Busy, FALSE) == TRUE);
if (FileObject->Waiters)
{
KeSetEvent(&FileObject->Lock, IO_NO_INCREMENT, FALSE);
}
ObDereferenceObject(FileObject);
}
FORCEINLINE

View file

@ -1729,7 +1729,12 @@ IopGetSetSecurityObject(IN PVOID ObjectBody,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock the file object */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, ExGetPreviousMode());
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(FileObject);
return Status;
}
}
else
{
@ -2026,7 +2031,7 @@ IopCloseFile(IN PEPROCESS Process OPTIONAL,
/* Check if this is a sync FO and lock it */
if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
{
IopLockFileObject(FileObject);
(VOID)IopLockFileObject(FileObject, KernelMode);
}
/* Go the FastIO path if possible, otherwise fall back to IRP */
@ -2100,7 +2105,7 @@ IopCloseFile(IN PEPROCESS Process OPTIONAL,
if (Process != NULL &&
BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
{
IopLockFileObject(FileObject);
(VOID)IopLockFileObject(FileObject, KernelMode);
}
/* Clear and set up Events */
@ -2259,6 +2264,52 @@ IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
return Status;
}
NTSTATUS
NTAPI
IopAcquireFileObjectLock(
_In_ PFILE_OBJECT FileObject,
_In_ KPROCESSOR_MODE WaitMode,
_In_ BOOLEAN Alertable,
_Out_ PBOOLEAN LockFailed)
{
NTSTATUS Status;
PAGED_CODE();
InterlockedIncrement((PLONG)&FileObject->Waiters);
Status = STATUS_SUCCESS;
do
{
if (!InterlockedExchange((PLONG)&FileObject->Busy, TRUE))
{
break;
}
Status = KeWaitForSingleObject(&FileObject->Lock,
Executive,
WaitMode,
Alertable,
NULL);
} while (Status == STATUS_SUCCESS);
InterlockedDecrement((PLONG)&FileObject->Waiters);
if (Status == STATUS_SUCCESS)
{
ObReferenceObject(FileObject);
*LockFailed = FALSE;
}
else
{
if (!FileObject->Busy && FileObject->Waiters)
{
KeSetEvent(&FileObject->Lock, IO_NO_INCREMENT, FALSE);
}
*LockFailed = TRUE;
}
return Status;
}
PVOID
NTAPI
IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)

View file

@ -334,7 +334,13 @@ IopDeviceFsIoControl(IN HANDLE DeviceHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
if (EventObject) ObDereferenceObject(EventObject);
ObDereferenceObject(FileObject);
return Status;
}
/* Remember to unlock later */
LockedForSynch = TRUE;
@ -666,7 +672,7 @@ IopQueryDeviceInformation(IN PFILE_OBJECT FileObject,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
(void)IopLockFileObject(FileObject, KernelMode);
/* Use File Object event */
KeClearEvent(&FileObject->Event);
@ -1221,7 +1227,7 @@ IoSetInformation(IN PFILE_OBJECT FileObject,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
(void)IopLockFileObject(FileObject, KernelMode);
/* Use File Object event */
KeClearEvent(&FileObject->Event);
@ -1431,7 +1437,12 @@ NtFlushBuffersFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(FileObject);
return Status;
}
}
else
{
@ -1579,7 +1590,13 @@ NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
if (Event) ObDereferenceObject(Event);
ObDereferenceObject(FileObject);
return Status;
}
LockedForSync = TRUE;
}
@ -1779,7 +1796,13 @@ NtLockFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
if (Event) ObDereferenceObject(Event);
ObDereferenceObject(FileObject);
return Status;
}
LockedForSync = TRUE;
}
@ -1972,7 +1995,14 @@ NtQueryDirectoryFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
if (Event) ObDereferenceObject(Event);
ObDereferenceObject(FileObject);
if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
return Status;
}
/* Remember to unlock later */
LockedForSynch = TRUE;
@ -2207,7 +2237,12 @@ NtQueryInformationFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(FileObject);
return Status;
}
/* Check if the caller just wants the position */
if (FileInformationClass == FilePositionInformation)
@ -2619,7 +2654,13 @@ NtReadFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock the file object */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
if (EventObject) ObDereferenceObject(EventObject);
ObDereferenceObject(FileObject);
return Status;
}
/* Check if we don't have a byte offset available */
if (!(ByteOffset) ||
@ -2961,7 +3002,12 @@ NtSetInformationFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(FileObject);
return Status;
}
/* Check if the caller just wants the position */
if (FileInformationClass == FilePositionInformation)
@ -3411,7 +3457,12 @@ NtUnlockFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(FileObject);
return Status;
}
}
else
{
@ -3616,7 +3667,13 @@ NtWriteFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock the file object */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
if (EventObject) ObDereferenceObject(EventObject);
ObDereferenceObject(FileObject);
return Status;
}
/* Check if we don't have a byte offset available */
if (!(ByteOffset) ||
@ -3897,7 +3954,12 @@ NtQueryVolumeInformationFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(FileObject);
return Status;
}
}
else
{
@ -4068,7 +4130,13 @@ NtSetVolumeInformationFile(IN HANDLE FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
IopLockFileObject(FileObject);
Status = IopLockFileObject(FileObject, PreviousMode);
if (Status != STATUS_SUCCESS)
{
ObDereferenceObject(FileObject);
if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
return Status;
}
}
else
{