Attaching to volmgr's device but still not receiving read/write IRPs?

Previously we used UpperFilter of volume class in order to attach to the volume manager devices in order to monitor read/write IRPs.

Now I have changed it so we wouldn't need to be UpperFilter (Volume Class) and I manually attach to Volume Manager devices (only those that are needed) by enuming its devices and attaching to them manually (instead of relying on AddDevice), then I call our old AddDevice function manually, and pass the target device object as the second argument.

But weirdly, I notice that when I attach to them manually, I don't receive any IRP, even tho using !devstack crealy shows we are on top of the device stack!

I haven't changed to logic of attaching to the device, right now we just OR the filter device object's flags with the lower device object flags & (DO_DIRECT_IO | DO_BUFFERED_IO | DO_POWER_PAGABLE), we also do a &= ~DO_DEVICE_INITIALIZING on the filter device object's flags.

Then I compared the device object of our filter device, in the two case of using UpperFilter vs Manually Attaching, to see if they are any different, and I found out that, in case of Manual Attach:

  1. ReferenceCount is 0 (Manual), vs 775 (UpperFilter)
  2. Size of the device object is 0x190 (Manual), vs 0x320 (UpperFilter)
  3. Flags is 0x10 (Manual), vs 0x1150 (UpperFilter)
  4. Charachteristics is 0x100 (Manual), vs 0x60000 (UpperFilter)
  5. StackSize is 10 (Manual), vs 5 (UpperFilter)

My question is, why are these differences happening, even tho the logic of the attaching of manual vs upperfilter's add device is not different in my code?

Do I need to do some extra work in case I am manually finding the device and attaching, vs the case we are UpperFilter? If so, what more do I need to do in my attach funciton? Currently my attach function is exactly the same as the AddDevice function, I just manually call it and pass the target device object as the second argument.

Never mind the size differences, if you attach to the top of a device stack AFTER other drivers, such as filesystems, have obtained a pointer to the top of the stack, you are not filtering anything. You might get lucky and have a FSD get it's pointer after you, but really this is the wrong approach.

1 Like

So what is the proper way of filtering volmgr devices for read/writes, without using UpperFilter? I can't use minifilter because I need to monitor sector write IRPs.

Also, I did manage to attach to \Driver\Disk devices (the boot device in particular) fine with the same method and monitor read/write IRPs to sectors, without needing to do UpperFilter, but your answer made me question this as well, even tho right now it's working, is this also a correct approach?

Basically, I need to monitor write IRPs to sectors (Starting sectors) of a device of \Driver\Volmgr and also a device of \Driver\Disk, the volmgr device is for the boot partition (for example C:) and the disk device is the boot disk device. What is the correct way of attaching/intercepting write IRPs to these two devices, for protecting certain sectors from writes?

One very strange thing I noticed, is that when I manually attach to \device\harddiskX\dr0

my IRP_MJ_WRITE callback does get invoked, but for starting sectors only, before the 2048th sector (start of the volume, NTFS for example). But when my driver attaches to this disk using UpperFilter (DiskDrive) + AddDevice, it gets called for every sector write? it doesnt even make any sense.. why?!!! Is there anyway that I can also monitor writes to starting sectors of volume (2048 and 2049 for example) without using a DiskDrive or Volume UpperFilter?

More findings:

At least when I attach on top of the filesystem stack for the \device\harddiskvolumeX, meaning on top of the \device\ntfs stack, I at least do get IRP_FILE_WRITE IRPs, but as expected the problem is that the Write.ByteOffset is the offset of the file, not offset in the harddisk (nor volume offset)

So in order to detect writes to the starting sector of the volume, I came up with the following check:

	LARGE_INTEGER byteOffset = stack->Parameters.Write.ByteOffset;
	ULONG sectorNumber = (ULONG)(byteOffset.QuadPart / 512);

	if (sectorNumber == 0
		&& Length == 512
		&& stack->FileObject 
		&& ( stack->FileObject->Flags & FO_VOLUME_OPEN )
		&& stack->FileObject->FileName.Length == 0 
		&& stack->FileObject->WriteAccess
		&& stack->FileObject->RelatedFileObject == NULL
	    && (ULONG)PsGetCurrentProcessId() > 4)

It seems to be working, but I don't like it.
So I am again asking experts here that is there a better approach than this, and other than using UpperFilter? I just want to monitor writes to the starting sectors of the volume..

I tried to attach during DriverEntry (boot driver), in IoRegisterFsRegistrationChange callback, in IoRegisterBootDriverReinitialization callback, etc, tried to add Depend of volmgr or disk in my service, but non of them worked, they are either seem to be too early for attaching, or too "late" so I still don't get IRP_MJ_WRITE for the volume. And by manually attaching to \Driver\Disk I do get IRP_MJ_WRITEs, but only for the starting 2047 sectors right before the volume.. this doesn't make any sense..