Passing event notification from driver to application

Dear all,

I am developing an NDIS IM driver, I need the driver to notify the
application whenever packets of interest come in.

In the application side, I created an event and pass it to the driver using:
DeviceIoControl(
hHandle,
IOCTL_PIM_SET_EVENT,
&m_hEvent,
sizeof(HANDLE),
NULL,
0,
&bytesRet,
NULL);

In kernel side, I used the following code to get the reference the event:

if (ControlCode == IOCTL_PIM_SET_EVENT)
{

h = *((PHANDLE) irpStack->Parameters.DeviceIoControl.Type3InputBuffer);
Status = ObReferenceObjectByHandle(
h,
GENERIC_ALL,
NULL,
UserMode,
(PVOID)&gUserEvent,
(POBJECT_HANDLE_INFORMATION)NULL
);
if(Status != STATUS_SUCCESS)
{
DbgPrint(“ObReferenceObjectByHandle failed! status = %x\n”, Status);
break;
}
DbgPrint(“Referenct object sussfully!\n”);
}

In code where packets comes in, I use this code to set event:
if (gUserEvent!=NULL)
{
DbgPrint(“\nSet Event: \n”);

ASSERT(KeGetCurrentIrql()<=DISPATCH_LEVEL);

KeSetEvent(gUserEvent, 0, FALSE);
}

But this code doesn’t work for me.

Anyone has any idea what’s wrong here? Thanks a lot!

Yuanhui

In KernelMode try use it :

ObReferenceObjectByHandle(h,
0,
NULL,
KernelMode,
(PVOID *)(&gUserEvent),
NULL) ;

Do you are referencing your handle in kernel mode.

Best Regards,

Heldai

----- Original Message -----
From: “Yuanhui Zhao”
To: “NT Developers Interest List”
Sent: Wednesday, August 21, 2002 7:40 PM
Subject: [ntdev] Passing event notification from driver to application

> Dear all,
>
> I am developing an NDIS IM driver, I need the driver to notify the
> application whenever packets of interest come in.
>
> In the application side, I created an event and pass it to the driver
using:
> DeviceIoControl(
> hHandle,
> IOCTL_PIM_SET_EVENT,
> &m_hEvent,
> sizeof(HANDLE),
> NULL,
> 0,
> &bytesRet,
> NULL);
>
> In kernel side, I used the following code to get the reference the event:
>
> if (ControlCode == IOCTL_PIM_SET_EVENT)
> {
>
> h = *((PHANDLE)
irpStack->Parameters.DeviceIoControl.Type3InputBuffer);
> Status = ObReferenceObjectByHandle(
> h,
> GENERIC_ALL,
> NULL,
> UserMode,
> (PVOID)&gUserEvent,
> (POBJECT_HANDLE_INFORMATION)NULL
> );
> if(Status != STATUS_SUCCESS)
> {
> DbgPrint(“ObReferenceObjectByHandle failed! status = %x\n”, Status);
> break;
> }
> DbgPrint(“Referenct object sussfully!\n”);
> }
>
> In code where packets comes in, I use this code to set event:
> if (gUserEvent!=NULL)
> {
> DbgPrint(“\nSet Event: \n”);
>
> ASSERT(KeGetCurrentIrql()<=DISPATCH_LEVEL);
>
> KeSetEvent(gUserEvent, 0, FALSE);
> }
>
> But this code doesn’t work for me.
>
> Anyone has any idea what’s wrong here? Thanks a lot!
>
> Yuanhui
>
>
>
> —
> You are currently subscribed to ntdev as: xxxxx@scuasecurity.com.br
> To unsubscribe send a blank email to %%email.unsub%%

“Heldai” wrote in message news:xxxxx@ntdev…
>
> In KernelMode try use it :
>
> ObReferenceObjectByHandle(h,
> 0,
> NULL,
> KernelMode,
> (PVOID *)(&gUserEvent),
> NULL) ;
>
> Do you are referencing your handle in kernel mode.
>

Good heavens, please don’t do it that way. This opens up at least one ugly
security hole.

First of all, suppose the handle the user passes in isn’t a handle to an
event. And then, suppose the user doesn’t have access to the handle.

The proper way to reference a handle to an event passed from user-mode to a
driver is as follows:

Status = ObReferenceObjectByHandle(
SharedEventHandle,
EVENT_ALL_ACCESS,
*ExEventObjectType, // Check the
object type… fail if not an event
UserMode, // Check
for required access in USER mode
&SharedEvent,
NULL);

Please, NEVER omit the object type being referenced. It’s just ASKING for
trouble.

Also, note that this function call must be made in the context of the
process that created the event. That is, the handle is process-specific.
If all your function calls are working, Mr. Zhao, but you’re not seeing the
appropriate event set, then it is likely that you’re doing the ObRef… in
the wrong context. And, note that in many cases (though obviously not all)
specifying the object type will actually help you catch this problem.

To the larger issue raised by Mr. Zhao:

1)
if (ControlCode == IOCTL_PIM_SET_EVENT)
{

h = *((PHANDLE) irpStack->Parameters.DeviceIoControl.Type3InputBuffer);
Status = ObReferenceObjectByHandle(
h,
GENERIC_ALL,
NULL,
UserMode,
(PVOID)&gUserEvent,
(POBJECT_HANDLE_INFORMATION)NULL
);
if(Status != STATUS_SUCCESS)
{
DbgPrint(“ObReferenceObjectByHandle failed! status = %x\n”, Status);
break;
}
DbgPrint(“Referenct object sussfully!\n”);

Assuming the ObReference… is corrected, I sure hope the above is
“pseudo-code”… please tell me that you’re checking that the length of the
buffer is at least 4 bytes, and that the pointer is non-NULL, before
dereferencing it as shown above.

2)
For all the reasons discussed above, and more, I really struggle with the
entire concept of sharing events by having a user-mode app send a handle
into a driver. Why not share an event by name? Have the user-app create
the named event, then just open the damn thing:

//
// When you create a named event in user mode \BaseNamedObjects\ is
// prepended to the name specified in the call to CreateEvent
//
RtlInitUnicodeString(&EventName,
L"\BaseNamedObjects\SharedEvent");

//
// Get a pointer to a KEVENT object that is associated with this
// named event
//
SharedEvent = IoCreateNotificationEvent(&EventName,
&SharedEventHandle);

Doesn’t this strike everyone as much more sane and secure?

3)
Mr. Zhao, you don’t give us any information as to HOW what you’re doing
fails. Perhaps you can describe the behavior you’re seeing?

4)
We’ve written (well, actually, OSR’s Scott Noone did the work) an article
and a sample driver for the next issue of The NT Insider to try to fully
address this issue about sharing events between user apps and drivers. It
seems to be an increasingly common question, and there seems to be a lot of
marginally correct information out there (feel free to suggest your
favorite hot-button on this topic for inclusion… reply direct, please, not
to the list).

Peter
OSR

Is it at least a valid approach to pass the *name* of the event from
user-mode to kernel mode? Or is there a security hole there, too, that I’m
not seeing?

Phil


Philip D. Barila
Seagate Technology, LLC
(720) 684-1842

