Accessing User Space by Waiting for the Right Process Context

The DDK keeps saying that only highest-level drivers can be sure that their context is that of the user mode caller. But is it possible for the lower drivers/ISRs to waiting for the right process context to appear by chance by comparing the current process id with the target user process id(by checking the value of PsGetCurrentProcessId())

If the current process id happens to be that of the target process, can the driver directly access the user mode virtual address? i.e. does the pid enough to guarantee the same process context ?

I’m not using this technique for anything currently but just want to know in theory if is it possible to patiently wait for the right process context to appear by chance. One possible use maybe to have a timer object DPC to wake up periodically to see if by chance it is in the right context and do sometime on the target process user address.

For short you need to reference the eprocess object by PsLookupProcessByProcessId and switch process context by KeStackAttachProcess, read WDK document for details.

This is strongly discouraged & not recommended, and you are very likely to introduce security vulnerabilities into your product by doing this. Referencing the process is not sufficient to prevent the user mode address space from being destroyed (at which point it is illegal to reference user mode VAs in that process).

  • S (Msft)

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
Sent: Friday, October 02, 2015 11:35 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Accessing User Space by Waiting for the Right Process Context

For short you need to reference the eprocess object by PsLookupProcessByProcessId and switch process context by KeStackAttachProcess, read WDK document for details.


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

Using MDL for large amount data transfer is the best way to do such job, if you don’t know what exactly you are doing, you should just follow the documents and learn from official samples.

> If the current process id happens to be that of the target process, can the driver directly

access the user mode virtual address?

Sure - as long as you are desperate to crash the system this is the right way to go…

Just consider what happens if the target process frees the range that your driver is about to access, and you will (hopefully) understand why the very idea of accessing the userland from the kernel mode is really dumb.

Anton Bassov

Just use __try/__except around the user mode access.

This is how METHOD_NEITHER is supposed to work.


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

wrote in message news:xxxxx@ntdev…
>> If the current process id happens to be that of the target process, can the driver directly
>> access the user mode virtual address?
>
>
> Sure - as long as you are desperate to crash the system this is the right way to go…
>
> Just consider what happens if the target process frees the range that your driver is about to access, and you will (hopefully) understand why the very idea of accessing the userland from the kernel mode is really dumb.
>
>
>
>
> Anton Bassov
>

On 04-Oct-2015 22:30, Maxim S. Shatskih wrote:

Just use __try/__except around the user mode access.

This is how METHOD_NEITHER is supposed to work.

Just. It’s the Most Dangerous Word in software development…

https://www.google.com/search?q=Just++Most+Dangerous+Word+In+Software+Development

:wink:

> This is how METHOD_NEITHER is supposed to work.

…apart from the fact that, in order to use METHOD_NEITHER you must be 100% sure you are in context of a thread that has initiated the request.

Now look at the whole thing from the OP’s perspective - he is accessing a UM buffer and,once in a sudden, context switch occurs. If he was accessing the target buffer only in context of a thread that had initiated the request it would not be a big deal, but consider what happens if he does it in context of a system thread - the next time it gets scheduled the page directory may be already different, which means the OP may,for example, read a buffer in the address space X and write his modification to it already in totally unrelated address space Y. Funny,ugh…

In order to avoid this scenario he has to raise IRQL to DISPATCH_LEVEL in order to prevent context switches on a given CPU, but if he does so faulting at the userland address will immediately result in BSOD even if he does it in __try/__except block…

Anton Bassov

> Now look at the whole thing from the OP’s perspective - he is accessing a UM buffer and,once in a

sudden, context switch occurs.

Just do all of the stuff from the caller’s thread and not the system thread.


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

> Just do all of the stuff from the caller’s thread and not the system thread.

Now go and read the original question once more - the OP asks us how to access the userland in context of arbirary thread, rather than the calling one, and everyone (apart from you) tells him that this approach is inherently unsafe…

Anton Bassov

I have three thoughts on this thread.

  1. The OP’s question was clearly answered by Mr. Johnson.

  2. The remainder of the discussion is dumb beyond words, and makes me wonder why I approved Mr. Bassov’s post (he IS still on moderation, you know).

  3. Mr. Bassov’s statement: “he is accessing a UM buffer and, once in a sudden, context switch occurs”… made me laugh. If he’s in the context of a thread that belongs to the process that owns the memory, when “a context switch occurs” he will no longer be running until another context switch occurs that returns him to the same thread/process context. But none of it is relevant, see Mr. Johnson’s comment (supra).

Peter
OSR
@OSRDrivers

I am the OP and is very new to driver development.

