diff --git a/drivers/filesystems/udfs/protos.h b/drivers/filesystems/udfs/protos.h index acaa3cd52b8b4..534c471d1491a 100644 --- a/drivers/filesystems/udfs/protos.h +++ b/drivers/filesystems/udfs/protos.h @@ -1380,6 +1380,9 @@ UDFAcquireResource( #define UDFAcquirePagingIoExclusive(IC,F) \ UDFAcquireResource((IC), (F)->Header.PagingIoResource, FALSE, AcquireExclusive) +#define UDFAcquirePagingIoShared(IC,F) \ + UDFAcquireResource((IC), (F)->Header.PagingIoResource, FALSE, AcquireShared) + #define UDFReleasePagingIo(IC,F) \ ExReleaseResourceLite((F)->Header.PagingIoResource) diff --git a/drivers/filesystems/udfs/read.cpp b/drivers/filesystems/udfs/read.cpp index c920331dee579..4899338ee175a 100644 --- a/drivers/filesystems/udfs/read.cpp +++ b/drivers/filesystems/udfs/read.cpp @@ -66,6 +66,7 @@ UDFCommonRead( PVCB Vcb = NULL; BOOLEAN VcbAcquired = FALSE; BOOLEAN FcbAcquired = FALSE; + BOOLEAN PagingIoResourceAcquired = FALSE; PVOID SystemBuffer = NULL; BOOLEAN Wait; @@ -157,6 +158,11 @@ UDFCommonRead( UDFAcquireFcbSharedStarveExclusive(IrpContext, Fcb, FALSE); FcbAcquired = TRUE; + // Acquire PagingIo resource shared to serialize with writes that hold + // it exclusively while modifying the extent mapping (UDFResizeExtent). + // This prevents a use-after-free when iterating DataLoc.Mapping. + UDFAcquirePagingIoShared(IrpContext, Fcb); + PagingIoResourceAcquired = TRUE; } else { @@ -406,6 +412,9 @@ try_exit: NOTHING; } _SEH2_FINALLY { + if (PagingIoResourceAcquired) { + UDFReleasePagingIo(IrpContext, Fcb); + } if (FcbAcquired) { UDFReleaseFcb(IrpContext, Fcb); diff --git a/drivers/filesystems/udfs/write.cpp b/drivers/filesystems/udfs/write.cpp index 076e5a6cbe305..1cd6cfca18675 100644 --- a/drivers/filesystems/udfs/write.cpp +++ b/drivers/filesystems/udfs/write.cpp @@ -428,8 +428,15 @@ UDFCommonWrite( } } - UDFReleasePagingIo(IrpContext, Fcb); - PagingIoResourceAcquired = FALSE; + // For cached I/O, release now so that CcCopyWrite-triggered + // paging reads (which acquire PagingIoResource shared) do + // not deadlock against our exclusive hold. + // For non-cached I/O, keep it held through UDFWriteFile__ to + // protect against concurrent paging reads seeing a freed mapping. + if (!NonCachedIo) { + UDFReleasePagingIo(IrpContext, Fcb); + PagingIoResourceAcquired = FALSE; + } if (CcIsFileCached(FileObject)) { if (ExtendFS) {