“Peter Viscarola” wrote in message news:xxxxx@ntdev…
>
> “Heldai” wrote in message news:xxxxx@ntdev…
> >
> > In KernelMode try use it :
> >
> > ObReferenceObjectByHandle(h,
> > 0,
> > NULL,
> > KernelMode,
> > (PVOID *)(&gUserEvent),
> > NULL) ;
> >
> > Do you are referencing your handle in kernel mode.
> >
>
> Good heavens, please don’t do it that way. This opens up at least one
ugly
> security hole.
>
> First of all, suppose the handle the user passes in isn’t a handle to an
> event. And then, suppose the user doesn’t have access to the handle.
>
> The proper way to reference a handle to an event passed from user-mode to
a
> driver is as follows:
>
> Status = ObReferenceObjectByHandle(
> SharedEventHandle,
> EVENT_ALL_ACCESS,
> *ExEventObjectType, // Check the
> object type… fail if not an event
> UserMode, // Check
> for required access in USER mode
> &SharedEvent,
> NULL);
>
> Please, NEVER omit the object type being referenced. It’s just ASKING for
> trouble.
>
> Also, note that this function call must be made in the context of the
> process that created the event. That is, the handle is process-specific.
> If all your function calls are working, Mr. Zhao, but you’re not seeing
the
> appropriate event set, then it is likely that you’re doing the ObRef… in
> the wrong context. And, note that in many cases (though obviously not all)
> specifying the object type will actually help you catch this problem.
>
> To the larger issue raised by Mr. Zhao:
>
> 1)
> if (ControlCode == IOCTL_PIM_SET_EVENT)
> {
>
> h = *((PHANDLE)
irpStack->Parameters.DeviceIoControl.Type3InputBuffer);
> Status = ObReferenceObjectByHandle(
> h,
> GENERIC_ALL,
> NULL,
> UserMode,
> (PVOID)&gUserEvent,
> (POBJECT_HANDLE_INFORMATION)NULL
> );
> if(Status != STATUS_SUCCESS)
> {
> DbgPrint(“ObReferenceObjectByHandle failed! status = %x\n”, Status);
> break;
> }
> DbgPrint(“Referenct object sussfully!\n”);
>
> Assuming the ObReference… is corrected, I sure hope the above is
> “pseudo-code”… please tell me that you’re checking that the length of
the
> buffer is at least 4 bytes, and that the pointer is non-NULL, before
> dereferencing it as shown above.
>
> 2)
> For all the reasons discussed above, and more, I really struggle with the
> entire concept of sharing events by having a user-mode app send a handle
> into a driver. Why not share an event by name? Have the user-app create
> the named event, then just open the damn thing:
>
> //
> // When you create a named event in user mode \BaseNamedObjects<br>is
> // prepended to the name specified in the call to CreateEvent
> //
> RtlInitUnicodeString(&EventName,
> L"\BaseNamedObjects\SharedEvent");
>
> //
> // Get a pointer to a KEVENT object that is associated with this
> // named event
> //
> SharedEvent = IoCreateNotificationEvent(&EventName,
> &SharedEventHandle);
>
> Doesn’t this strike everyone as much more sane and secure?
>
> 3)
> Mr. Zhao, you don’t give us any information as to HOW what you’re doing
> fails. Perhaps you can describe the behavior you’re seeing?
>
> 4)
> We’ve written (well, actually, OSR’s Scott Noone did the work) an article
> and a sample driver for the next issue of The NT Insider to try to fully
> address this issue about sharing events between user apps and drivers. It
> seems to be an increasingly common question, and there seems to be a lot
of
> marginally correct information out there (feel free to suggest your
> favorite hot-button on this topic for inclusion… reply direct, please,
not
> to the list).
>
> Peter
> OSR
>
>
>
>
>

Peter and Heldai,

Thanks for your help! Finally I worked out. The problem is I didn’t
initialize the event in the driver (it’s initialized in the application and
sent a handler to the driver). In my driver code, I added a NULL checking
statement before setting the event. Now it works fine.

However, another question arises. For heavy traffic, I lose packets.
Basically I copy the packets to Irp.AssociatedIrp.SystemBuffer, notify the
application that new packet comes in, application use DeviceIoControl to
read the buffer. Now my question is: can I make the SystemBuffer a circular
buffer in order increase the capacity of the buffer to process more packets?
Any idea is appreciated.

Yuanhui

----- Original Message -----
From: “Peter Viscarola”
Newsgroups: ntdev
To: “NT Developers Interest List”
Sent: Thursday, August 22, 2002 12:17 PM
Subject: [ntdev] Re: Passing event notification from driver to application

> “Heldai” wrote in message news:xxxxx@ntdev…
> >
> > In KernelMode try use it :
> >
> > ObReferenceObjectByHandle(h,
> > 0,
> > NULL,
> > KernelMode,
> > (PVOID *)(&gUserEvent),
> > NULL) ;
> >
> > Do you are referencing your handle in kernel mode.
> >
>
> Good heavens, please don’t do it that way. This opens up at least one
ugly
> security hole.
>
> First of all, suppose the handle the user passes in isn’t a handle to an
> event. And then, suppose the user doesn’t have access to the handle.
>
> The proper way to reference a handle to an event passed from user-mode to
a
> driver is as follows:
>
> Status = ObReferenceObjectByHandle(
> SharedEventHandle,
> EVENT_ALL_ACCESS,
> *ExEventObjectType, // Check the
> object type… fail if not an event
> UserMode, // Check
> for required access in USER mode
> &SharedEvent,
> NULL);
>
> Please, NEVER omit the object type being referenced. It’s just ASKING for
> trouble.
>
> Also, note that this function call must be made in the context of the
> process that created the event. That is, the handle is process-specific.
> If all your function calls are working, Mr. Zhao, but you’re not seeing
the
> appropriate event set, then it is likely that you’re doing the ObRef… in
> the wrong context. And, note that in many cases (though obviously not all)
> specifying the object type will actually help you catch this problem.
>
> To the larger issue raised by Mr. Zhao:
>
> 1)
> if (ControlCode == IOCTL_PIM_SET_EVENT)
> {
>
> h = *((PHANDLE)
irpStack->Parameters.DeviceIoControl.Type3InputBuffer);
> Status = ObReferenceObjectByHandle(
> h,
> GENERIC_ALL,
> NULL,
> UserMode,
> (PVOID)&gUserEvent,
> (POBJECT_HANDLE_INFORMATION)NULL
> );
> if(Status != STATUS_SUCCESS)
> {
> DbgPrint(“ObReferenceObjectByHandle failed! status = %x\n”, Status);
> break;
> }
> DbgPrint(“Referenct object sussfully!\n”);
>
> Assuming the ObReference… is corrected, I sure hope the above is
> “pseudo-code”… please tell me that you’re checking that the length of
the
> buffer is at least 4 bytes, and that the pointer is non-NULL, before
> dereferencing it as shown above.
>
> 2)
> For all the reasons discussed above, and more, I really struggle with the
> entire concept of sharing events by having a user-mode app send a handle
> into a driver. Why not share an event by name? Have the user-app create
> the named event, then just open the damn thing:
>
> //
> // When you create a named event in user mode \BaseNamedObjects<br>is
> // prepended to the name specified in the call to CreateEvent
> //
> RtlInitUnicodeString(&EventName,
> L"\BaseNamedObjects\SharedEvent");
>
> //
> // Get a pointer to a KEVENT object that is associated with this
> // named event
> //
> SharedEvent = IoCreateNotificationEvent(&EventName,
> &SharedEventHandle);
>
> Doesn’t this strike everyone as much more sane and secure?
>
> 3)
> Mr. Zhao, you don’t give us any information as to HOW what you’re doing
> fails. Perhaps you can describe the behavior you’re seeing?
>
> 4)
> We’ve written (well, actually, OSR’s Scott Noone did the work) an article
> and a sample driver for the next issue of The NT Insider to try to fully
> address this issue about sharing events between user apps and drivers. It
> seems to be an increasingly common question, and there seems to be a lot
of
> marginally correct information out there (feel free to suggest your
> favorite hot-button on this topic for inclusion… reply direct, please,
not
> to the list).
>
> Peter
> OSR
>
>
>
>
> —
> You are currently subscribed to ntdev as: xxxxx@nexland.com
> To unsubscribe send a blank email to %%email.unsub%%
>

“Phil Barila” wrote in message
news:xxxxx@ntdev…
>
> Is it at least a valid approach to pass the name of the event from
> user-mode to kernel mode? Or is there a security hole there, too, that
I’m
> not seeing?
>

Passing the name is fine. Subject to usual barage of caveats and warnings
about validating buffers, etc.

Probably the best mechanism would be to pass the name as a NULL-terminated
WCHAR string in the InBuffer (not using METHOD_NEITHER). Don’t forget the
name lives in “base named objects” and that the name is, thus, unique in the
SYSTEM (not per session).

Peter
OSR