I come up with this question after reading the all thick textbooks on driver development and want to verify if my understanding of the basic concepts is correct or not. This is why I’m just asking if my idea is correct “in theory”

About Mr Ken Johnson’s suggestion:

Referencing the process is not sufficient to prevent the user mode address space from being
destroyed (at which point it is illegal to reference user mode VAs in that
process).

Security aside (for this theoretical discussion), I don’t understand why the above is the issue. As suggested by Mr Shatskih, my understanding is that surrounding the whole thing by __try/__except should be able prevent reading memory paged out to disk - except as shown in Chap7 of Oney’s book we should, in addition to __try, locks the pages by MmProbeAndLockPages().

> The remainder of the discussion is dumb beyond words,

Could well be the case - more on it below…

If he’s in the context of a thread that belongs to the process that owns the memory,
when “a context switch occurs” he will no longer be running until another context switch
occurs that returns him to the same thread/process context.

I was just looking at the OP’s original question and somehow disregarded the post mentioning KeStackAttachProcess () which would, indeed, attach him to the target address space and ensure the scenario I mentioned just cannot occur. As a result, I managed to turn the whole thing into the absurdity…

Anton Bassov

ISRs and DPCs cannot ever access usermode addresses, even if they are in the right process context. Usermode PTE can be invalidated at any time, even if the physical page page is locked.
A system thread is not guaranteed to be in any process context for any time, unless it’s attached to the target process.
The right way to access user buffer in arbitrary context is to lock it and obtain system mapping address for it.

Sorry for my post before reading OP carefully. If he means accessing UM buffer in an arbitrary thread context, that would be normally in a DPC or ISR routine with raised IRQL, touch any unlocked paged memory including UM buffer is not allowed in this situation.

xxxxx@hotmail.com wrote:

> Referencing the process is not sufficient to prevent the user mode address space from being
> destroyed (at which point it is illegal to reference user mode VAs in that process).
Security aside (for this theoretical discussion), I don’t understand why the above is the issue. As suggested by Mr Shatskih, my understanding is that surrounding the whole thing by __try/__except should be able prevent reading memory paged out to disk - except as shown in Chap7 of Oney’s book we should, in addition to __try, locks the pages by MmProbeAndLockPages().

__try and __except don’t do anything to keep memory around. They merely
prevent an address exception from crashing the system.
MmProbeAndLockPages (and similar) is the API that forces the pages to
stay in memory.

When you’re doing kernel programming, you ALWAYS have to think in terms
of simultaneous action. What could be going on at the exact same time
I’m going this? Well, until you lock those pages, another thread in the
process could release the memory entirely, at which point the address is
invalid. Referencing it causes a crash (or catchable exception).
That’s why just calling MmProbeAndLockPages is not enough – between the
time you checked the address and the time you called ProbeAndLock, the
memory could have been released.

Once you call MmProbeAndLockPages, the physical pages will not go away
until you release the lock. It’s still possible for another thread to
release the memory, so the user-mode virtual address can still
evaporate, but the pages will still be around, and you can use the
kernel virtual address from ProbeAndLock to access them.


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

>suggested by Mr Shatskih, my understanding is that surrounding the whole thing by __try/__except

should be able prevent reading memory paged out to disk

Since METHOD_NEITHER accesses are mandated to be < DISPATCH, paging is not an issue at all.

Only unresolved page faults (i.e. stray pointers) are the issue, and they are caught by __try/__except.

So, the rules are a) be in the correct process context b) use __try/__except. Nothing else.

MmProbeAndLockPages().

Well, this is the call you use to create a MDL with these pages.

MDLs are not by-pointer accesses and not related to the latter. MDLs are only used for:

a) to map the pages to system PTEs
b) to pass it down to the stack which wants MDLs
c) to build a subrange MDL from the range MDL (and usually pass it down to the stack which wants MDLs)
d) to do DMA

Nothing else.

Also note that, even though MDLs are not by-pointer access, MmProbeAndLockPages MUST be surrounded by __try/__except.


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

> Since METHOD_NEITHER accesses are mandated to be < DISPATCH, paging

is not an issue at all.

Only unresolved page faults (i.e. stray pointers) are the issue, and
they are caught by __try/__except.

So, the rules are a) be in the correct process context
b) use __try/__except. Nothing else.

Also

c) Use ProbeForRead/ProbeForWrite before accessing the buffer and any embedded pointers.

d) Be aware that the app can change the contents of the buffer at any time. If necessary, capture values to stack/pool memory to avoid TOCTOU issues.

Or just use METHOD_BUFFERED instead and let the system probe and capture the buffer for you. Much simpler (assuming you don’t have embedded pointers).