From 0fddeef592744f92b9d617f78333164c16eefa22 Mon Sep 17 00:00:00 2001 From: Audrius Buika Date: Sun, 12 Apr 2026 19:20:21 +0300 Subject: [PATCH] Fix hibernation crash on fresh Windows 11 25H2 (BSOD Event 41) --- src/Driver/DriveFilter.c | 31 ++++++++++++++++++++++++------- src/Driver/DumpFilter.c | 23 +++++++++++++++++++---- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/Driver/DriveFilter.c b/src/Driver/DriveFilter.c index 93ee34cbb3..b572df4cf9 100644 --- a/src/Driver/DriveFilter.c +++ b/src/Driver/DriveFilter.c @@ -52,10 +52,6 @@ static uint8 BootLoaderFingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE]; static BOOL CrashDumpEnabled = FALSE; static BOOL HibernationEnabled = FALSE; -static BOOL LegacyHibernationDriverFilterActive = FALSE; -static uint8 *HibernationWriteBuffer = NULL; -static MDL *HibernationWriteBufferMdl = NULL; - static uint32 HibernationPreventionCount = 0; static BootEncryptionSetupRequest SetupRequest; @@ -972,7 +968,12 @@ static NTSTATUS DispatchPower (PDEVICE_OBJECT DeviceObject, PIRP Irp, DriveFilte && irpSp->MinorFunction == IRP_MN_SET_POWER && irpSp->Parameters.Power.ShutdownType == PowerActionHibernate) { - while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES); + int retries = 50; + while (retries-- > 0 + && SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES) + { + TCSleep (100); + } } // Dismount the system drive on shutdown on Windows 7 and later @@ -1208,7 +1209,21 @@ void ReopenBootVolumeHeader (PIRP irp) } -// Legacy Windows XP/2003 hibernation dump filter +/* + * Legacy Windows XP/2003 hibernation dump filter. + * + * DISABLED: This code is not active — LoadImageNotifyRoutine was never + * registered via PsSetLoadImageNotifyRoutine, so none of these functions + * are reachable at runtime. Additionally the code has known issues: + * - HibernationWriteBuffer / HibernationWriteBufferMdl are never allocated + * (NULL dereference if reached) + * - MmInitializeMdl is called in a context that may run at HIGH_LEVEL + * - dataMdl->MappedSystemVa is accessed without checking MDL flags + * + * Kept behind #if 0 for historical reference. The modern hibernation + * encryption path is in DumpFilter.c (Vista+ dump filter API). + */ +#if 0 typedef NTSTATUS (*HiberDriverWriteFunctionA) (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3); typedef NTSTATUS (*HiberDriverWriteFunctionB) (PLARGE_INTEGER writeOffset, PMDL dataMdl); @@ -1300,7 +1315,7 @@ static NTSTATUS HiberDriverWriteFunctionFilter (int filterNumber, PLARGE_INTEGER if (writeB) return (*OriginalHiberDriverWriteFunctionsB[filterNumber]) (writeOffset, encryptedDataMdl); - + return (*OriginalHiberDriverWriteFunctionsA[filterNumber]) (arg0WriteA, writeOffset, encryptedDataMdl, arg3WriteA); } @@ -1475,6 +1490,8 @@ static VOID LoadImageNotifyRoutine (PUNICODE_STRING fullImageName, HANDLE proces KeLowerIrql (origIrql); } +#endif /* Legacy XP/2003 hibernation filter */ + static VOID SetupThreadProc (PVOID threadArg) { diff --git a/src/Driver/DumpFilter.c b/src/Driver/DumpFilter.c index 2631b6b8b1..44ea4e4357 100644 --- a/src/Driver/DumpFilter.c +++ b/src/Driver/DumpFilter.c @@ -266,11 +266,26 @@ static NTSTATUS DumpFilterWrite (PFILTER_EXTENSION filterExtension, PLARGE_INTEG if ((offset & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0) TC_BUG_CHECK (STATUS_INVALID_PARAMETER); - // Require either a valid mapping or a nonpaged system VA we can read at HIGH_LEVEL. - if ((writeMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL)) == 0) - TC_BUG_CHECK(STATUS_INVALID_PARAMETER); + // Resolve the system VA we can safely read at HIGH_LEVEL. + // MDL_SOURCE_IS_NONPAGED_POOL: original VA (StartVa + ByteOffset) is a kernel VA. + // MDL_MAPPED_TO_SYSTEM_VA: MappedSystemVa is the correct kernel VA (StartVa + // may point elsewhere, e.g. user-mode or stale VA). + // Windows 11 25H2+ dump stacks may provide mapped MDLs that are NOT from nonpaged + // pool, so we must prefer MappedSystemVa when available. + if (writeMdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) + { + writeBuffer = MmGetMdlVirtualAddress (writeMdl); + } + else if (writeMdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) + { + writeBuffer = writeMdl->MappedSystemVa; + } + else + { + // Unrecognized MDL type — include MdlFlags in bugcheck param3 for diagnosis. + KeBugCheckEx (SECURITY_SYSTEM, __LINE__, (ULONG_PTR) STATUS_INVALID_PARAMETER, (ULONG_PTR) writeMdl->MdlFlags, 'VC'); + } - writeBuffer = MmGetMdlVirtualAddress (writeMdl); if (!writeBuffer) TC_BUG_CHECK (STATUS_INVALID_PARAMETER);