[NTOS:FSRTL] Respect byte-range lock ownership (#9342)

FsRtlCheckLockForReadAccess() accepts access through an exclusive
byte-range lock when the IRP key matches, even if another process
owns the lock. FsRtlFastUnlockAll() likewise removes exclusive locks
without checking the Process argument.

Require both the key and requestor process for exclusive-read access,
and skip exclusive locks owned by other processes in FsRtlFastUnlockAll().
This matches the ownership checks already used by
FsRtlFastCheckLockForRead() and FsRtlFastUnlockAllByKey().

Reference:
- https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-_fsrtl_advanced_fcb_header-fsrtlfastchecklockforread
This commit is contained in:
Ahmed Arif
2026-07-29 21:54:44 +03:00
committed by GitHub
parent 3da59bca94
commit c606fd79b1
2 changed files with 6 additions and 2 deletions
+5 -1
View File
@@ -676,6 +676,7 @@ FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock,
PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
COMBINED_LOCK_ELEMENT ToFind; COMBINED_LOCK_ELEMENT ToFind;
PCOMBINED_LOCK_ELEMENT Found; PCOMBINED_LOCK_ELEMENT Found;
PEPROCESS Process = IoGetRequestorProcess(Irp);
DPRINT("CheckLockForReadAccess(%wZ, Offset %08x%08x, Length %x)\n", DPRINT("CheckLockForReadAccess(%wZ, Offset %08x%08x, Length %x)\n",
&IoStack->FileObject->FileName, &IoStack->FileObject->FileName,
IoStack->Parameters.Read.ByteOffset.HighPart, IoStack->Parameters.Read.ByteOffset.HighPart,
@@ -697,7 +698,8 @@ FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock,
return TRUE; return TRUE;
} }
Result = !Found->Exclusive.FileLock.ExclusiveLock || Result = !Found->Exclusive.FileLock.ExclusiveLock ||
IoStack->Parameters.Read.Key == Found->Exclusive.FileLock.Key; (IoStack->Parameters.Read.Key == Found->Exclusive.FileLock.Key &&
Process == Found->Exclusive.FileLock.ProcessId);
DPRINT("CheckLockForReadAccess(%wZ) => %s\n", &IoStack->FileObject->FileName, Result ? "TRUE" : "FALSE"); DPRINT("CheckLockForReadAccess(%wZ) => %s\n", &IoStack->FileObject->FileName, Result ? "TRUE" : "FALSE");
return Result; return Result;
} }
@@ -1060,6 +1062,8 @@ FsRtlFastUnlockAll(IN PFILE_LOCK FileLock,
Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE)) Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE))
{ {
LARGE_INTEGER Length; LARGE_INTEGER Length;
if (Entry->Exclusive.FileLock.ProcessId != Process)
continue;
// We'll take the first one to be the list head, and free the others first... // We'll take the first one to be the list head, and free the others first...
Length.QuadPart = Length.QuadPart =
Entry->Exclusive.FileLock.EndingByte.QuadPart - Entry->Exclusive.FileLock.EndingByte.QuadPart -
+1 -1
View File
@@ -190,7 +190,7 @@ typedef struct _FILE_LOCK_INFO {
BOOLEAN ExclusiveLock; BOOLEAN ExclusiveLock;
ULONG Key; ULONG Key;
PFILE_OBJECT FileObject; PFILE_OBJECT FileObject;
PVOID ProcessId; PVOID ProcessId; /**< This field actually holds a pointer to EPROCESS structure */
LARGE_INTEGER EndingByte; LARGE_INTEGER EndingByte;
} FILE_LOCK_INFO, *PFILE_LOCK_INFO; } FILE_LOCK_INFO, *PFILE_LOCK_INFO;