my Volume access control minifilter causes USB mass storage eject to fail

my minifilter blocks read/write access for IRP_MJ_CREATE, IRP_MJ_READ and IRP_MJ_WRITE based on the given access rules.

I’m having problem using the “safely remove hardware” option when my filter is attached to a mass storage device volume.
I tried excluding IRPs targeted to directory and volume from my access control logic with no luck.

debugging shows me that there are some file access(write access) when the “safely remove hardware” is invoked.

so the first approach to overcome this which comes to my mind is to make a list of the files being accessed and exclude them as well.
But the concern is that this list is identical on all scenarios for a given version? set aside the difference between different windows versions. (my target is win 7 and higher)

what do you suggest for this?

This usually means that there is a file object still open against the volume. “all” you need to do is to work out why you are causing a file object to not get close - perhaps a missing ObDreferenceObject

I think you got my situation wrong.
in the process of “safely remove hardware” my minifilter receives a few IRPS which it fails them because of the specified rules and I assume the reason of “safely remove hardware” process being failed is my driver failing those IRPs.
AM I even wrong at that?

I am not an expert in PnP but I’m pretty sure that you want to let everything go down. Its not your job to police that stuff - that belongs to the FSD (a little bit) and the real device stack stuff…

What IRP’s are you blocking? As Rod says you cannot block PnP IRP’s and you need to be careful on other requests, there are things that need to be done to the volume as part of the removal. You will need to allow access to the boot sector and volume header to deal with removal correctly.

As I said earlier

my minifilter blocks read/write access for IRP_MJ_CREATE, IRP_MJ_READ and IRP_MJ_WRITE based on the given access rules.

And it is not blindly blocking the IRP. I put a callback for them in my minifilter.
Then if my policy is, for example, to block write access for a specified volume, I complete irp_mj_create or irp mj_write with access denied status if the requested access is for write. And the same goes for read.
I think this causes windows to fail writing some data to some files in volume during"safely remove hardware" process. causing the process to fail
Here is the pre callback code I registered for IRP_MJ_CREATE, IRP_MJ_READ and IRP_MJ_WRITE. (one callback for all 3)

FLT_PREOP_CALLBACK_STATUS
dacPreOperation (
Inout PFLT_CALLBACK_DATA Data,
In PCFLT_RELATED_OBJECTS FltObjects,
Flt_CompletionContext_Outptr PVOID *CompletionContext
)
{
NTSTATUS status;
PVOLUME_ACCESS_RIGHTS pVAR = NULL;
ACCESS_MASK requestedAccess = 0;
BOOLEAN accessDenied = FALSE, isDirectory = FALSE;

UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER( CompletionContext );

status = FltIsDirectory(Data->Iopb->TargetFileObject, FltObjects->Instance, &isDirectory);

if (((Data->Iopb->TargetFileObject->Flags & FO_VOLUME_OPEN) == TRUE) ||
    ((Data->Iopb->TargetFileObject->FileName.Length == 0) && (Data->Iopb->TargetFileObject->RelatedFileObject == NULL)) ||
    isDirectory)
{
    // The create is targeted for a volume or a directory -> no access check

    return FLT_PREOP_SUCCESS_NO_CALLBACK;
}

switch (Data->Iopb->MajorFunction)
{
case IRP_MJ_CREATE: 
    requestedAccess = Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess;
    break;
case IRP_MJ_READ:
    requestedAccess = FILE_READ_DATA;
    break;
case IRP_MJ_WRITE:
    requestedAccess = FILE_WRITE_DATA;
    break;
}

if (FltGetInstanceContext(FltObjects->Instance, &pVAR) == STATUS_SUCCESS)
{
    if (pVAR->writeAccessDenied)
        if ((requestedAccess & FILE_WRITE_DATA)
            || (requestedAccess & FILE_APPEND_DATA)
            || (requestedAccess & DELETE))
            accessDenied = TRUE;

    // checking read and execute access
    if (pVAR->readAccessDenied)
        if ((requestedAccess & FILE_READ_DATA)
            || (requestedAccess & FILE_EXECUTE))
            accessDenied = TRUE;

}

if(pVAR != NULL)
    FltReleaseContext(pVAR);

if(accessDenied)
{
    Data->IoStatus.Status = STATUS_ACCESS_DENIED;
    Data->IoStatus.Information = 0;

    // Access denied. No callback needed
    return FLT_PREOP_COMPLETE;
}

return FLT_PREOP_SUCCESS_NO_CALLBACK;

}

If your policy is for write access denied are you handling the queries on whether the volume is write protected and indicating it is read only? You cannot just blindly stop all writes to the volume, unless you have done this.

I am assuming that this is a system wide block of the writes.

1 Like

It is a per volume write or read policy.
And basically only applies block rules for removable devices.

If your policy is for write access denied are you handling the queries on whether the volume is write protected and indicating it is read only? You >cannot just blindly stop all writes to the volume, unless you have done this.
No I haven’t. So I need an advice on how to handle write protected queries here and after that I’m good to block write access as I am doing here?
Seems to me it is not ok to block all writes even after handling write protected