“Peter Viscarola” wrote in message news:xxxxx@ntdev…
>
> “Phil Barila” wrote in message
> news:xxxxx@ntdev…
> >
> > Is it at least a valid approach to pass the name of the event from
> > user-mode to kernel mode? Or is there a security hole there, too, that
> I’m
> > not seeing?
> >
>
> Passing the name is fine. Subject to usual barage of caveats and warnings
> about validating buffers, etc.
>
> Probably the best mechanism would be to pass the name as a NULL-terminated
> WCHAR string in the InBuffer (not using METHOD_NEITHER). Don’t forget the
> name lives in “base named objects” and that the name is, thus, unique in
the
> SYSTEM (not per session).

I was about to reply that a UNICODE_STRING seems like a better idea, but
then I realized that there is no way to verify that the Length/MaxLength
members are valid, short of revalidating the Buffer, but the Buffer doesn’t
have to be null terminated, so maybe that’s not such a good idea. I guess
the worst thing that can happen is that the Length indication is longer than
the buffer, so you read beyond a page boundary and cause a PF in NonPaged
area, or one of the other bugchecks that can be caused by reading beyond
your allocation. For that matter, a malicious user could pass you a buffer
that ends on a page boundary, without a null, you strlen or strcpy it, go
into the next page, and you have the same problem. Seems like passing any
string from UM to KM has some risks. Comments / rebuttal anyone? I’d love
to be shown to not have a clue on this one.

Michal pointed out the previous discussion, which I had forgotten, of the
potential for mis-using a driver to twiddle system events that the user-mode
app should only be able to read. So, I guess sharing a name in a common
header file is the way to go, after all. :-Z

Phil

Philip D. Barila
Seagate Technology, LLC
(720) 684-1842

You can use IoCreateSynchronizationEvent in the kernel. You can then open
the same even in user mode. This way the name never gets passed from user to
kernel and vice versa. There is also IoCreateNotificationEvent. Until .NET
server the handle returned by these APIs are process specific handles and
you should immediately convert them to object pointers. In .NET server these
have been fixed.


Nar Ganapathy
Windows Core OS group
This posting is provided “AS IS” with no warranties, and confers no rights.

“Phil Barila” wrote in message
news:xxxxx@ntdev…
>
> “Peter Viscarola” wrote in message news:xxxxx@ntdev…
> >
> > “Phil Barila” wrote in message
> > news:xxxxx@ntdev…
> > >
> > > Is it at least a valid approach to pass the name of the event from
> > > user-mode to kernel mode? Or is there a security hole there, too,
that
> > I’m
> > > not seeing?
> > >
> >
> > Passing the name is fine. Subject to usual barage of caveats and
warnings
> > about validating buffers, etc.
> >
> > Probably the best mechanism would be to pass the name as a
NULL-terminated
> > WCHAR string in the InBuffer (not using METHOD_NEITHER). Don’t forget
the
> > name lives in “base named objects” and that the name is, thus, unique in
> the
> > SYSTEM (not per session).
>
> I was about to reply that a UNICODE_STRING seems like a better idea, but
> then I realized that there is no way to verify that the Length/MaxLength
> members are valid, short of revalidating the Buffer, but the Buffer
doesn’t
> have to be null terminated, so maybe that’s not such a good idea. I
guess
> the worst thing that can happen is that the Length indication is longer
than
> the buffer, so you read beyond a page boundary and cause a PF in NonPaged
> area, or one of the other bugchecks that can be caused by reading beyond
> your allocation. For that matter, a malicious user could pass you a
buffer
> that ends on a page boundary, without a null, you strlen or strcpy it, go
> into the next page, and you have the same problem. Seems like passing any
> string from UM to KM has some risks. Comments / rebuttal anyone? I’d
love
> to be shown to not have a clue on this one.
>
> Michal pointed out the previous discussion, which I had forgotten, of the
> potential for mis-using a driver to twiddle system events that the
user-mode
> app should only be able to read. So, I guess sharing a name in a common
> header file is the way to go, after all. :-Z
>
> Phil
> –
> Philip D. Barila
> Seagate Technology, LLC
> (720) 684-1842
>
>
>
>
>

“Phil Barila” wrote in message
news:xxxxx@ntdev…
>
> into the next page, and you have the same problem. Seems like passing any
> string from UM to KM has some risks. Comments / rebuttal anyone? I’d
love
> to be shown to not have a clue on this one.
>

That’s why I recommended using the InBuffer, and not using METHOD_NEITHER.
In this case, the user’s data buffer is copied to an appropriately sized
intermediate buffer in non-paged pool. So now, given a max length that must
include the terminating wide null, you can pretty safely wcsncpy (or
RtlStringCbCopyW from ntstrsafe.h) to copy the NULL terminated string.

> Michal pointed out the previous discussion, which I had forgotten, of the
> potential for mis-using a driver to twiddle system events that the
user-mode
> app should only be able to read. So, I guess sharing a name in a common
> header file is the way to go, after all. :-Z
>

Yeah… I agree. Passing the name leaves the driver open malicious exploit,
as our colleague noted. A pre-shared named, with the event created in user
mode, is the way to go.

Peter
OSR

“Nar Ganapathy[MS]” wrote in message
news:xxxxx@ntdev…
>
> You can use IoCreateSynchronizationEvent in the kernel. You can then open
> the same even in user mode. This way the name never gets passed from user
to
> kernel and vice versa. There is also IoCreateNotificationEvent. Until .NET
> server the handle returned by these APIs are process specific handles and
> you should immediately convert them to object pointers. In .NET server
these
> have been fixed.

In other words, do what Peter suggested, and I agreed was the right thing,
after talking myself into it, which is to share a name internally? Or are
you suggesting that we should pass a handle, which is what Peter was saying
we shouldn’t do, because you have to be really careful to make sure you
don’t open a security hole? Or are you suggesting that we pass the actual
event structure from UM to KM?

Looking at the doc for IoCreateNotificationEvent (and
IoCreateSynchronizationEvent, as well), I see it says: “The preferred method
to share event objects between user mode and kernel mode is for the
user-mode program to create the event object and pass it to the driver
through an IOCTL.” So which event descriptor does that say pass in the
IOCTL: PKEVENT, HANDLE, or KEVENT?

Thanks,

Phil

Philip D. Barila
Seagate Technology, LLC
(720) 684-1842

There are several reasons why you could be losing packets.
You are mentioning heavy traffic. Are you sure that your miniport
DPCforISR has seen them.

One possibility could be that you running out of the Packet Descritor
Queue. Since whatever you are doing in the DPC or wherever
is taking a long time. Having a circular buffer might
not necessarily solve your problem.

If you card supports drop count try querying it.

>>From: Yuanhui Zhao [mailto:xxxxx@nexland.com]
>>Sent: Thursday, August 22, 2002 11:15 AM
>>To: NT Developers Interest List
>>Subject: [ntdev] Re: Passing event notification from driver to
>>application

>>Peter and Heldai,

>>Thanks for your help! Finally I worked out. The problem is I didn’t
>>initialize the event in the driver (it’s initialized in the application
and
>>sent a handler to the driver). In my driver code, I added a NULL
checking
>>statement before setting the event. Now it works fine.
>>
>>However, another question arises. For heavy traffic, I lose packets.
>>Basically I copy the packets to Irp.AssociatedIrp.SystemBuffer, notify
the
>>application that new packet comes in, application use DeviceIoControl
to
>>read the buffer. Now my question is: can I make the SystemBuffer a
circular
>>buffer in order increase the capacity of the buffer to process more
packets?
>>Any idea is appreciated.
>>
>>Yuanhui

----- Original Message -----
From: “Peter Viscarola”
Newsgroups: ntdev
To: “NT Developers Interest List”
Sent: Thursday, August 22, 2002 12:17 PM
Subject: [ntdev] Re: Passing event notification from driver to application

