Skip to content

Fix hibernation crash on fresh Windows 11 25H2 (BSOD Event 41)#1671

Open
audriusbuika wants to merge 1 commit intoveracrypt:masterfrom
audriusbuika:bugfix/windows11-hibernate-crash
Open

Fix hibernation crash on fresh Windows 11 25H2 (BSOD Event 41)#1671
audriusbuika wants to merge 1 commit intoveracrypt:masterfrom
audriusbuika:bugfix/windows11-hibernate-crash

Conversation

@audriusbuika
Copy link
Copy Markdown

solved problem: #1668

@idrassi
Copy link
Copy Markdown
Member

idrassi commented Apr 13, 2026

@audriusbuika
Thanks for working on this. I reviewed the patch, and the DumpFilter.c change looks like the core fix here.

Some remarks:

  1. The DriveFilter.c retry/sleep change should either be split out or tightened. I traced the local call path into this branch and DispatchPower is reached directly from the incoming IRP_MJ_POWER dispatch path. There is no worker-item handoff or local guarantee that this runs at PASSIVE_LEVEL. That matters because TCSleep uses KeDelayExecutionThread and requires IRQL <= APC_LEVEL. For hibernation-file device paths, Windows requires drivers to lock to run at PASSIVE_LEVEL.

  2. The bounded retry changes an important invariant in this path. STATUS_INSUFFICIENT_RESOURCES from SendDeviceIoControlRequest can mean the driver failed to allocate/queue/build the internal IOCTL request, not that AbortBootEncryptionSetup ran and failed. If all 50 attempts return STATUS_INSUFFICIENT_RESOURCES, the abort request may never have reached AbortBootEncryptionSetup, so EncryptionSetupThreadAbortRequested may remain false and the setup thread may still be active. That conflicts with the invariant already documented in DumpFilterWrite (EncryptedAreaEndUpdatePending -> "Hibernation should always abort the setup thread"). Please make the post-retry behavior preserve that invariant, for example by proving setup has actually stopped before continuing, or by handling/logging the failure path explicitly instead of silently proceeding as if the abort completed.

  3. The direct KeBugCheckEx call uses the same SECURITY_SYSTEM bugcheck code and argument convention as TC_BUG_CHECK. The only difference is that it puts writeMdl->MdlFlags in bugcheck parameter 3 instead of 0. That is useful diagnostically, but it does bypass the local TC_BUG_CHECK convention. This could either use TC_BUG_CHECK(STATUS_INVALID_PARAMETER) and drop the extra diagnostic value, or introduce a small TC_BUG_CHECK_EX(status, detail) helper.

Minor style note: the new comments contain Unicode punctuation (em-dash). Using ASCII hyphens/apostrophes would avoid GitHub's hidden/Unicode warning noise.

My recommendation would be to keep the DumpFilter.c MDL fix as the core bug fix but rework or split out the DispatchPower retry/sleep change until its IRQL assumptions and "setup stopped before hibernation" invariant are explicit.

Copy link
Copy Markdown
Member

@idrassi idrassi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DumpFilter.c MDL address selection looks like the right core fix for the hibernation crash. I am requesting changes because the DispatchPower retry/sleep change introduces separate power-path concerns: it may sleep without a local IRQL guarantee and the bounded retry can proceed without proving that boot encryption setup was actually aborted. Please either rework that part to preserve the existing hibernation/setup invariant safely, or split it out so the MDL fix can be reviewed independently.

while (retries-- > 0
&& SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES)
{
TCSleep (100);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid sleeping directly in this DispatchPower path unless the IRQL guarantee is explicit. This branch is reached directly from the incoming IRP_MJ_POWER dispatch path. I do not see a local worker-item handoff or other guarantee that it runs at PASSIVE_LEVEL. TCSleep wraps
KeDelayExecutionThread and requires IRQL <= APC_LEVEL. For hibernation-related power paths, the stack may have cleared DO_POWER_PAGABLE, so this needs either an explicit IRQL-safe implementation or a move to a path that is guaranteed to run at a waitable IRQL.

Comment on lines +972 to +973
while (retries-- > 0
&& SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bounded retry can leave boot encryption setup running. STATUS_INSUFFICIENT_RESOURCES from SendDeviceIoControlRequest() can be returned before the IOCTL reaches AbortBootEncryptionSetup() at all, for example if the work item or internal IOCTL IRP cannot be allocated. After 50 attempts this code falls through even though EncryptionSetupThreadAbortRequested may still be false and SetupInProgress may still be true. That conflicts with the invariant already documented in DumpFilterWrite that hibernation should always abort the setup thread before dump writes proceed. Please preserve that invariant by proving the setup thread has stopped before continuing, or make the failure path explicit instead of silently proceeding as if the abort completed.

// 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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small clarification: this comment says we must prefer MappedSystemVa when available, but the code below gives MDL_SOURCE_IS_NONPAGED_POOL precedence over MDL_MAPPED_TO_SYSTEM_VA. If that precedence is intentional, please adjust the comment so it matches the implementation. If MappedSystemVa should really win whenever MDL_MAPPED_TO_SYSTEM_VA is set, the checks should be reordered.

@idrassi idrassi self-assigned this Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants