app or driver

what is hte best way to check whether a caller to a driver is from user mode
or kernel mode?

given that I know the Entry point and save it in say gInPoint, this looks
ugly and might not always work…

// Check if the caller is app or driver
if(gInPoint < (POINTER) 0x80000000)
{
// it’s an app

}
else
{
// it’s kenel
}

Irp->RequestorMode will tell you for Irp’s, and since user code cannot call
a driver …


Don Burn (MVP, Windows DDK)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

“A P” wrote in message news:xxxxx@ntdev…
> what is hte best way to check whether a caller to a driver is from user
> mode
> or kernel mode?
>
> given that I know the Entry point and save it in say gInPoint, this looks
> ugly and might not always work…
>
>
> // Check if the caller is app or driver
> if(gInPoint < (POINTER) 0x80000000)
> {
> // it’s an app
>
> }
> else
> {
> // it’s kenel
> }
>

(a) you don’t care
(b) if you think you care, see (a)

The test you gave is meaningless nonsense, because it pretends that the
value 0x80000000 has meaning, which you can safelyl assume it never will
(hint: /3GB invalidates the test, so it only works in a very special, and
essentially uninteresting, case)

There may be a DDI call that indicates the kind of thread you are in (user
or kernel) but the test you propose is utter nonsense and will never work.
You may THINK it works but it doesn’t. Any illusion that it works can be
trivially shattered by a single reboot operation that enables a 3GB user
mode. And, of course, such a nonsensical test can never work in a 64-bit
compiler. I think there is a DDI call that indicates the kind of thread you
are in, but let’s go back to the above question: why should your driver
care?

I presume you are only talking about the top-level driver dispatch routines,
and not some intermediate-level driver.
joe


From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of A P
Sent: Friday, December 19, 2008 6:45 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] app or driver

what is hte best way to check whether a caller to a driver is from user mode
or kernel mode?

given that I know the Entry point and save it in say gInPoint, this looks
ugly and might not always work…

// Check if the caller is app or driver
if(gInPoint < (POINTER) 0x80000000)
{
// it’s an app

}
else
{
// it’s kenel
}

— NTDEV is sponsored by OSR 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 message has been scanned for viruses and
dangerous content by http:</http:> MailScanner, and is
believed to be clean.

You can call ProbeForRead within a try/except block on a pointer. It will raise an access violation if it’s not a user address (the address must be valid otherwise it can still bugcheck).

If you have an IRP, you can use Irp->RequestorMode to check if the original initiator of the operation was in usermode or kernel mode.

To check the previous mode for the current thread you can use ExGetPreviousMode.

//Daniel

“A P” wrote in message news:xxxxx@ntdev…
what is hte best way to check whether a caller to a driver is from user mode or kernel mode?

given that I know the Entry point and save it in say gInPoint, this looks ugly and might not always work…

// Check if the caller is app or driver
if(gInPoint < (POINTER) 0x80000000)
{
// it’s an app

}
else
{
// it’s kenel
}

>what is hte best way to check whether a caller to a driver is from user mode or kernel mode?

For IRP-based path, use Irp->RequestorMode, in other paths, use ExGetPreviousMode

if(gInPoint < (POINTER) 0x80000000)

Why is “g”? is it global? it must not be global.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

I keep forgetting that people attribute names in such a way as to suggest
their storage class. OF COURSE it cannot possibly be a global, but it never
occurred to me that anyone would even think that kind of thing made sense!

[I tell my students: if you write a static local or a global that does not have the word ‘const’ in front of it, you have made a fundamental design error. 100.0% of the time; the remaining cases are lost in the roundoff. The remaining times, it is going to either be a write-once constant, for example, set up once at DriverEntry or the first AddDevice and never, ever changed thereafter, and that accounts for 100.00% of the time, or it is going to require a LOT of care, and only after you’ve written a few drivers will you understand the reasons you might need a global and the degree of care that must be exercised to make it work right. The purpose of this is to save them from newbie blunders]
joe

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Sunday, December 21, 2008 8:17 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] app or driver

