Object manager refusing to reparse

Hi Folks,

I’m writing a classic cross-volume file system mini-filter driver that redirects all I/O requests from one volume (C:) to another (say, X:). I achieve this by using the famous reparse approach i.e.

// Change filename in Data->Iopb->TargetFileObject using IoReplaceFileObjectName
// So e.g. replacing L"\??\Volume{dd9d0273-0000-0000-0000-602200000000}\Users\Admin" with L"\??\Volume{e53ce0d4-0000-0000-0000-100000000000}\Users\Admin"
Data->IoStatus.Information = IO_REPARSE;
Data->IoStatus.Status = STATUS_REPARSE;
Data->Iopb->TargetFileObject->RelatedFileObject = NULL;
FltSetCallbackDataDirty(Data);
return FLT_PREOP_COMPLETE;

This seems to be working fine until I launch Microsoft edge. The browser gets launched but it fails to load home page contents, suggestions etc.
After putting in long debugging / investigation hours here’s what I see in the Procmon:

MicrosoftEdgeCP.exe (FAILURE LOGS)

MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Open Reparse Point, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Superseded
MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Open Reparse Point, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Superseded
MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Open Reparse Point, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Superseded
MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Open Reparse Point, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Superseded
MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Open Reparse Point, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Superseded

MicrosoftEdge.exe (SUCCESS LOGS)

MicrosoftEdge.exe CreateFile C:\Users\Admin REPARSE Desired Access: Read Attributes, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Open Reparse Point, Disallow Exclusive, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Superseded
MicrosoftEdge.exe CreateFile X:\Users\Admin SUCCESS Desired Access: Read Attributes, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Open Reparse Point, Disallow Exclusive, Attributes: N, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
MicrosoftEdge.exe CloseFile X:\Users\Admin SUCCESS
MicrosoftEdge.exe CreateFile C:\Users\Admin REPARSE Desired Access: Read Attributes, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Attributes: n/a, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Superseded
MicrosoftEdge.exe CreateFile X:\Users\Admin SUCCESS Desired Access: Read Attributes, Synchronize, Disposition: Open, Options: Synchronous IO Non-Alert, Attributes: n/a, ShareMode: Read, Write, AllocationSize: n/a, OpenResult: Opened
MicrosoftEdge.exe CloseFile X:\Users\Admin SUCCESS

In the Procmon, there’s simply no entry corresponding to IRP_MJ_CREATE for X:\Users\Admin for EdgeCP.exe whereas that’s not the case with Edge.exe.
Its literally like IO manager / object manager has not re-issued a new IRP_MJ_CREATE for the new filename.

So what are those mysterious circumstances during which IO manager / object manager decides to do this.

Thanks

Any idea guys why reparse might be failing? I’m not making changes anywhere apart from the filename in the target file object. Thanks

Here’s the simplified version of procmon logs with my fs redirection mini-filter loaded:

MicrosoftEdgeCP.exe (FAILURE LOGS)

MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE
MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE
MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE
MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE
MicrosoftEdgeCP.exe CreateFile C:\Users\Admin REPARSE

MicrosoftEdge.exe (SUCCESS LOGS)

MicrosoftEdge.exe CreateFile C:\Users\Admin REPARSE
MicrosoftEdge.exe CreateFile X:\Users\Admin SUCCESS
MicrosoftEdge.exe CloseFile X:\Users\Admin SUCCESS
MicrosoftEdge.exe CreateFile C:\Users\Admin REPARSE
MicrosoftEdge.exe CreateFile X:\Users\Admin SUCCESS
MicrosoftEdge.exe CloseFile X:\Users\Admin SUCCESS

During the debugging session, I debugged the call stack backwards meaning I put the break-point wherein I receive the original Create request and change its IoStatus.Status to STATUS_REPARSE and then executed 1 instruction at a time. I can see that in the stack, Filter manager’s PerformPreCallback is never called again for the corresponding new Create request.

Does anyone have any insights on this?

Thanks in advance.

Does anyone have any insights on this
No, but you might want to set a break on read access breakpoint in Iosb->Status

Thanks rod_widdowson for getting back.

@rod_widdowson said:

Does anyone have any insights on this
No, but you might want to set a break on read access breakpoint in Iosb->Status

Can you please elaborate a bit more on this?

When you have set STATUS_REPARSE, find the address and do a ba r 4 <Address>

Windbg will then stop every time that (virtual) address is accessed. That might be a faster way to detect when the working flow diverges from the failing one and thus work out whats happening and why…

Just a thought tho’