Windows System Software -- Consulting, Training, Development -- Engineering Excellent, Every Time.

NTFS Status Debugging

NTFS Status Debugging

As a file system filter developer, one of the great pains in life is when a file system operation fails deep in the bowels of the file system. For example, say I’m trying to rename a file with FltSetInformationFile for FileRenameInformation and I get back STATUS_ACCESS_DENIED. How do I track that down? Sure, I could try single stepping through the function until I see a STATUS_ACCESS_DENIED, but that could take quite a while. Even worse, if the file system is NTFS I will undoubtedly end up stepping into some other thread and losing the thread context of my failing rename.

Enter NTSTATUS debugging! Since at least Windows 7, NTFS has had a handy undocumented feature that can cause a breakpoint when NTFS is about to return a particular NTSTATUS. Prior to Windows 10 you enable this feature using the following WinDbg command:

eb Ntfs!NtfsStatusDebugEnabled 1

On Windows 10 and later you enable this feature using a different command:

ed Ntfs!NtfsStatusDebugFlags 2

Now you’re ready to set the status that you want to break on. You do that with the following:

ed Ntfs!NtfsStatusBreakOnStatus 0xc0000022

Where the supplied value is whatever NTSTATUS value you want to break on in the debugger. Once NTFS is about to return that particular value from any internal function, you’ll hit a breakpoint:

Assertion failure - code c0000420 (first chance)
Ntfs!NtfsStatusTraceAndDebugInternal+0x20c:
fffff801`3640e0f4 int 2Ch
kd> k
Child-SP RetAddr Call Site
fffffe0f`cf03d550 fffff801`36494b5a Ntfs!NtfsStatusTraceAndDebugInternal+0x20c
fffffe0f`cf03d5a0 fffff801`364962b1 Ntfs!TxfAccessCheck+0x2da
fffffe0f`cf03d700 fffff801`36495cd1 Ntfs!NtfsAccessCheck+0x281
fffffe0f`cf03d930 fffff801`364959ea Ntfs!NtfsCheckExistingFile+0xd1
fffffe0f`cf03d9d0 fffff801`3649502c Ntfs!NtfsOpenExistingAttr+0xda
fffffe0f`cf03da90 fffff801`364939ed Ntfs!NtfsOpenAttributeInExistingFile+0x3dc
fffffe0f`cf03dc40 fffff801`364ebfb4 Ntfs!NtfsOpenExistingPrefixFcb+0x1ed
fffffe0f`cf03dd20 fffff801`364ec4bb Ntfs!NtfsFindStartingNode+0xcc4

Of course, lacking source code to NTFS this doesn’t exactly tell you why the error is being returned, but it at least gives you a place to start. Usually at this point I begin setting breakpoints farther and farther up the call stack until I can figure out where the working and non-working cases diverge (hey, no one ever said this was a glamorous job).

Note that this functionality is not in FAT, though at least with FAT you can (mostly) just look at the public version of the sources and figure out the possible reasons for the failure.