what is hte best way to check whether a caller to a driver is from user
mode or kernel mode?

For IRP-based path, use Irp->RequestorMode, in other paths, use
ExGetPreviousMode

if(gInPoint < (POINTER) 0x80000000)

Why is “g”? is it global? it must not be global.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com


NTDEV is sponsored by OSR

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 message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.

This reminds me of a ‘rule’ I was introduced to many years ago when writing
Cobol. That was to never use ‘go to’. It can be done and was very good
training when I was getting used to writing in a higher level language.
With experience you learn to use it only to get to exit paragraphs since you
can’t trace go to statements on most systems. I happen to agree with
telling students the rule you gave below and that it takes a lot of
experience to get it correct.

Now to my point of disagreement where even a fairly new programmer might
need globals. In a Windows NDIS Miniport driver you don’t own the driver or
any of the devices OS structures. You have your own that are passed to and
from NDIS when required. If you want to supply additional information in a
Bug Check Callback, you will need access to your structures that control
your devices. Since the BC Callback is driver level, the only way to find
your structures is to maintain a linked list anchored in global data. As
each NIC is brought up it is added and when it is shutdown/halted it is
removed from the list. Adding or removing from the list requires a spinlock
to protect it. The BC Callback runs at HIGH_LEVEL which eliminates any OS
calls.

“Joseph M. Newcomer” wrote in message
news:xxxxx@ntdev…
>I keep forgetting that people attribute names in such a way as to suggest
> their storage class. OF COURSE it cannot possibly be a global, but it
> never
> occurred to me that anyone would even think that kind of thing made sense!
>
> [I tell my students: if you write a static local or a global that does not<br>&gt; have the word ‘const’ in front of it, you have made a fundamental design<br>&gt; error. 100.0% of the time; the remaining cases are lost in the roundoff.<br>&gt; The remaining times, it is going to either be a write-once constant, for<br>&gt; example, set up once at DriverEntry or the first AddDevice and never, ever<br>&gt; changed thereafter, and that accounts for 100.00% of the time, or it is<br>&gt; going to require a LOT of care, and only after you’ve written a few <br>&gt; drivers<br>&gt; will you understand the reasons you might need a global and the degree of<br>&gt; care that must be exercised to make it work right. The purpose of this is<br>&gt; to save them from newbie blunders]
> joe
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
> Sent: Sunday, December 21, 2008 8:17 PM
> To: Windows System Software Devs Interest List
> Subject: Re:[ntdev] app or driver
>
>>what is hte best way to check whether a caller to a driver is from user
> mode or kernel mode?
>
> For IRP-based path, use Irp->RequestorMode, in other paths, use
> ExGetPreviousMode
>
>> if(gInPoint < (POINTER) 0x80000000)
>
> Why is “g”? is it global? it must not be global.
>
> –
> Maxim S. Shatskih
> Windows DDK MVP
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
> —
> NTDEV is sponsored by OSR
>
> 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 message has been scanned for viruses and
> dangerous content by MailScanner, and is
> believed to be clean.
>
>

How about… DEVICE NUMBER that’s used as part of the device name (ADC0, ADC1, … ADCn)? How about global statistics? How about any cross-controller global state… which is, ah, the definition of why you’d have global data in your driver that’s not ‘const’.

What am I missing, pray tell?

Peter
OSR

The device numbering issue is EXACTLY one of the examples I mention. Then I
mention that it has interesting implications, such as it depends on the
order of enumeration of the devices, or for USB, the order of detection,
which has its own interesting set of implications…

