Repository navigation
DokanEventRelease re-entrancy race: double ExDeleteLookasideListEx / freed VCB access causes BSOD (0xA / 0x50) #1335
Description
Check List
- I checked my issue doesn't exist yet (searched for lookaside / ExDeleteLookasideListEx / DokanEventRelease / AV_dokan2; no matching report)
- My issue is valid with mirror default sample and not specific to my user-mode driver implementation (the race is in the driver's unmount path; it can be triggered from any FS implementation, including mirror, by concurrent unmount requests)
- I can always reproduce the issue with the provided description below (timing-dependent race — reproduction is probabilistic; Driver Verifier increases the chance)
- I have updated Dokany to the latest version and have reboot my computer after (2.3.1.1000 is the latest release)
- I tested one of the last snapshot from appveyor CI (not run; the faulty code is unchanged on master — see below)
Describe the bug
DokanEventRelease (sys/notification.c) has a non-atomic re-entry guard, leaving a race window between passing the guard and setting the unmount flags. If two threads enter concurrently for the same VCB, this leads to either a double ExDeleteLookasideListEx on the same list (0xA IRQL_NOT_LESS_OR_EQUAL), or a store into a VCB already freed by the thread that got ahead (0x50 PAGE_FAULT_IN_NONPAGED_AREA).
Observed under a workload where a user-mode FS process repeatedly mounts/unmounts (up to 8 concurrent mounts, 60 s request timeout): multiple BSODs, three times 0xA at dokan2+0x13cbc and once 0x50 at dokan2+0x144da, all in the same process on the same code path. Present in both v2.3.1.1000 and master (as of 2026-07-22).
To Reproduce
- Mount a volume (mirror is fine) with a short request timeout.
- Issue
DokanRemoveMountPointconcurrently from two threads against the same mount point — or race oneDokanRemoveMountPointagainst the timeout-triggered unmount (timeout.cDokanUnmount). - Repeat in a loop. Enabling Driver Verifier (special pool, force IRQL checking) on dokan2.sys makes the race easier to catch.
Expected behavior
Concurrent unmount/release requests for the same VCB are serialized: one performs the teardown, the others return cleanly. No BSOD.
Logs
BSOD minidump analysis. The 0xA dumps are identical (FAILURE_BUCKET_ID: AV_dokan2!unknown_function):
nt!KeBugCheckEx
nt!KiBugCheckDispatch
nt!KiPageFault
nt!ExpRemoveGeneralLookaside+0x21
nt!ExDeleteLookasideListEx+0x28
dokan2+0x13cbc
Symbol resolution with dokan2.pdb (private PDB) from the release asset dokan.zip — the installed dokan2.sys is SHA256-identical to x64/Release/Driver/dokan2.sys:
dokan2+0x13cbc=dokan2!DokanEventRelease+0x198(notification.c:380) — return address right after theExDeleteLookasideListEx(&vcb->FCBAvlNodeLookasideList)call at line 378dokan2+0x144da=dokan2!DokanStopFcbGarbageCollectorThread+0x36(notification.c:309) — theVcb->FcbGarbageCollectorThread = NULL;store, i.e. the 0x50 is a write to an already-freed VCB
DokanStopFcbGarbageCollectorThread is called from DokanEventRelease (line 374), so both crashes are inside the unmount path. Minidumps can be provided if needed.
Environment:
- Windows version: Windows 11 Pro build 26200
- Processor architecture: x64
- Dokany version: 2.3.1.1000 (dokan2.sys built 2025-09-28)
- Library type (Dokany/FUSE): Dokany
Additional context
Root cause in v2.3.1.1000's DokanEventRelease (sys/notification.c):
- The re-entry guards (line 336
IsDeletePending, line 341IsUnmountPendingVcb) are plain flag reads with no locking; check and set are not atomic. - The flags are only set at lines 358–359 (
SetLongFlag:VCB_DISMOUNT_PENDING/DCB_DELETE_PENDING), afterDokanDeleteMountPoint(line 355, which involves mount manager I/O). Two threads entering at about the same time both pass the guard and execute the whole teardown twice. FCBAvlNodeLookasideListInitis never cleared afterExDeleteLookasideListEx(lines 377–379; same at 385–387 on master), so nothing prevents re-entering the deleted list.
The 0xA is two threads running ExDeleteLookasideListEx on the same list concurrently — ExpRemoveGeneralLookaside then walks a corrupted list (ExDeleteLookasideListEx does not tolerate concurrent calls on the same list). The 0x50 is the trailing thread executing the line-309 store after the leading thread had already freed the VCB.
Entry points that can race for the same VCB:
DokanRemoveMountPoint→SendGlobalReleaseIRP→ FSCTL_EVENT_RELEASE →DokanGlobalEventRelease(fscontrol.c:430). Every call reaches the driver; no idempotency on the user-mode side.- Volume FSCTL (fscontrol.c:575)
- Timeout watcher thread →
DokanUnmount(timeout.c:32). The driver unmounts on its own when the request timeout fires. - MountManager link deletion (device.c:469/480)
- EventStart failure (event.c:1162)
For example, while a DokanRemoveMountPoint unmount is inside DokanDeleteMountPoint, the timeout thread (or a second DokanRemoveMountPoint) can pass the guard.
Suggested fix:
- Make the re-entry guard an interlocked test-and-set, and set the flags at the top of the function (before
IoAcquireRemoveLock) - Set
FCBAvlNodeLookasideListInit = FALSEbeforeExDeleteLookasideListEx - Make teardown steps such as
DokanStopFcbGarbageCollectorThreadidempotent and order them against VCB freeing
Activity
strvert commentedon Jul 22, 2026
Reproduced with Driver Verifier (
verifier /standard /driver dokan2.sys, reboot). The repro mounts mirror.exe, then fires 16 concurrentDokanRemoveMountPointcalls at the same mount point, in a loop. Crash within ~100 iterations.Crash 1 — the lookaside double-delete, same offset as the production 0xA dumps (dokan2+0x13cbc = DokanEventRelease+0x198):
Crash 2 — second concurrent release reading DCB fields torn down by the first:
Repro source (build:
cl /O2 repro_unmount_race.c, run with dokan2.dll on PATH):Details