> “Heldai” wrote in message news:xxxxx@ntdev…
> >
> > In KernelMode try use it :
> >
> > ObReferenceObjectByHandle(h,
> > 0,
> > NULL,
> > KernelMode,
> > (PVOID *)(&gUserEvent),
> > NULL) ;
> >
> > Do you are referencing your handle in kernel mode.
> >
>
> Good heavens, please don’t do it that way. This opens up at least one
ugly
> security hole.
>
> First of all, suppose the handle the user passes in isn’t a handle to an
> event. And then, suppose the user doesn’t have access to the handle.
>
> The proper way to reference a handle to an event passed from user-mode to
a
> driver is as follows:
>
> Status = ObReferenceObjectByHandle(
> SharedEventHandle,
> EVENT_ALL_ACCESS,
> *ExEventObjectType, // Check the
> object type… fail if not an event
> UserMode, // Check
> for required access in USER mode
> &SharedEvent,
> NULL);
>
> Please, NEVER omit the object type being referenced. It’s just ASKING for
> trouble.
>
> Also, note that this function call must be made in the context of the
> process that created the event. That is, the handle is process-specific.
> If all your function calls are working, Mr. Zhao, but you’re not seeing
the
> appropriate event set, then it is likely that you’re doing the ObRef… in
> the wrong context. And, note that in many cases (though obviously not all)
> specifying the object type will actually help you catch this problem.
>
> To the larger issue raised by Mr. Zhao:
>
> 1)
> if (ControlCode == IOCTL_PIM_SET_EVENT)
> {
>
> h = *((PHANDLE)
irpStack->Parameters.DeviceIoControl.Type3InputBuffer);
> Status = ObReferenceObjectByHandle(
> h,
> GENERIC_ALL,
> NULL,
> UserMode,
> (PVOID)&gUserEvent,
> (POBJECT_HANDLE_INFORMATION)NULL
> );
> if(Status != STATUS_SUCCESS)
> {
> DbgPrint(“ObReferenceObjectByHandle failed! status = %x\n”, Status);
> break;
> }
> DbgPrint(“Referenct object sussfully!\n”);
>
> Assuming the ObReference… is corrected, I sure hope the above is
> “pseudo-code”… please tell me that you’re checking that the length of
the
> buffer is at least 4 bytes, and that the pointer is non-NULL, before
> dereferencing it as shown above.
>
> 2)
> For all the reasons discussed above, and more, I really struggle with the
> entire concept of sharing events by having a user-mode app send a handle
> into a driver. Why not share an event by name? Have the user-app create
> the named event, then just open the damn thing:
>
> //
> // When you create a named event in user mode \BaseNamedObjects<br>is
> // prepended to the name specified in the call to CreateEvent
> //
> RtlInitUnicodeString(&EventName,
> L"\BaseNamedObjects\SharedEvent");
>
> //
> // Get a pointer to a KEVENT object that is associated with this
> // named event
> //
> SharedEvent = IoCreateNotificationEvent(&EventName,
> &SharedEventHandle);
>
> Doesn’t this strike everyone as much more sane and secure?
>
> 3)
> Mr. Zhao, you don’t give us any information as to HOW what you’re doing
> fails. Perhaps you can describe the behavior you’re seeing?
>
> 4)
> We’ve written (well, actually, OSR’s Scott Noone did the work) an article
> and a sample driver for the next issue of The NT Insider to try to fully
> address this issue about sharing events between user apps and drivers. It
> seems to be an increasingly common question, and there seems to be a lot
of
> marginally correct information out there (feel free to suggest your
> favorite hot-button on this topic for inclusion… reply direct, please,
not
> to the list).
>
> Peter
> OSR
>
>
>
>
> —
> You are currently subscribed to ntdev as: xxxxx@nexland.com
> To unsubscribe send a blank email to %%email.unsub%%
>


You are currently subscribed to ntdev as: xxxxx@nai.com
To unsubscribe send a blank email to %%email.unsub%%

“Phil Barila” wrote in message
news:xxxxx@ntdev…
>
> “Nar Ganapathy[MS]” wrote in message
> news:xxxxx@ntdev…
> >
> > kernel and vice versa. There is also IoCreateNotificationEvent. Until
.NET
> > server the handle returned by these APIs are process specific handles
and
> > you should immediately convert them to object pointers. In .NET server
> these
> > have been fixed.
>