The other one is the statistics (in fact, we chose the USB sniffer example
because it REQUIRES a global variable, just so we’d have an excuse to talk
about the global variable and how it has to be used.

Cross-controller global state: well, if it is different logical devices on
the same physical hardware, wouldn’t that be handled by a CONTROLLER_OBJECT?

You aren’t missing anything; also, you didn’t mention the trick of saving
the driver key from DriverEntry into a write-once global. And note that I
said “subject to roundoff error”.

OTOH, the number of crap drivers I’ve had to diagose where the programmer
uses a static local variable to hold state across two calls, or puts things
in a global variable (like a buffer pointer used by the ISR) “just because
that’s how you do it” are really horrendously high. While I don’t write
drivers, I get called in to diagnose drivers. I usually spend a few hours
reading the source code, looking for the global variables (usually too
many), static local variables (not often, but there in a few drivers), and
bad use of (or failure to use) spin locks. I look at every ++ or – to make
sure it isn’t using thread-shared data. I look for NT_SUCCESS tests instead
of == STATUS_SUCCESS. Then, after I’ve identified all the simple problems,
I start looking for the second-order disasters: failure to pass down power
IRPs, using the PnP completion trick in the Power handlers, and of course,
run the driver verifier (MTTF: < 2 seconds in 90% of the drivers I’ve had to
diagnose! Plug in USB connector, watch verifier choke…)

Nearly all of these drivers were written by offshore outsourcing, or by “Our
summer intern”.

Mostly, the use of global variables ignores both the notion of more than one
instance of the device (unlike the device-name counter, which exists BECAUSE
of multiple instances) or the notion of threading. So the warning “only if
you think about the implications” is the indication that the programmer
needs to *think* [Oh! Horror!] about *why* a global variable is used, *how*
it is used, *when* it is used, etc.

Oh, and here’s a great pattern I found, in two different drivers, from two
different unrelated companies:

InterlockedIncrement(&counter);
if(counter > value)
{
DoSomething(counter);
}

Where, in fact, this code could be hit by multiple threads at the same time.
The explanation (from the company that had their in-house programmer write
the driver): “Well, I was told that if I didn’t use InterlockedIncrement,
the counter wouldn’t increment properly. But once I’ve incremented it, then
it’s safe to use”. Duh. And yes, one of the drivers only failed on
multiprocessors (and should have on uniprocessors, but obviously luck was
present), but the bug was discovered by a customer who plugged two cards in
(Explanation for the static variable: “I didn’t put it in the device
extension because that would be too expensive to access it through a
pointer”)
joe

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@osr.com
Sent: Sunday, December 21, 2008 11:52 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] app or driver

How about… DEVICE NUMBER that’s used as part of the device name (ADC0,
ADC1, … ADCn)? How about global statistics? How about any
cross-controller global state… which is, ah, the definition of why you’d
have global data in your driver that’s not ‘const’.

What am I missing, pray tell?

Peter
OSR


NTDEV is sponsored by OSR

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 message has been scanned for viruses and dangerous content by
MailScanner, and is believed to be clean.

And that’s lost in the roundoff of the 100%…Actually, I’ve never seen a
driver that handled BugCheck callbacks, but it’s a good example to add to my
list.

The key is that programmers are used to tossing global variables around as
if they make sense. Only in very limited contexts do they make sense. So
if I give them a simple rule, “Don’t do it. When you need to do it, you
will understand the exception” is a lot better as a rule. They have a
simple rule. They know it is a powerful guideline, and it should be
violated only with extreme care. Saves a lot of
application-level-C-programmers from making really dumb mistakes. Put that
threshold function in the way of their decision and they have to think about
it HARD to justify it.

[From a friend who just finished his PhD in proving concurrent programs
correct: “Everyone gets threading wrong all the time. That’s close enough
to the truth to be the easiest rule to understand”. He validated close to a
million lines of code in a variety of projects, and even one of the reputed
world’s best threading programmers got it wrong in a system that had been
delivered as an open source product for several years. Simple rules work
best]
joe

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of David Craig
Sent: Sunday, December 21, 2008 11:43 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] app or driver

This reminds me of a ‘rule’ I was introduced to many years ago when writing
Cobol. That was to never use ‘go to’. It can be done and was very good
training when I was getting used to writing in a higher level language.
With experience you learn to use it only to get to exit paragraphs since you
can’t trace go to statements on most systems. I happen to agree with
telling students the rule you gave below and that it takes a lot of
experience to get it correct.

