How to filter all disk requests using a filter driver?

Hi, I have a disk filter driver (This is a lower filter driver for disk.sys and without any other filter drivers in the system sits about storahci.sys or other Storport drivers).

The disk filter driver implements IRP_MJ_SCSI and also IOCTL_SCSI_PASS_THROUGH_DIRECT and IOCTL_SCSI_PASS_THROUGH_DIRECT_EX in the IRP_MJ_DEVICE_CONTROL.

Even with these, on certain systems, my filter driver is not seeing all requests. Or at least I think I am missing some requests.
For example, if I put a breakpoint on the underlying Storport’s read/write routines, those breakpoints hit and my driver is not on the call stack.

This is Windows 10 1903 if it matters.

How do I guarantee that all disk accesses are routed through my filter driver?. i though implementing IRP_MJ_SCSI and the above were enough.

Thanks,
RK

if I put a breakpoint on the underlying Storport’s read/write routines, those breakpoints hit and my driver is not on the call stack.

But you do see disk.sys?? Please be explicit.

What is different about these requests that show-up in Storport but do not include your driver? Look at the disk.sys FDO and its associated Dev Node. Are you in that dev node?

There aren’t really any “tricks” at this level of the storage stack… If you’re always a lower filter of disk.sys, you should see all the IRPs that disk.sys sends to the PDOs over which you are instantiated.

This really should just be a matter of looking at how the system is configured and seeing where you area…

Peter

Peter, thanks. Let me check to see that disk.sys is on the call stack even when my driver is not. I agree that if disk.sys is there and I am always a lower filter of disk.sys (which I am) then I should see all the IRPs.

I will check again and get back to this newsgroup.

Thanks,
Ram

I wanted to provide an update. I was mistaken on what I was seeing on the stack.

My driver is being called at IRP_MJ_DEVICE_CONTROL with IOCTL_SCSI_PASS_THROUGH_DIRECT but now I have a new problem.

a) My filter driver needs to handle disk reads in a particular manner.
So my driver filters out read operation code from the CDB. But the CDB operation code is always 0.
I was hoping that it would be SCSI reads of various types 6-byte, 12 byte 16 byte.
But it is always 0.

The system has 2 drives, one boot drive and one data drive.

For the controller that has the boot drive plugged to it, my filter driver never gets called at the above ioctl codes. Instead it only gets called at IRP_MJ_SCSI. Boot drives are treated specially by the driver and no processing is performed on boot drives

for the controller that has the data plugged in, initial SCSI operations are sent synchronously via the IRP_MJ_SCSI handler and then they are sent using the above ioctl codes (SCSI_PASS_THROUGH_DIRECT and SCSI_PASS_THROUGH).

Here is my processing for SCSI_PASS_THROUGH_DIRECT and SCSI_PASS_THROUGH IRP
I flag reads only if the CDB operation code matches one of the following values
8, 0x88, 0x28, 0xA8 (for various SCSI lengths).
These IRPs are treated specially by my driver. Everything else is just passed through

I did notice that sometimes I get 0xA1 operation code. This is a ATA_PASSTHROUGH operation code. What is the meaning of this operation code?. Otherwise I am getting 0 operation code all the time.

The reads and writes are happening just fine.

For now if the IRP is issued by a 32-bit process, I wanted to catch that to see if I was not handling that. I am never hitting this breakpoint.

Also, what dictates whether the disk driver uses IRP_MJ_SCSI or SCSI_PASS_THROUGH/SCSI_PASS_THROUGH_DIRECT to send CDB commands to the Storport driver?. is it some combination of Flags in the device Object of the underlying controller driver.

==========================================================Code==========================================

	case IOCTL_SCSI_PASS_THROUGH:
	case IOCTL_SCSI_PASS_THROUGH_DIRECT:

		if (IoIs32bitProcess(Irp)) {
			__debugbreak();
		}
			PUCHAR pDataBuffer = nullptr;
			PCDB pcdb = nullptr;
			ULONG dataTransferLength = 0;
			UCHAR dataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
			if (fcn == IOCTL_SCSI_PASS_THROUGH)
			{
				if (stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)) 
					break;

				PSCSI_PASS_THROUGH pPT = static_cast<PSCSI_PASS_THROUGH>(Irp->AssociatedIrp.SystemBuffer);
				pDataBuffer = (PUCHAR)(pPT) + pPT->DataBufferOffset;
				pcdb = (PCDB)pPT->Cdb;
				dataTransferLength = pPT->DataTransferLength;
				dataIn = pPT->DataIn;
			}
			else
			{
				if (stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH_DIRECT)) 
					break;

				PSCSI_PASS_THROUGH_DIRECT pPTD = (PSCSI_PASS_THROUGH_DIRECT)Irp->AssociatedIrp.SystemBuffer;
				pDataBuffer = (PUCHAR)pPTD->DataBuffer;
				pcdb = (PCDB)(pPTD->Cdb);
				dataTransferLength = pPTD->DataTransferLength;
				dataIn = pPTD->DataIn;
			}

I was hoping that it would be SCSI reads of various types 6-byte, 12 byte 16 byte.
But it is always 0.

Well, command 0 is TEST UNIT READY, but that seems unlikely.

Also, what dictates whether the disk driver uses IRP_MJ_SCSI or SCSI_PASS_THROUGH/SCSI_PASS_THROUGH_DIRECT to send CDB commands

I don’t believe the disk driver ever uses passthrough. That comes from user-mode apps.

1 Like