Can't DeleteFile on NT Server

Subject: Help! DFS is bullying our file system driver!

Hello all!

I’m the guy who posted a message a while ago about our file system
driver not getting DeleteFile requests under Win2K Server. Well, I’ve
done some further investigation and found the cause of the problem,
although I’ll be darned if I can find a way to fix it! Any help in
solving this problem would be appreciated.

The root of the problem is the Distributed File System driver,
DFS.SYS. By default this driver only runs under Server, which
explains why we weren’t seeing the problem under Workstation. DFS is
a filter driver, so it attaches itself to our driver. It then
PREVENTS the DeleteFile request from ever making it to us! For some
reason, it intercepts it and just fails the request completely. What
right does it have to do that?!? Damn bully!!

Anyone who likes a challenge should read on…

More info:

Since DFS is a filter driver, one of the things it does is call
IoRegisterFsRegistrationChange() to register itself to receive
notification of new file system changes. In other words, whenever a
file system driver calls IoRegisterFileSystem(), the DFS driver is
called with a pointer to its DeviceObject.

Here’s what happens: Our file system driver starts up. DFS is
notified. It attaches itself as a filter driver to our driver. After
that, all seems fine: Requests are passed through to our driver
without problem. BUT!!! When a DeleteFile request comes in (that is,
IRP_MJ_SET_INFORMATION with FileInformationClass =
FileDispositionInformation) the request is immediately FAILED by DFS
with an error code of STATUS_INVALID_DEVICE_REQUEST. It never even
calls our driver!!

I’ve spent a bunch of time stepping through assembly code trying to
figure out why DFS is behaving this way and to see if there was
anything I could do to stop it. No solution is evident. I examined
it from two angles: Why DFS is attaching to our driver, and why DFS
is not passing the DeleteFile request through to our driver.

With respect to attaching:

From what I can tell, when DFS is informed that a file system driver
has started, all it does is confirm that the DeviceType is
FILE_DEVICE_DISK_FILE_SYSTEM, and then it attaches itself. No other
querying of the driver or anything.

Here is the callback typedef for receiving notification that a file
system driver has started, and the beginning code for DFS’s
implementation of this function:

VOID (*PDRIVER_FS_NOTIFICATION) ( IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN FsActive );

F887E470 MOV EAX,[ESP+04]
F887E474 CMP DWORD PTR [EAX+2C],08
F887E478 JNZ F887E48E (branch not taken)
F887E47A CMP BYTE PTR [ESP+08],00
F887E47F PUSH EAX
F887E480 JZ F887E489 (branch not taken)
F887E482 CALL F887E492
F887E487 JMP F887E48E
F887E489 CALL F887E516
F887E48E RET 0008
F887E491 INT 3
F887E492

There are no additional checks or querying after this point. Starting
at F887E492, the driver attaches to our device.

So as you can see, DFS simply checks the DeviceType (at F887E474) and
that the file system is starting not stopping (at F887E47A) and then
like a leech it attaches itself to the device. So there appears to be
no way to stop it from attaching to our driver, short of disabling
DFS.

With respect to receiving a DeleteFile request:

As mentioned, a DeleteFile request is done via IRP_MJ_SET_INFORMATION.
The DFS driver does something really weird here. It checks if the
DeviceType is 0x36, and if it’s not then it just fails the request
with a STATUS_INVALID_DEVICE_REQUEST error. Well of course the
DeviceType is not going to be 0x36 (anyone even know what that is?!?)
because the DeviceType is FILE_DEVICE_DISK_FILE_SYSTEM.

Here is the typedef for processing an IRP_MJ_SET_INFORMATION IRP, and
the code for DFS’s implementation of this function:

NTSTATUS (*PFS_SET_INFO_FUNC) ( PDEVICE_OBJECT pDeviceObject,
PIRP pIRP );

F8886CB2 MOV EAX,[ESP+04]
F8886CB6 PUSH ESI
F8886CB7 CMP DWORD PTR [EAX+2C],36
F8886CBB JNZ F8886CD1 (branch taken)
F8886CBD MOV AL,[EAX+000000E0]
F8886CC3 PUSH EAX
F8886CC4 PUSH DWORD PTR [ESP+10]
F8886CC8 CALL F8886CE8
F8886CCD MOV ESI,EAX
F8886CCF JMP F8886CE2
F8886CD1 MOV EAX,C0000010 ; STATUS_INVALID_DEVICE_REQUEST
F8886CD6 PUSH EAX
F8886CD7 MOV ESI,EAX
F8886CD9 PUSH DWORD PTR [ESP+10]
F8886CDD CALL F887E7C8
F8886CE2 MOV EAX,ESI
F8886CE4 POP ESI
F8886CE5 RET 0008