Now to my point of disagreement where even a fairly new programmer might
need globals. In a Windows NDIS Miniport driver you don’t own the driver or
any of the devices OS structures. You have your own that are passed to and
from NDIS when required. If you want to supply additional information in a
Bug Check Callback, you will need access to your structures that control
your devices. Since the BC Callback is driver level, the only way to find
your structures is to maintain a linked list anchored in global data. As
each NIC is brought up it is added and when it is shutdown/halted it is
removed from the list. Adding or removing from the list requires a spinlock
to protect it. The BC Callback runs at HIGH_LEVEL which eliminates any OS
calls.

“Joseph M. Newcomer” wrote in message
news:xxxxx@ntdev…
>I keep forgetting that people attribute names in such a way as to
>suggest their storage class. OF COURSE it cannot possibly be a
>global, but it never occurred to me that anyone would even think that
>kind of thing made sense!
>
> [I tell my students: if you write a static local or a global that does <br>&gt; not have the word ‘const’ in front of it, you have made a fundamental <br>&gt; design error. 100.0% of the time; the remaining cases are lost in the<br>roundoff.<br>&gt; The remaining times, it is going to either be a write-once constant, <br>&gt; for example, set up once at DriverEntry or the first AddDevice and <br>&gt; never, ever changed thereafter, and that accounts for 100.00% of the <br>&gt; time, or it is going to require a LOT of care, and only after you’ve <br>&gt; written a few drivers will you understand the reasons you might need a <br>&gt; global and the degree of care that must be exercised to make it work <br>&gt; right. The purpose of this is to save them from newbie blunders] joe
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S.
> Shatskih
> Sent: Sunday, December 21, 2008 8:17 PM
> To: Windows System Software Devs Interest List
> Subject: Re:[ntdev] app or driver
>
>>what is hte best way to check whether a caller to a driver is from
>>user
> mode or kernel mode?
>
> For IRP-based path, use Irp->RequestorMode, in other paths, use
> ExGetPreviousMode
>
>> if(gInPoint < (POINTER) 0x80000000)
>
> Why is “g”? is it global? it must not be global.
>
> –
> Maxim S. Shatskih
> Windows DDK MVP
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
> —
> NTDEV is sponsored by OSR
>
> 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 message has been scanned for viruses and dangerous content by
> MailScanner, and is believed to be clean.
>
>


NTDEV is sponsored by OSR

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 message has been scanned for viruses and dangerous content by
MailScanner, and is believed to be clean.

Simple rules that properly reflect reality are best.

There is nothing inherently more difficult about using a global variable in a driver than there is in using a controller-wide (device-extension based) variable in a driver. They both require serialization for protection against concurrent access. One either understands this, or one fails to write an adequate Windows driver.

I find “Global variables are evil 100% of the time” to be a misleading, silly, rule. It must be codified SOMEwhere that neophytes can find it, because I occasionally have students say to me “it’s really evil to use global variables in a driver, right??” and I have to tell them, “well, no… not really.”

I don’t subscribe to or preach rules that are wrong on their face. We’ll just have to agree to disagree on this one, I suspect.

Peter
OSR

And how at all a write-once variable should be defined in C?
It can’t be simply a const, and cast the const
off in the point of initialization, because the compiler
may put it into a read only section?
OTOH, the section can be specified - but this needs compiler
dependent obscure pragmas/macros.

Init-once (RtlRunOnceExecuteOnce, RtlRunOnceBeginInitialize …)
exist only in Vista, and looks not very intuitive.

Regards,
–PA

xxxxx@osr.com wrote:

Simple rules that properly reflect reality are best.

There is nothing inherently more difficult about using a global variable in a driver than there is in using a controller-wide (device-extension based) variable in a driver. They both require serialization for protection against concurrent access. One either understands this, or one fails to write an adequate Windows driver.

I find “Global variables are evil 100% of the time” to be a misleading, silly, rule. It must be codified SOMEwhere that neophytes can find it, because I occasionally have students say to me “it’s really evil to use global variables in a driver, right??” and I have to tell them, “well, no… not really.”

I don’t subscribe to or preach rules that are wrong on their face. We’ll just have to agree to disagree on this one, I suspect.

Peter
OSR