pass through example for PnP

Hello.

Is there any working example of pass-through driver for PnP?
Basically what I need to do is to attach to existing pnp driver with my own and filter one particular IRP. My question is how to do this in safe way? Thus I’m asking for working sample.

Thank you for any help.

These are called Filter drivers, and you can find examples in the Windows Kits (you may need to download the Samples separately).

Start at https://msdn.microsoft.com/en-us/windows/hardware/gg454513.aspx

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-596122-
xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: 20 November 2015 12:44
To: Windows System Software Devs Interest List
Subject: [ntdev] pass through example for PnP

Hello.

Is there any working example of pass-through driver for PnP?
Basically what I need to do is to attach to existing pnp driver with my
own and filter one particular IRP. My question is how to do this in
safe way? Thus I’m asking for working sample.

Thank you for any help.


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer
This email message has been delivered safely and archived online by Mimecast.

For more information please visit http://www.mimecast.com

As Mr. Boyce says… this is a “filter driver”

And let me add, you almost certainly want to write such a driver using WDF. It makes the development of filter drivers EXTREMELY easy. Even if you’re already a WDM expert, it’s worth learning enough WDF just to do this.

And there ARE some decent MSFT examples that’ll show how this is done.

Peter
OSR
@OSRDrivers

Thank you for answers guys.