F887E7C8 MOV ECX,[ESP+04]
F887E7CC TEST ECX,ECX
F887E7CE JZ F887E7DF (branch not taken)
F887E7D0 MOV EAX,[ESP+08]
F887E7D4 MOV DL,01
F887E7D6 MOV [ECX+18],EAX
F887E7D9 CALL [@IofCompleteRequest]
F887E7DF RET 0008

As you can see, the IRP is immediately failed. There does not appear
to be anything we can do to stop DFS from failing this IRP.

So there you have it! Anyone have any thoughts!?!?? Any ideas!?!?!?

(Mucho thanks to everyone who has read this far!!!)

Alex Sheffield
Digital Processing Systems, Inc.
(http://www.dps.com)

> The DFS driver does something really weird here. It checks if the

DeviceType is 0x36, and if it’s not then it just fails the request
with a STATUS_INVALID_DEVICE_REQUEST error. Well of course the
DeviceType is not going to be 0x36 (anyone even know what that is?!?)
because the DeviceType is FILE_DEVICE_DISK_FILE_SYSTEM.

Why not set the DeviceType of your filter device to 0x36? Is it not a
workaround?

Max

Don’t know if this will help you much, but I found this definition for
0x36 in WinIoCtl.h:

#define FILE_DEVICE_DFS_VOLUME 0x00000036

Keegan O’Neill
Software Developer
Vanguard Victoria Labs

xxxxx@dps.com wrote:

Subject: Help! DFS is bullying our file system driver!

Hello all!

I’m the guy who posted a message a while ago about our file system
driver not getting DeleteFile requests under Win2K Server. Well, I’ve
done some further investigation and found the cause of the problem,
although I’ll be darned if I can find a way to fix it! Any help in
solving this problem would be appreciated.

The root of the problem is the Distributed File System driver,
DFS.SYS. By default this driver only runs under Server, which
explains why we weren’t seeing the problem under Workstation. DFS is
a filter driver, so it attaches itself to our driver. It then
PREVENTS the DeleteFile request from ever making it to us! For some
reason, it intercepts it and just fails the request completely. What
right does it have to do that?!? Damn bully!!

Anyone who likes a challenge should read on…

More info:

Since DFS is a filter driver, one of the things it does is call
IoRegisterFsRegistrationChange() to register itself to receive
notification of new file system changes. In other words, whenever a
file system driver calls IoRegisterFileSystem(), the DFS driver is
called with a pointer to its DeviceObject.

Here’s what happens: Our file system driver starts up. DFS is
notified. It attaches itself as a filter driver to our driver. After
that, all seems fine: Requests are passed through to our driver
without problem. BUT!!! When a DeleteFile request comes in (that is,
IRP_MJ_SET_INFORMATION with FileInformationClass =
FileDispositionInformation) the request is immediately FAILED by DFS
with an error code of STATUS_INVALID_DEVICE_REQUEST. It never even
calls our driver!!

I’ve spent a bunch of time stepping through assembly code trying to
figure out why DFS is behaving this way and to see if there was
anything I could do to stop it. No solution is evident. I examined
it from two angles: Why DFS is attaching to our driver, and why DFS
is not passing the DeleteFile request through to our driver.

With respect to attaching:

>From what I can tell, when DFS is informed that a file system driver
has started, all it does is confirm that the DeviceType is
FILE_DEVICE_DISK_FILE_SYSTEM, and then it attaches itself. No other
querying of the driver or anything.

Here is the callback typedef for receiving notification that a file
system driver has started, and the beginning code for DFS’s
implementation of this function:

VOID (*PDRIVER_FS_NOTIFICATION) ( IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN FsActive );

F887E470 MOV EAX,[ESP+04]
F887E474 CMP DWORD PTR [EAX+2C],08
F887E478 JNZ F887E48E (branch not taken)
F887E47A CMP BYTE PTR [ESP+08],00
F887E47F PUSH EAX
F887E480 JZ F887E489 (branch not taken)
F887E482 CALL F887E492
F887E487 JMP F887E48E
F887E489 CALL F887E516
F887E48E RET 0008
F887E491 INT 3
F887E492
>
> There are no additional checks or querying after this point. Starting
> at F887E492, the driver attaches to our device.
>
> So as you can see, DFS simply checks the DeviceType (at F887E474) and
> that the file system is starting not stopping (at F887E47A) and then
> like a leech it attaches itself to the device. So there appears to be
> no way to stop it from attaching to our driver, short of disabling
> DFS.
>
> With respect to receiving a DeleteFile request:
>
> As mentioned, a DeleteFile request is done via IRP_MJ_SET_INFORMATION.
> The DFS driver does something really weird here. It checks if the
> DeviceType is 0x36, and if it’s not then it just fails the request
> with a STATUS_INVALID_DEVICE_REQUEST error. Well of course the
> DeviceType is not going to be 0x36 (anyone even know what that is?!?)
> because the DeviceType is FILE_DEVICE_DISK_FILE_SYSTEM.
>
> Here is the typedef for processing an IRP_MJ_SET_INFORMATION IRP, and
> the code for DFS’s implementation of this function:
>
> NTSTATUS (*PFS_SET_INFO_FUNC) ( PDEVICE_OBJECT pDeviceObject,
> PIRP pIRP );
>
> F8886CB2 MOV EAX,[ESP+04]
> F8886CB6 PUSH ESI
> F8886CB7 CMP DWORD PTR [EAX+2C],36
> F8886CBB JNZ F8886CD1 (branch taken)
> F8886CBD MOV AL,[EAX+000000E0]
> F8886CC3 PUSH EAX
> F8886CC4 PUSH DWORD PTR [ESP+10]
> F8886CC8 CALL F8886CE8
> F8886CCD MOV ESI,EAX
> F8886CCF JMP F8886CE2
> F8886CD1 MOV EAX,C0000010 ; STATUS_INVALID_DEVICE_REQUEST
> F8886CD6 PUSH EAX
> F8886CD7 MOV ESI,EAX
> F8886CD9 PUSH DWORD PTR [ESP+10]
> F8886CDD CALL F887E7C8
> F8886CE2 MOV EAX,ESI
> F8886CE4 POP ESI
> F8886CE5 RET 0008
> …
> F887E7C8 MOV ECX,[ESP+04]
> F887E7CC TEST ECX,ECX
> F887E7CE JZ F887E7DF (branch not taken)
> F887E7D0 MOV EAX,[ESP+08]
> F887E7D4 MOV DL,01
> F887E7D6 MOV [ECX+18],EAX
> F887E7D9 CALL [@IofCompleteRequest]
> F887E7DF RET 0008
>
> As you can see, the IRP is immediately failed. There does not appear
> to be anything we can do to stop DFS from failing this IRP.
>
> So there you have it! Anyone have any thoughts!?!?? Any ideas!?!?!?
>
> (Mucho thanks to everyone who has read this far!!!)
>
> Alex Sheffield
> Digital Processing Systems, Inc.
> (http://www.dps.com)
>
> —
> You are currently subscribed to ntfsd as: xxxxx@s-s-g.com
> To unsubscribe send a blank email to $subst(‘Email.Unsub’)

Thanks, but I’m afraid that won’t work. We’re not a filter driver, we are
an actual file system driver. And as such, we have to return
FILE_DEVICE_DISK_FILE_SYSTEM because, well, that’s what we are!

Alex

“Maxim S. Shatskih”
Sent by: xxxxx@lists.osr.com
2000-11-27 06:43 PM
Please respond to “File Systems Developers”

To: “File Systems Developers”
cc:
Subject: [ntfsd] Re: Can’t DeleteFile on NT Server

> The DFS driver does something really weird here. It checks if the
> DeviceType is 0x36, and if it’s not then it just fails the request
> with a STATUS_INVALID_DEVICE_REQUEST error. Well of course the
> DeviceType is not going to be 0x36 (anyone even know what that is?!?)
> because the DeviceType is FILE_DEVICE_DISK_FILE_SYSTEM.

Why not set the DeviceType of your filter device to 0x36? Is it not a
workaround?

Max

Thanks. I actually found that myself a little while ago. Well, it
supports my theory that the DFS driver’s implementation is flawed. (I
know I know, it’s bad to blame the OS when something doesn’t work, but I
can’t see any way that it could not be a Microsoft bug.)

I think the reason no one else has seen this problem is that it only
affects file system drivers that start up AFTER the DFS kernel driver.
Once the DFS driver is active, it attaches itself to all devices of type
0x08 (file system driver) that start up after it, and then proceeds to
reject all SET_INFORMATION commands because, surprise, the device is not
what it expects (type 0x36, a DFS volume).

Anyone know the best way to report this to Microsoft?

Thanks,
Alex

Keegan O’Neill
Sent by: xxxxx@lists.osr.com
2000-11-29 01:18 PM
Please respond to “File Systems Developers”

To: “File Systems Developers”
cc:
Subject: [ntfsd] Re: Can’t DeleteFile on NT Server

Don’t know if this will help you much, but I found this definition for
0x36 in WinIoCtl.h:

#define FILE_DEVICE_DFS_VOLUME 0x00000036

Keegan O’Neill
Software Developer
Vanguard Victoria Labs