are you handling the queries on whether the volume is write protected and indicating it is read only?
I have seen other posts on this context here and on Microsoft forums a lot. I actually searched this thoroughly on the internet before I start coding.
I mean, Is this write-protected queries conversation valid in FS minifilter context? How can I intercept such query in a minifilter?
Isn’t that a disk(or maybe other) class filter driver you are talking about?

Well, that WOULD be the logical question. Why are you trying to apply a read-only constraint to a volume in a FS Minifilter, when the right place to do this is a volume filter.

Peter

Thanks for response Peter. The satisfying answer to why i chose FS minifilter would be lack of knowledge. About the volume filter you said, are we talking about a KMDF filter driver? And above what driver? And if I want to pot the read-only constraint on the whole disk it would be a KMDF above disk.sys. right?

Yes, a KMDF filter. Above the Volume Manager.

If you want to do this “for a whole disk”… (where there could be multiple partitions) you COULD do it above disk.sys — though, I’ve personally never tried that.

Peter

Btw, Let’s say i put a filter abow disk.sys and make a usb stick disk read-only. Since it is the physical disk abstraction level we are talking about. Can I then successfully execute the “safely remove hardware” process? On an above comment Don Brun sent he said: > You will need to allow access to the boot sector and volume header to deal with removal correctly. Maybe this means a disk filter would fail in safe removal too? But that is the whole disk removal! It probably won’t need access to a volume header. Specially when the disk itself declares it is read-only right from the start. May I ask for a bit of more clarification here?

Sorry to take so long to respond. I didn’t want to try to answer this from my iPad.

What you want to do is make the file system have to deal with the whole issue of the volume being read-only. When a volume is first mounted, the file system sends a (long and torturous) series of queries/IOCTLs to the underlying volume. One of those is to determine if the underlying media is write-enabled. The results of this query allow the file system to “do the right thing.”

The IOCTL the file system sends is IOCTL_DISK_IS_WRITABLE (see this in the FAT file system source code here). If the disk IS writable, the request is completed with success, if not the request is completed with STATUS_MEDIA_WRITE_PROTECTED (see the DISK class driver source code here).

Sooo… all you need to do is filter where you want, and when you see IOCTL_DISK_IS_WRITABLE complete the request with STATUS_MEDIA_WRITE_PROTECTED. And… bingo! The file system will treat the disk as being read only, and nothing else is your concern.

It really is simplicity itself.

Peter

Thanks for your consideration!
Guess I will jump into writing and building my first KMDF filter rather than taking your time with imaginary questions.
I will try to get to the point you said.

If you want a bare-bones place to start… you’re welcome to look here.

You’ll need to add a default Queue, and an EvtIoDeviceControl callback.

If you filter above the Volume or Disk classes, you’ll also need to figure out some way to know which INSTANCE of the class you’re instantiated over and (therefore) whether or not you want to fake it to be read-only. This is likely to be the hardest part of the project, really.

I hope that all helps,

Peter

I started ahead with building and testing toaster sample from Microsoft.
I would gladly look at the sample you pointed to. And enjoy playing with it!

The filter driver from toaster sample just got installed using the inf file.
So I am wondering if the talk about the need for an installer app in the “KMDF Filter Driver: 30-Minutes – Installation: Ah…Somewhat Longer” article is valid yet or it was an issue of the date the article was written?
In short if I change that CDfilter sample and build it, I would need and installer app or my filter will install using the inf itself?

You’re right to ask about that article… it’s almost 15 years old, and was written within a year of the formal release of KMDF.

The issue that article discusses has to do with getting the CO-INSTALLER on the target machine. This should no longer be an issue, because a reasonably useful version of KMDF has shipped in box, with every version of Windows since Windows 7. If you build your driver and target KMDF V1.9, which was released in-box with Windows 7, then your driver will be able to run without any issues on every version of Windows starting with Windows 7.

That means you CAN just use a “right click” INF that does something like:

[DefaultInstall.NT]
CopyFiles = @Filter.sys
Addreg    = Filter.AddReg

[DestinationDirs]
DefaultDestDir = 12

[Filter.AddReg]
HKLM, System\CurrentControlSet\Control\Class\{DEVICE-INTERFACE-GUID-TO-FILTER}, UpperFilters, 0x00010008, %DriverName%     

You can find the appropriate Device Interface GUID in “devguid.h” in the WDK. See the INF with our CDFilter project I pointed you to on GitHub.

Peter

Thanks alot Peter for the great help

My KMDF disk filter is ready. Runs well and a minor functionality of making USB devices write protected was implemented!
The Question is why so easy!!! I actually fell in love with KMDF.
Just wanted to inform that I made something out of it.
Thanks again for helping me out!
you’ll also need to figure out some way to know which INSTANCE of the class you’re instantiated over and (therefore) whether or not you want to fake it to be read-only. This is likely to be the hardest part of the project, really.

@“Peter_Viscarola_(OSR)” said:
If you filter above the Volume or Disk classes, you’ll also need to figure out some way to know which INSTANCE of the class you’re instantiated over and (therefore) whether or not you want to fake it to be read-only. This is likely to be the hardest part of the project, really.

Time to get a little more dirty