Could you be more specific?
My plan till now was to register pnp notification (https://msdn.microsoft.com/en-us/library/windows/hardware/ff549526(v=vs.85).aspx) for interesing device class, then create new device with proper device type, then attach to existing pnp device with IoAttachDeviceToDeviceStack. Obviously my driverObject will handle IRP_MJ_CREATE, IRP_MJ_CLOSE, IRP_MJ_POWER, IRP_MJ_PNP. Create and close handlers seems to be pretty straight forward; Power dispatch also seems to be pretty straight-forward and most likely it needs to have following calls:
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
PoCallDriver(devExt->TopOfStack, Irp);

Now most ‘wodering’ part for me is to know how to pass properly (without issues) pnp.
I understand I should only care about IRP_MN_REMOVE_DEVICE, where I should detach device.

is that more or less something I should do?
I would be really grateful to see kind of sample that does this.

Thank you in advance.

So your intention is to filter arbitrary pci devices of assorted device
classes with a variety of function drivers on top of them? This is not
going to work the way you think it does.

Mark Roddy

On Fri, Nov 20, 2015 at 9:53 AM, wrote:

> Thank you for answers guys.
>
> Could you be more specific?
> My plan till now was to register pnp notification (
> https://msdn.microsoft.com/en-us/library/windows/hardware/ff549526(v=vs.85).aspx)
> for interesing device class, then create new device with proper device
> type, then attach to existing pnp device with IoAttachDeviceToDeviceStack.
> Obviously my driverObject will handle IRP_MJ_CREATE, IRP_MJ_CLOSE,
> IRP_MJ_POWER, IRP_MJ_PNP. Create and close handlers seems to be pretty
> straight forward; Power dispatch also seems to be pretty straight-forward
> and most likely it needs to have following calls:
> PoStartNextPowerIrp(Irp);
> IoSkipCurrentIrpStackLocation(Irp);
> PoCallDriver(devExt->TopOfStack, Irp);
>
> Now most ‘wodering’ part for me is to know how to pass properly (without
> issues) pnp.
> I understand I should only care about IRP_MN_REMOVE_DEVICE, where I should
> detach device.
>
> is that more or less something I should do?
> I would be really grateful to see kind of sample that does this.
>
> Thank you in advance.
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

xxxxx@gmail.com wrote:

Could you be more specific?
My plan till now was to register pnp notification (https://msdn.microsoft.com/en-us/library/windows/hardware/ff549526(v=vs.85).aspx) for interesing device class, then create new device with proper device type, then attach to existing pnp device with IoAttachDeviceToDeviceStack.

You can’t do that. By the time you get the notification of a device
interface coming or going, the driver stack has long since finished
being built. You cannot insert yourself into an existing driver stack.

Obviously my driverObject will handle IRP_MJ_CREATE, IRP_MJ_CLOSE, IRP_MJ_POWER, IRP_MJ_PNP. Create and close handlers seems to be pretty straight forward; Power dispatch also seems to be pretty straight-forward and most likely it needs to have following calls:

What would you expect to do in a CREATE or CLOSE handler? You don’t
know anything about the devices you’re planning to filter, nor what
assumptions they make at CREATE time.

is that more or less something I should do?
I would be really grateful to see kind of sample that does this.

No, this is not something you should do. What, EXACTLY, are you trying
to do here?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Ok. I think I need to explain it bit better.
Basically what I want to acheive is to get notification when anybody is trying to access microphone (actually we are interested in one particular type of microphones, but this is easy part). How to achieve it in kernel-mode in safe way? Do you have any advices? So this is not like filtering everything everywhere (I suppose :)).

xxxxx@gmail.com wrote:

Ok. I think I need to explain it bit better.
Basically what I want to acheive is to get notification when anybody is trying to access microphone (actually we are interested in one particular type of microphones, but this is easy part). How to achieve it in kernel-mode in safe way? Do you have any advices? So this is not like filtering everything everywhere (I suppose :)).

Yes, this is a very different problem from the one you originally described.

You CAN install a device upper filter on your specific microphone, which
would get loaded each time the device is detected. You could then raise
an alarm when you get a IRP_MJ_CREATE. However, there are a lot of
things to think about here. In the Vista+ audio model, audio drivers
are always opened by the special Audio Engine Process. The driver has
absolutely no clue which process is actually using the audio stream; the
application talks to the Audio Engine, and the Audio Engine talks to the
driver. There is no traceback. So, if you want to know “who” as well
as “when”, you have a serious problem.

And remember that microphones get fired up a lot. The Cortana/Siri/“Hey
Google” concepts all require that your microphone be running most of the
time.

Are you just looking for telemetry information, like how often and how
long it was used? That type of thing might already be available in the
ETW logs.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

>You CAN install a device upper filter on your specific microphone, which would get loaded each time the device is detected

Could it be realized in a way I wrote before? (PnpNotify, create device and attach)? Or I should use different approach?

If so then I don’t get what you have wrote a bit earlier:

You can’t do that. By the time you get the notification of a device interface coming or going, the driver stack has long since finished being built. You cannot insert yourself into an existing driver stack.

Could you elaborate it a bit?
Also let me dig a bit and ask you why you think my initial question was very different problem? :wink: I’d like to correct myself next time? It was too generic? Or maybe you (as an expert saw so many different things that may be hidden under such description?)?.

Anyway… As for Audio Engine Process - I noticed it already and working on it. BTW this is quiet wierd that Microsoft creates such ‘frameworks’ (which I consider as good and useful), but does not provide that interesting information (like origin of call). BTW are such things anywhere documented?Out of curiosity: how it looks for video streams? Is it also going through proxy process/framework?

Are you just looking for telemetry information, like how often and how long it was used? That type of thing might already be available in the ETW logs.
You have magic ball? :slight_smile: ok… this is not main purpose of this project, but this is next project/feature.
Anywya ETW - I believe you are talking about user-mode don’t you?

Thank you again.

xxxxx@gmail.com wrote:

> You CAN install a device upper filter on your specific microphone, which would get loaded each time the device is detected
Could it be realized in a way I wrote before? (PnpNotify, create device and attach)? Or I should use different approach?

You might want to read a little bit about PnP filter drivers. They are
a powerful concept. You install a device upper filter by creating a
services entry, then adding your service to the UpperFilters registry
entry for the device you want to filter. Now you will automatically be
loaded with the rest of the drivers for the device, and you will be
inserted at the right spot in the hierarchy.

> You can’t do that. By the time you get the notification of a device interface coming or going, the driver stack has long since finished being built. You cannot insert yourself into an existing driver stack.
Could you elaborate it a bit?

After the device stack has been initialized, it is too late to go back
and add yourself. Among other problems, each driver in the stack is
told at initialization time how many drivers are below it, and they use
that information to create a set of request stack entries in each IRP.
If you get in the way, that count is wrong, and memory gets overwritten.

Also let me dig a bit and ask you why you think my initial question was very different problem? :wink: I’d like to correct myself next time? It was too generic? Or maybe you (as an expert saw so many different things that may be hidden under such description?)?.

Yes, what you asked was how to add yourself as a filter to every PCI
device in the system, using PnP notifications. That’s a different
problem from inserting a single device upper filter driver.

Anyway… As for Audio Engine Process - I noticed it already and working on it. BTW this is quiet wierd that Microsoft creates such ‘frameworks’ (which I consider as good and useful), but does not provide that interesting information (like origin of call). BTW are such things anywhere documented?

The whole question of identifying a process is itself a point of
contention. How do you identify a process? If I give you a process ID,
what good does that do? How would you use that information? In
general, if there is no reasonable use for a piece of information,
Microsoft doesn’t go out of their way to design a way to access it.

Microsoft also has to think in terms of the general case. In general
terms, there might be 6 applications all feeding audio data to the Audio
Engine, where it gets mixed and muxed and sent to the hardware as a
single stream. How do you report that? Also remember that, as audio is
flowing, some devices (WaveRT) don’t every transition to kernel mode.
The data transfer is all handled inside the Audio Engine process. In
that case, there is nothing to filter.

The original audio driver system was collapsing under its own weight.
There were hundreds or thousands of people like you, who wanted to
insert just a bit of filtering and custom processing into the timeline.
It got so bad that professional audio systems simply could not operate
because of the unpredictable overhead – death by a thousand cuts.

The Audio Engine was also a by-product of well-dressed Hollywood
lawyers. By putting all of the audio policy-making decisions in a
specially protected process, Microsoft could make security guarantees
that eventually satisfied Shania Twain’s attorneys and allowed her music
to be played on a Windows system.

Out of curiosity: how it looks for video streams? Is it also going through proxy process/framework?

No. Video applications use DirectShow or Media Foundation, both of
which have in-process proxies to call into Kernel Streaming drivers.

> Are you just looking for telemetry information, like how often and how long it was used? That type of thing might already be available in the ETW logs.
You have magic ball? :slight_smile: ok… this is not main purpose of this project, but this is next project/feature.
Anywya ETW - I believe you are talking about user-mode don’t you?

ETW is used throughout Windows in both modes. In a Win 8 or Win 10
system, the quantity of tracing and logging information is
overwhelming. Every useful piece of data is being tracked, and it
becomes your job to figure out how to tap into that.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Tim thank you for your time,

Regarding receiving origin process id of audio stream. Well I would say such info is useful as you can for instance evaulate such process in order to see if something should be done or not. Anyway all you wrote about how Microsoft has to deal with 3rd party vendors is correct and I agree with it. I can imagine it have to be hard to design flexible enough (for everybody) framework.

Regarding upper filters: basically I’m not arguing with concept of upper filters here. This is definately a way it should be done in 100% safe way - no doubt and thank you for those clarifications.

Still this attaching thing makes me wonder. Here is mind experiment: imagine you need to do something generic. For instance you want to intercept IRP_MJ_CREATE on every microphone on any pc on which your software will be installed and you want to evaluate if this process is allowed. (for time of such experiment - we can cut off problems with getting process id, lets assume it is doeable - we are talking about doing generic driver).

Among other problems, each driver in the stack is told at initialization time how many drivers are below it, and they use that information to create a set of request stack entries in each IRP. If you get in the way, that count is wrong, and memory gets overwritten.

Isn’t all those problems solved with https://msdn.microsoft.com/en-us/library/ff548236.aspx ?
Stack should be updated with it, and drivers should be prepared for having too small stack locations - isn’t it?

Please do not treat it as arguing. I’m just curious.
Thank you again for all time you gave me.

xxxxx@gmail.com wrote:

Still this attaching thing makes me wonder. Here is mind experiment: imagine you need to do something generic. For instance you want to intercept IRP_MJ_CREATE on every microphone on any pc on which your software will be installed and you want to evaluate if this process is allowed. (for time of such experiment - we can cut off problems with getting process id, lets assume it is doeable - we are talking about doing generic driver).

Folks who have been on this list for a while know that I have a
particularly irrational bias against “should it be allowed” apps. If I
have my own microphone attached to my own computer, then I sure as hell
ought to be able to use it whenever I want without asking you “Mother
may I?”. There are a billion (almost literally) options in Windows
Group Policy that can already control almost every action you take.

> Among other problems, each driver in the stack is told at initialization time how many drivers are below it, and they use that information to create a set of request stack entries in each IRP. If you get in the way, that count is wrong, and memory gets overwritten.
Isn’t all those problems solved with https://msdn.microsoft.com/en-us/library/ff548236.aspx ?
Stack should be updated with it, and drivers should be prepared for having too small stack locations - isn’t it?

Well, assuming the very top of the device stack is where you want to
be. There are other problems as well. By the time you get called, the
whole PnP/power exchange is finished, and you didn’t participate.
Mostly, that won’t matter, but if you’re filtering arbitrary objects,
you can’t know that.

Please do not treat it as arguing. I’m just curious.

There’s nothing wrong with arguing. This exchange has been as civil as
a British formal high tea compared to some of what we’ve seen recently.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

I can’t imagine how this would work correctly. That call to IoAttachDeviceToDeviceStackSafe attaches to the TOP of the driver stack. This also means anybody why already opened the device has a pointer to some device below your filter, so you will never see it’s activity. So what’s you plan on how to find all pointers in other drivers or the I/O subsystem that already point to devices below you and getting them to come you your filter first?

It seems like you’re assuming ALL requests will be delivered to the updated top driver in the stack, which is not accurate. It’s IoCallDriver(device, irp) not IoCallTopOfStack(deviceInTheStack, irp). The device pointer is saved at the moment of first access to the stack, like when it opens the stack by name/interface. IoAttachDeviceToDeviceStackSafe doesn’t help this problem at all.

Jan

On 11/20/15, 1:44 PM, “xxxxx@lists.osr.com on behalf of xxxxx@gmail.com” wrote:

>Tim thank you for your time,
>
>Regarding receiving origin process id of audio stream. Well I would say such info is useful as you can for instance evaulate such process in order to see if something should be done or not. Anyway all you wrote about how Microsoft has to deal with 3rd party vendors is correct and I agree with it. I can imagine it have to be hard to design flexible enough (for everybody) framework.
>
>Regarding upper filters: basically I’m not arguing with concept of upper filters here. This is definately a way it should be done in 100% safe way - no doubt and thank you for those clarifications.
>
>
>Still this attaching thing makes me wonder. Here is mind experiment: imagine you need to do something generic. For instance you want to intercept IRP_MJ_CREATE on every microphone on any pc on which your software will be installed and you want to evaluate if this process is allowed. (for time of such experiment - we can cut off problems with getting process id, lets assume it is doeable - we are talking about doing generic driver).
>
>> Among other problems, each driver in the stack is told at initialization time how many drivers are below it, and they use that information to create a set of request stack entries in each IRP. If you get in the way, that count is wrong, and memory gets overwritten.
>
>Isn’t all those problems solved with https://msdn.microsoft.com/en-us/library/ff548236.aspx ?
>Stack should be updated with it, and drivers should be prepared for having too small stack locations - isn’t it?
>
>Please do not treat it as arguing. I’m just curious.
>Thank you again for all time you gave me.
>
>
>—
>NTDEV is sponsored by OSR
>
>Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
>OSR is HIRING!! See http://www.osr.com/careers
>
>For our schedule of WDF, WDM, debugging and other seminars visit:
>http://www.osr.com/seminars
>
>To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> My plan till now was to register pnp notification (https://msdn.microsoft.com/en-

us/library/windows/hardware/ff549526%28v=vs.85%29.aspx) for interesing device class, then
create new device with proper device type, then attach to existing pnp device with
IoAttachDeviceToDeviceStack.

Absolutely wrong idea, especially for block storage stacks where you can get the notification after the FS is mounted, and attach a filter which will be unknown for the FS.

Register as Upper/LowerFilters for a class instead.

Obviously my driverObject will handle IRP_MJ_CREATE, IRP_MJ_CLOSE, IRP_MJ_POWER,
IRP_MJ_PNP.

IRP_MJ_SYSTEM_CONTROL is also a must, just pass it down.

PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
PoCallDriver(devExt->TopOfStack, Irp);

Yes.

I understand I should only care about IRP_MN_REMOVE_DEVICE, where I should detach device.

If you assign any new names (symlinks, device interfaces) to the stack - then they must be deleted in SURPRISE_REMOVAL (if it is observed before REMOVE_DEVICE). So, the REMOVE_DEVICE path must be aware of whether the names were already deleted by SURPRISE_REMOVAL, or not so, in which case it must delete them itself.

Also, if you need to send some IRPs down the stack for your initialization, post-MN_START_DEVICE is the first place where you can do this. You cannot do this in AddDevice, though you can call IoGetDeviceProperty from AddDevice.

This is probably all which is required for a minimal PnP filter.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com