Nar’s pointing out here (perhaps I should just shut-up and let him speak for
himself :slight_smile: is that prior to .NET, IoCreateNotificationEvent and
IoCreateSynchronizationEvent return process-specific handles. Starting with
.NET, they return kernel-mode specific handles (created with
OBJ_KERNEL_HANDLE set in the object attributes structure) and are thus
usable in kernel mode in an arbitrary thread context.

> Looking at the doc for IoCreateNotificationEvent (and
> IoCreateSynchronizationEvent, as well), I see it says: “The preferred
method
> to share event objects between user mode and kernel mode is for the
> user-mode program to create the event object and pass it to the driver
> through an IOCTL.”
>

I guess the operative question here is “preferred by whom?” Certainly not
by me. It’s not nearly clear enough an issue for me to say “the docs are
just wrong”, but I REALLY don’t think passing handles around the system is
the standard for “best practice” in this case, for the previous reasons I
mentioned.

Peter
OSR

The problem with creating a named event in KM is that should this
event happen to be created within the context of the system process your
user mode
application’s request for a handle will be denied.

Bottom line if you’re looking to share events - create the named event in
user mode,
open the named event in kernel mode.

-snoone
OSR

“Nar Ganapathy[MS]” wrote in message
news:xxxxx@ntdev…
>
> You can use IoCreateSynchronizationEvent in the kernel. You can then open
> the same even in user mode. This way the name never gets passed from user
to
> kernel and vice versa. There is also IoCreateNotificationEvent. Until .NET
> server the handle returned by these APIs are process specific handles and
> you should immediately convert them to object pointers. In .NET server
these
> have been fixed.
>
> –
> Nar Ganapathy
> Windows Core OS group
> This posting is provided “AS IS” with no warranties, and confers no
rights.
>
> “Phil Barila” wrote in message
> news:xxxxx@ntdev…
> >
> > “Peter Viscarola” wrote in message news:xxxxx@ntdev…
> > >
> > > “Phil Barila” wrote in message
> > > news:xxxxx@ntdev…
> > > >
> > > > Is it at least a valid approach to pass the name of the event from
> > > > user-mode to kernel mode? Or is there a security hole there, too,
> that
> > > I’m
> > > > not seeing?
> > > >
> > >
> > > Passing the name is fine. Subject to usual barage of caveats and
> warnings
> > > about validating buffers, etc.
> > >
> > > Probably the best mechanism would be to pass the name as a
> NULL-terminated
> > > WCHAR string in the InBuffer (not using METHOD_NEITHER). Don’t forget
> the
> > > name lives in “base named objects” and that the name is, thus, unique
in
> > the
> > > SYSTEM (not per session).
> >
> > I was about to reply that a UNICODE_STRING seems like a better idea, but
> > then I realized that there is no way to verify that the Length/MaxLength
> > members are valid, short of revalidating the Buffer, but the Buffer
> doesn’t
> > have to be null terminated, so maybe that’s not such a good idea. I
> guess
> > the worst thing that can happen is that the Length indication is longer
> than
> > the buffer, so you read beyond a page boundary and cause a PF in
NonPaged
> > area, or one of the other bugchecks that can be caused by reading beyond
> > your allocation. For that matter, a malicious user could pass you a
> buffer
> > that ends on a page boundary, without a null, you strlen or strcpy it,
go
> > into the next page, and you have the same problem. Seems like passing
any
> > string from UM to KM has some risks. Comments / rebuttal anyone? I’d
> love
> > to be shown to not have a clue on this one.
> >
> > Michal pointed out the previous discussion, which I had forgotten, of
the
> > potential for mis-using a driver to twiddle system events that the
> user-mode
> > app should only be able to read. So, I guess sharing a name in a common
> > header file is the way to go, after all. :-Z
> >
> > Phil
> > –
> > Philip D. Barila
> > Seagate Technology, LLC
> > (720) 684-1842
> >
> >
> >
> >
> >
>
>
>
>

The process contexts never come into play here. I suggest that the
application and driver both agree on a specific name for the event. If a
user process creates a name, the driver now has to validate that the event
with a particular name was created by the application it was really
interested in and not from someone else. If the driver creates the name
then there is no issue. This is why the IO APIs are useful. No handle is
passed from user to kernel mode or vice versa.


Nar Ganapathy
Windows Core OS group
This posting is provided “AS IS” with no warranties, and confers no rights.

“Scott Noone” wrote in message news:xxxxx@ntdev…
>
> The problem with creating a named event in KM is that should this
> event happen to be created within the context of the system process your
> user mode
> application’s request for a handle will be denied.
>
> Bottom line if you’re looking to share events - create the named event in
> user mode,
> open the named event in kernel mode.
>
> -snoone
> OSR
>
> “Nar Ganapathy[MS]” wrote in message
> news:xxxxx@ntdev…
> >
> > You can use IoCreateSynchronizationEvent in the kernel. You can then
open
> > the same even in user mode. This way the name never gets passed from
user
> to
> > kernel and vice versa. There is also IoCreateNotificationEvent. Until
.NET
> > server the handle returned by these APIs are process specific handles
and
> > you should immediately convert them to object pointers. In .NET server
> these
> > have been fixed.
> >
> > –
> > Nar Ganapathy
> > Windows Core OS group
> > This posting is provided “AS IS” with no warranties, and confers no
> rights.
> >
> > “Phil Barila” wrote in message
> > news:xxxxx@ntdev…
> > >
> > > “Peter Viscarola” wrote in message
news:xxxxx@ntdev…
> > > >
> > > > “Phil Barila” wrote in message
> > > > news:xxxxx@ntdev…
> > > > >
> > > > > Is it at least a valid approach to pass the name of the event
from
> > > > > user-mode to kernel mode? Or is there a security hole there, too,
> > that
> > > > I’m
> > > > > not seeing?
> > > > >
> > > >
> > > > Passing the name is fine. Subject to usual barage of caveats and
> > warnings
> > > > about validating buffers, etc.
> > > >
> > > > Probably the best mechanism would be to pass the name as a
> > NULL-terminated
> > > > WCHAR string in the InBuffer (not using METHOD_NEITHER). Don’t
forget
> > the
> > > > name lives in “base named objects” and that the name is, thus,
unique
> in
> > > the
> > > > SYSTEM (not per session).
> > >
> > > I was about to reply that a UNICODE_STRING seems like a better idea,
but
> > > then I realized that there is no way to verify that the
Length/MaxLength
> > > members are valid, short of revalidating the Buffer, but the Buffer
> > doesn’t
> > > have to be null terminated, so maybe that’s not such a good idea. I
> > guess
> > > the worst thing that can happen is that the Length indication is
longer
> > than
> > > the buffer, so you read beyond a page boundary and cause a PF in
> NonPaged
> > > area, or one of the other bugchecks that can be caused by reading
beyond
> > > your allocation. For that matter, a malicious user could pass you a
> > buffer
> > > that ends on a page boundary, without a null, you strlen or strcpy it,
> go
> > > into the next page, and you have the same problem. Seems like passing
> any
> > > string from UM to KM has some risks. Comments / rebuttal anyone? I’d
> > love
> > > to be shown to not have a clue on this one.
> > >
> > > Michal pointed out the previous discussion, which I had forgotten, of
> the
> > > potential for mis-using a driver to twiddle system events that the
> > user-mode
> > > app should only be able to read. So, I guess sharing a name in a
common
> > > header file is the way to go, after all. :-Z
> > >
> > > Phil
> > > –
> > > Philip D. Barila
> > > Seagate Technology, LLC
> > > (720) 684-1842
> > >
> > >
> > >
> > >
> > >
> >
> >
> >
> >
>
>
>
>

(Sorry for the delayed response, I was out of town, sleeping late)

The PROBLEM with this approach is, as SNoone pointed out, is that if the
DRIVER creates the event in the context of the system process (the process
context does INDEED come into play here) the app will NOT be able to open
the event unless it is running with Admin privs.

That sorta limits the utility of having the driver create the event, doesn’t
it. Or, perhaps I’m missing something…

Peter
OSR

“Nar Ganapathy[MS]” wrote in message
news:xxxxx@ntdev…
>
> The process contexts never come into play here. I suggest that the
> application and driver both agree on a specific name for the event. If a
> user process creates a name, the driver now has to validate that the event
> with a particular name was created by the application it was really
> interested in and not from someone else. If the driver creates the name
> then there is no issue. This is why the IO APIs are useful. No handle is
> passed from user to kernel mode or vice versa.
>
> –
> Nar Ganapathy
> Windows Core OS group
> This posting is provided “AS IS” with no warranties, and confers no
rights.
>
> “Scott Noone” wrote in message news:xxxxx@ntdev…
> >
> > The problem with creating a named event in KM is that should this
> > event happen to be created within the context of the system process your
> > user mode
> > application’s request for a handle will be denied.
> >
> > Bottom line if you’re looking to share events - create the named event
in
> > user mode,
> > open the named event in kernel mode.
> >
> > -snoone
> > OSR
> >
> > “Nar Ganapathy[MS]” wrote in message
> > news:xxxxx@ntdev…
> > >
> > > You can use IoCreateSynchronizationEvent in the kernel. You can then
> open
> > > the same even in user mode. This way the name never gets passed from
> user
> > to
> > > kernel and vice versa. There is also IoCreateNotificationEvent. Until
> .NET
> > > server the handle returned by these APIs are process specific handles
> and
> > > you should immediately convert them to object pointers. In .NET server
> > these
> > > have been fixed.
> > >
> > > –
> > > Nar Ganapathy
> > > Windows Core OS group
> > > This posting is provided “AS IS” with no warranties, and confers no
> > rights.
> > >
> > > “Phil Barila” wrote in message
> > > news:xxxxx@ntdev…
> > > >
> > > > “Peter Viscarola” wrote in message
> news:xxxxx@ntdev…
> > > > >
> > > > > “Phil Barila” wrote in message
> > > > > news:xxxxx@ntdev…
> > > > > >
> > > > > > Is it at least a valid approach to pass the name of the event
> from
> > > > > > user-mode to kernel mode? Or is there a security hole there,
too,
> > > that
> > > > > I’m
> > > > > > not seeing?
> > > > > >
> > > > >
> > > > > Passing the name is fine. Subject to usual barage of caveats and
> > > warnings
> > > > > about validating buffers, etc.
> > > > >
> > > > > Probably the best mechanism would be to pass the name as a
> > > NULL-terminated
> > > > > WCHAR string in the InBuffer (not using METHOD_NEITHER). Don’t
> forget
> > > the
> > > > > name lives in “base named objects” and that the name is, thus,
> unique
> > in
> > > > the
> > > > > SYSTEM (not per session).
> > > >
> > > > I was about to reply that a UNICODE_STRING seems like a better idea,
> but
> > > > then I realized that there is no way to verify that the
> Length/MaxLength
> > > > members are valid, short of revalidating the Buffer, but the Buffer
> > > doesn’t
> > > > have to be null terminated, so maybe that’s not such a good idea.
I
> > > guess
> > > > the worst thing that can happen is that the Length indication is
> longer
> > > than
> > > > the buffer, so you read beyond a page boundary and cause a PF in
> > NonPaged
> > > > area, or one of the other bugchecks that can be caused by reading
> beyond
> > > > your allocation. For that matter, a malicious user could pass you a
> > > buffer
> > > > that ends on a page boundary, without a null, you strlen or strcpy
it,
> > go
> > > > into the next page, and you have the same problem. Seems like
passing
> > any
> > > > string from UM to KM has some risks. Comments / rebuttal anyone?
I’d
> > > love
> > > > to be shown to not have a clue on this one.
> > > >
> > > > Michal pointed out the previous discussion, which I had forgotten,
of
> > the
> > > > potential for mis-using a driver to twiddle system events that the
> > > user-mode
> > > > app should only be able to read. So, I guess sharing a name in a
> common
> > > > header file is the way to go, after all. :-Z
> > > >
> > > > Phil
> > > > –
> > > > Philip D. Barila
> > > > Seagate Technology, LLC
> > > > (720) 684-1842
> > > >
> > > >
> > > >
> > > >
> > > >
> > >
> > >
> > >
> > >
> >
> >
> >
> >
>
>
>
>

It may be obvious that I’m out of my depth here, but I’ll press on until I
drown… :slight_smile:

Is it not true that the dispatch entry points are called in the user app
context, unless the dispatch is called from a system thread? Is it not also
true that an event created in the user app context will *always* be visible
to the user app? Does it not therefore follow that creating the event as a
repsonse to a call from the user app, say an IOCTL_CREATE_MY_PRIVATE_EVENT,
would give your user app an event they can always see?

What am *I* missing here?

Phil

Philip D. Barila
Seagate Technology, LLC
(720) 684-1842

“Peter Viscarola” wrote in message news:xxxxx@ntdev…
>
> (Sorry for the delayed response, I was out of town, sleeping late)
>
> The PROBLEM with this approach is, as SNoone pointed out, is that if the
> DRIVER creates the event in the context of the system process (the process
> context does INDEED come into play here) the app will NOT be able to open
> the event unless it is running with Admin privs.
>
> That sorta limits the utility of having the driver create the event,
doesn’t
> it. Or, perhaps I’m missing something…
>
> Peter
> OSR
>
>
> “Nar Ganapathy[MS]” wrote in message
> news:xxxxx@ntdev…
> >
> > The process contexts never come into play here. I suggest that the
> > application and driver both agree on a specific name for the event. If a
> > user process creates a name, the driver now has to validate that the
event
> > with a particular name was created by the application it was really
> > interested in and not from someone else. If the driver creates the name
> > then there is no issue. This is why the IO APIs are useful. No handle is
> > passed from user to kernel mode or vice versa.
> >
> > –
> > Nar Ganapathy
> > Windows Core OS group
> > This posting is provided “AS IS” with no warranties, and confers no
> rights.
> >
> > “Scott Noone” wrote in message news:xxxxx@ntdev…
> > >
> > > The problem with creating a named event in KM is that should this
> > > event happen to be created within the context of the system process
your
> > > user mode
> > > application’s request for a handle will be denied.
> > >
> > > Bottom line if you’re looking to share events - create the named event
> in
> > > user mode,
> > > open the named event in kernel mode.
> > >
> > > -snoone
> > > OSR
> > >
> > > “Nar Ganapathy[MS]” wrote in message
> > > news:xxxxx@ntdev…
> > > >
> > > > You can use IoCreateSynchronizationEvent in the kernel. You can then
> > open
> > > > the same even in user mode. This way the name never gets passed from
> > user
> > > to
> > > > kernel and vice versa. There is also IoCreateNotificationEvent.
Until
> > .NET
> > > > server the handle returned by these APIs are process specific
handles
> > and
> > > > you should immediately convert them to object pointers. In .NET
server
> > > these
> > > > have been fixed.
> > > >
> > > > –
> > > > Nar Ganapathy
> > > > Windows Core OS group
> > > > This posting is provided “AS IS” with no warranties, and confers no
> > > rights.
> > > >
> > > > “Phil Barila” wrote in message
> > > > news:xxxxx@ntdev…
> > > > >
> > > > > “Peter Viscarola” wrote in message
> > news:xxxxx@ntdev…
> > > > > >
> > > > > > “Phil Barila” wrote in message
> > > > > > news:xxxxx@ntdev…
> > > > > > >
> > > > > > > Is it at least a valid approach to pass the name of the
event
> > from
> > > > > > > user-mode to kernel mode? Or is there a security hole there,
> too,
> > > > that
> > > > > > I’m
> > > > > > > not seeing?
> > > > > > >
> > > > > >
> > > > > > Passing the name is fine. Subject to usual barage of caveats
and
> > > > warnings
> > > > > > about validating buffers, etc.
> > > > > >
> > > > > > Probably the best mechanism would be to pass the name as a
> > > > NULL-terminated
> > > > > > WCHAR string in the InBuffer (not using METHOD_NEITHER). Don’t
> > forget
> > > > the
> > > > > > name lives in “base named objects” and that the name is, thus,
> > unique
> > > in
> > > > > the
> > > > > > SYSTEM (not per session).
> > > > >
> > > > > I was about to reply that a UNICODE_STRING seems like a better
idea,
> > but
> > > > > then I realized that there is no way to verify that the
> > Length/MaxLength
> > > > > members are valid, short of revalidating the Buffer, but the
Buffer
> > > > doesn’t
> > > > > have to be null terminated, so maybe that’s not such a good
idea.
> I
> > > > guess
> > > > > the worst thing that can happen is that the Length indication is
> > longer
> > > > than
> > > > > the buffer, so you read beyond a page boundary and cause a PF in
> > > NonPaged
> > > > > area, or one of the other bugchecks that can be caused by reading
> > beyond
> > > > > your allocation. For that matter, a malicious user could pass you
a
> > > > buffer
> > > > > that ends on a page boundary, without a null, you strlen or strcpy
> it,
> > > go
> > > > > into the next page, and you have the same problem. Seems like
> passing
> > > any
> > > > > string from UM to KM has some risks. Comments / rebuttal anyone?
> I’d
> > > > love
> > > > > to be shown to not have a clue on this one.
> > > > >
> > > > > Michal pointed out the previous discussion, which I had forgotten,
> of
> > > the
> > > > > potential for mis-using a driver to twiddle system events that the
> > > > user-mode
> > > > > app should only be able to read. So, I guess sharing a name in a
> > common
> > > > > header file is the way to go, after all. :-Z
> > > > >
> > > > > Phil
> > > > > –
> > > > > Philip D. Barila
> > > > > Seagate Technology, LLC
> > > > > (720) 684-1842
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > >
> > > >
> > > >
> > > >
> > >
> > >
> > >
> > >
> >
> >
> >
> >
>
>
>
>

“Phil Barila” wrote in message
news:xxxxx@ntdev…
>
> Is it not true that the dispatch entry points are called in the user app
> context, unless the dispatch is called from a system thread?

Absolutely not.

Any driver that is in a device stack below another driver must only expect
to be called in an arbitrary thread context.

Consider a filter above the disk port driver… Is there some reason to
expect it will be called in the context of the thread that requested the I/O
that it is processing?

> Is it not also
> true that an event created in the user app context will always be
visible
> to the user app?

Always? Well, with some limitations on the meaning of always and
barring the metaphysically absurd, I s’pose that’d be hard to debate.

> Does it not therefore follow that creating the event as a
> repsonse to a call from the user app, say an
IOCTL_CREATE_MY_PRIVATE_EVENT,
> would give your user app an event they can always see?
>

Well, maybe. You have to ask yourself one question: “Do I feel lucky?”
Sure, there “should be no reason” that
- the file system that receives that IRP and forwards it to the
volume manager,
- who forwards it to the disk class driver,
- who forwards it to the partition manager,
- who forwards it to the disk class driver,
- who forwards it to your filter driver…

would change context. Then again, there’s nothing that I am aware of that
would prohibit them from doing so.

Basing a design on this would make me sort of nervous.

Not to mention that in the general case, which was what I was speaking about
in my previous answer, the driver wasn’t restricted to creating the event in
response to an IOCTL. You might choose to create the event in, for example,
your AddDevice routine… or your Disptach Start Device processing function.
As Mr. Roddy has pointed out on numerous occaisions, that can lead to the
access issues that SNoone mentioned.

Of course, any arbitrary driver could create an added Device Object (maybe
using IoCreateDeviceSecure with a unique GUID) for control use. And,
indeed, if that Device Object is directly opened by the application, there
should be no reason the driver’s dispatch routine for that Device Object
will not be called in the context of the requesting thread.

Hope that makes what I was thinking more clear (that’s one of the problems
with following-up week-old posts… we all kinda lose context).

Peter
OSR

I have used the event technique in the FlashPath & Smarty drivers for
SmartDisk. The app, usually a service or just a tray app, would create and
initialize an event. On W9X it would get the ring zero handle or on NT just
send it to the driver which would do the system call to get a kernal mode
handle. The driver would set the event that a thread was waiting upon.
After waking up that thread would reset the event so it could be triggered
again. This was a very low occurance event only dealing with media/battery
issues. I found examples of the event code in something from Vireo or
Microsoft. It had the ability to work on both NT & 9x with only a
conditional branch in the app. So the same app was released for all
platforms.

----- Original Message -----
From: “Phil Barila”
Newsgroups: ntdev
To: “NT Developers Interest List”
Sent: Tuesday, September 03, 2002 6:24 PM
Subject: [ntdev] Re: Passing event notification from driver to application

> It may be obvious that I’m out of my depth here, but I’ll press on until I
> drown… :slight_smile:
>
> Is it not true that the dispatch entry points are called in the user app
> context, unless the dispatch is called from a system thread? Is it not
also
> true that an event created in the user app context will always be
visible
> to the user app? Does it not therefore follow that creating the event as
a
> repsonse to a call from the user app, say an
IOCTL_CREATE_MY_PRIVATE_EVENT,
> would give your user app an event they can always see?
>
> What am I missing here?
>
> Phil
> –
> Philip D. Barila
> Seagate Technology, LLC
> (720) 684-1842
>
> “Peter Viscarola” wrote in message news:xxxxx@ntdev…
> >
> > (Sorry for the delayed response, I was out of town, sleeping late)
> >
> > The PROBLEM with this approach is, as SNoone pointed out, is that if the
> > DRIVER creates the event in the context of the system process (the
process
> > context does INDEED come into play here) the app will NOT be able to
open
> > the event unless it is running with Admin privs.
> >
> > That sorta limits the utility of having the driver create the event,
> doesn’t
> > it. Or, perhaps I’m missing something…
> >
> > Peter
> > OSR
> >
> >
> > “Nar Ganapathy[MS]” wrote in message
> > news:xxxxx@ntdev…
> > >
> > > The process contexts never come into play here. I suggest that the
> > > application and driver both agree on a specific name for the event. If
a
> > > user process creates a name, the driver now has to validate that the
> event
> > > with a particular name was created by the application it was really
> > > interested in and not from someone else. If the driver creates the
name
> > > then there is no issue. This is why the IO APIs are useful. No handle
is
> > > passed from user to kernel mode or vice versa.
> > >
> > > –
> > > Nar Ganapathy
> > > Windows Core OS group
> > > This posting is provided “AS IS” with no warranties, and confers no
> > rights.
> > >
> > > “Scott Noone” wrote in message news:xxxxx@ntdev…
> > > >
> > > > The problem with creating a named event in KM is that should this
> > > > event happen to be created within the context of the system process
> your
> > > > user mode
> > > > application’s request for a handle will be denied.
> > > >
> > > > Bottom line if you’re looking to share events - create the named
event
> > in
> > > > user mode,
> > > > open the named event in kernel mode.
> > > >
> > > > -snoone
> > > > OSR
> > > >
> > > > “Nar Ganapathy[MS]” wrote in message
> > > > news:xxxxx@ntdev…
> > > > >
> > > > > You can use IoCreateSynchronizationEvent in the kernel. You can
then
> > > open
> > > > > the same even in user mode. This way the name never gets passed
from
> > > user
> > > > to
> > > > > kernel and vice versa. There is also IoCreateNotificationEvent.
> Until
> > > .NET
> > > > > server the handle returned by these APIs are process specific
> handles
> > > and
> > > > > you should immediately convert them to object pointers. In .NET
> server
> > > > these
> > > > > have been fixed.
> > > > >
> > > > > –
> > > > > Nar Ganapathy
> > > > > Windows Core OS group
> > > > > This posting is provided “AS IS” with no warranties, and confers
no
> > > > rights.
> > > > >
> > > > > “Phil Barila” wrote in message
> > > > > news:xxxxx@ntdev…
> > > > > >
> > > > > > “Peter Viscarola” wrote in message
> > > news:xxxxx@ntdev…
> > > > > > >
> > > > > > > “Phil Barila” wrote in message
> > > > > > > news:xxxxx@ntdev…
> > > > > > > >
> > > > > > > > Is it at least a valid approach to pass the name of the
> event
> > > from
> > > > > > > > user-mode to kernel mode? Or is there a security hole
there,
> > too,
> > > > > that
> > > > > > > I’m
> > > > > > > > not seeing?
> > > > > > > >
> > > > > > >
> > > > > > > Passing the name is fine. Subject to usual barage of caveats
> and
> > > > > warnings
> > > > > > > about validating buffers, etc.
> > > > > > >
> > > > > > > Probably the best mechanism would be to pass the name as a
> > > > > NULL-terminated
> > > > > > > WCHAR string in the InBuffer (not using METHOD_NEITHER).
Don’t
> > > forget
> > > > > the
> > > > > > > name lives in “base named objects” and that the name is, thus,
> > > unique
> > > > in
> > > > > > the
> > > > > > > SYSTEM (not per session).
> > > > > >
> > > > > > I was about to reply that a UNICODE_STRING seems like a better
> idea,
> > > but
> > > > > > then I realized that there is no way to verify that the
> > > Length/MaxLength
> > > > > > members are valid, short of revalidating the Buffer, but the
> Buffer
> > > > > doesn’t
> > > > > > have to be null terminated, so maybe that’s not such a good
> idea.
> > I
> > > > > guess
> > > > > > the worst thing that can happen is that the Length indication is
> > > longer
> > > > > than
> > > > > > the buffer, so you read beyond a page boundary and cause a PF in
> > > > NonPaged
> > > > > > area, or one of the other bugchecks that can be caused by
reading
> > > beyond
> > > > > > your allocation. For that matter, a malicious user could pass
you
> a
> > > > > buffer
> > > > > > that ends on a page boundary, without a null, you strlen or
strcpy
> > it,
> > > > go
> > > > > > into the next page, and you have the same problem. Seems like
> > passing
> > > > any
> > > > > > string from UM to KM has some risks. Comments / rebuttal
anyone?
> > I’d
> > > > > love
> > > > > > to be shown to not have a clue on this one.
> > > > > >
> > > > > > Michal pointed out the previous discussion, which I had
forgotten,
> > of
> > > > the
> > > > > > potential for mis-using a driver to twiddle system events that
the
> > > > > user-mode
> > > > > > app should only be able to read. So, I guess sharing a name in
a
> > > common
> > > > > > header file is the way to go, after all. :-Z
> > > > > >
> > > > > > Phil
> > > > > > –
> > > > > > Philip D. Barila
> > > > > > Seagate Technology, LLC
> > > > > > (720) 684-1842
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > >
> > > >
> > > >
> > > >
> > >
> > >
> > >
> > >
> >
> >
> >
> >
>
>
>
> —
> You are currently subscribed to ntdev as: xxxxx@yoshimuni.com
> To unsubscribe send a blank email to %%email.unsub%%
>

“Peter Viscarola” wrote in message news:xxxxx@ntdev…
>
>
> “Phil Barila” wrote in message
> news:xxxxx@ntdev…
> >
> > Is it not true that the dispatch entry points are called in the user app
> > context, unless the dispatch is called from a system thread?
>
> Absolutely not.

Told you I’d drown. :slight_smile:

>
> Any driver that is in a device stack below another driver must only expect
> to be called in an arbitrary thread context.
>
> Consider a filter above the disk port driver… Is there some reason to
> expect it will be called in the context of the thread that requested the
I/O
> that it is processing?
>
> > Is it not also
> > true that an event created in the user app context will always be
> visible
> > to the user app?
>
> Always? Well, with some limitations on the meaning of always and
> barring the metaphysically absurd, I s’pose that’d be hard to debate.

Well yes, but since the first point was bogus, then this point is, more or
less, irrelevant in this context.

>
> > Does it not therefore follow that creating the event as a
> > repsonse to a call from the user app, say an
> IOCTL_CREATE_MY_PRIVATE_EVENT,
> > would give your user app an event they can always see?
> >
>
> Well, maybe. You have to ask yourself one question: “Do I feel lucky?”
> Sure, there “should be no reason” that
> - the file system that receives that IRP and forwards it to the
> volume manager,
> - who forwards it to the disk class driver,
> - who forwards it to the partition manager,
> - who forwards it to the disk class driver,
> - who forwards it to your filter driver…
>
> would change context. Then again, there’s nothing that I am aware of that
> would prohibit them from doing so.

Of course. I really missed the whole ballpark on this one. That’s why this
list is such a cool resource, discussions like this enable learning when
it’s most effective. Thanks.

>
> Basing a design on this would make me sort of nervous.
>
> Not to mention that in the general case, which was what I was speaking
about
> in my previous answer, the driver wasn’t restricted to creating the event
in
> response to an IOCTL. You might choose to create the event in, for
example,
> your AddDevice routine… or your Disptach Start Device processing
function.
> As Mr. Roddy has pointed out on numerous occaisions, that can lead to the
> access issues that SNoone mentioned.
>
> Of course, any arbitrary driver could create an added Device Object (maybe
> using IoCreateDeviceSecure with a unique GUID) for control use. And,
> indeed, if that Device Object is directly opened by the application, there
> should be no reason the driver’s dispatch routine for that Device Object
> will not be called in the context of the requesting thread.
>
> Hope that makes what I was thinking more clear (that’s one of the problems
> with following-up week-old posts… we all kinda lose context).

So here’s how I understand the different options for sync’ing between user
app and driver. They all seem to have some trade-offs between utility,
security, and reliability.

1. Create event in user-mode, pass handle to kernel. David Craig says this
works great for him, and the OP in this thread started with this method.
The downside is that this handle is process specific, and it can be
troublesome to get a kernel handle to the same event that is valid in an
arbitrary context. Maybe? the event goes away when the app does, so driver
needs to guard against that? Or am I confusing that with another UM->KM
interaction? Is there another security or stability hole that I missed?

2. Create named event in user-mode, open same named event in kernel mode.
PGV’s personal preference, if I’m reading the archive right. Really not a
good idea to pass a name into the driver, lots of pitfalls there. Downside
of creating named event in UM is that named events are a security hole that
haven’t been patched? I’m not sure about this one.

3. Create named event in KM, open it in UM. This appears to be xxxxx@MSFT’s
preferred method. No apparent security hole, but until .NET server, this
resulted in process specific handles, which led to the possibility
(probability?) of creating the event in the system context, which then
resulted in ACCESS_DENIED when attempting to open in in the UM app, as
pointed out by SNoone and reinforced by PGV.

4 Create event in KM, pass handle to UM. Nobody has advocated it, I think
it’s because the KM address of the event will be off-limits to the UM app by
definition? Maybe you could put the event memory in a mapping or some such
memory sharing technique, but this seems like it creates a lot more problems
than it solves.

So if I’m reading the archive correctly, MS recommends creating named event
in KM, opening same event in UM. OSR suggests the reverse. However, as has
been discussed before, and repeated by Michal and Mark, named events are a
potential security hole that is only closed by using PGV’s favorite
undocumented kernel API.

Am I getting close now?

If I have misrepresented anyone, I am profoundly sorry.

Thanks,

Phil

Philip D. Barila
Seagate Technology, LLC
(720) 684-1842

“Phil Barila” wrote in message
news:xxxxx@ntdev…
>

This is really very useful. I’m sure SNoone is taking it all in for his
article in the upcoming issue of The NT Insider which will cover precisely
this topic.

> So here’s how I understand the different options for sync’ing between user
> app and driver. They all seem to have some trade-offs between utility,
> security, and reliability.
>
> 1. Create event in user-mode, pass handle to kernel. David Craig says
this
> works great for him, and the OP in this thread started with this method.
> The downside is that this handle is process specific, and it can be
> troublesome to get a kernel handle to the same event that is valid in an
> arbitrary context.

Not really. The issues here are (a) the handle has to be passed to the
driver, and the driver must reference it in the current context (turning the
handle into a pointer) using ObReferenceObjectByHandle, and (b) you must be
careful to call ObReferenceObjectByHandle “properly”, providing the object
type, and specifying user mode as the access mode.

> Maybe? the event goes away when the app does, so driver
> needs to guard against that? Or am I confusing that with another UM->KM
> interaction?
>
Referencing the handle via ObRefObjByHandle keeps the object from “going
away”, even when the handle is closed by the user app.

> Is there another security or stability hole that I missed?
>

Given the above, not that I’m aware of.

>
> 2. Create named event in user-mode, open same named event in kernel mode.
> PGV’s personal preference, if I’m reading the archive right. Really not a
> good idea to pass a name into the driver, lots of pitfalls there.
Downside
> of creating named event in UM is that named events are a security hole
that
> haven’t been patched? I’m not sure about this one.
>

No downside that I can see, except that you must pre-agree on the name
(perhaps via a header file).

I don’t agree NarG’s point that when the event is created in user mode “the
driver now has to validate that the event with a particular name was created
by the application it was really interested in and not from someone else” –
An event is a system-wide named object. Regardless of which app created it,
anyone with appropriate access can open it. So, even if it’s created by
“someone else”, I can’t see why that would matter. We’re not trying to
create a distinct and PRIVATE control channel here (though, if we were, we
could always set the protection on the object using the appropriate Win32
API).

>
> 3. Create named event in KM, open it in UM. This appears to be
xxxxx@MSFT’s
> preferred method. No apparent security hole, but until .NET server, this
> resulted in process specific handles, which led to the possibility
> (probability?) of creating the event in the system context, which then
> resulted in ACCESS_DENIED when attempting to open in in the UM app, as
> pointed out by SNoone and reinforced by PGV.
>

Almost, but not quite.

The difference here between .NET and other platforms is also very important,
as NarG rightly points out. When you call IoCreateXxxxEvent on systems
before .NET, the handle that’s returned to you is a handle created in the
context of the current process. Starting with .NET, the handle that’s
returned to you is a distinct kernel handle (created with OBJ_KERNEL_HANDLE
set in the object attributes structure) that’s only useable from kernel
mode.

The issue (on any platform) is that if one creates an object in their driver
in the context of the system process, the object won’t be accessible unless
you have admin privs.

> 4 Create event in KM, pass handle to UM. Nobody has advocated it, I think
> it’s because the KM address of the event will be off-limits to the UM app
by
> definition? Maybe you could put the event memory in a mapping or some
such
> memory sharing technique, but this seems like it creates a lot more
problems
> than it solves.
>

Again, not quite. Remember, a handle is nothing more than a reference to an
entry in the process-specific handle table. The issue here is (a) in .NET
and later, the user app won’t be able to use the handle (assuming the event
is created with IoCreateXxxxEvent), (b) the call would have to take place in
the context of the requesting process (or the handle won’t be valid), (c)
unless the driver references the event (here’s ObRefObjByHandle again) that
one handle instance will be SHARED between the driver and the user app. As
soon as one of them closes the handle, the event goes away.

All in all, this isn’t a good option.

> So if I’m reading the archive correctly, MS recommends creating named
event
> in KM, opening same event in UM. OSR suggests the reverse. However, as
has
> been discussed before, and repeated by Michal and Mark, named events are a
> potential security hole that is only closed by using PGV’s favorite
> undocumented kernel API.
>

Ahhhh, well… my “favorite” undocumented NtWhateverItIs call here is the
one that would allow you to create the event in kernel mode in the system
process context, yet allow the event to be accessed by the user app. That’s
all. So, no, it’s not a security hole.

Finally, I would add that NarG isn’t someone with whom I would normally
disagree. When it comes to matters of the I/O subsystem, he is THE ultimate
authority. Thus, it’s possible that even in this case there is some subtle
issue he’s thinking about that I’m not seeing.

Peter
OSR