PsCreateSystemThread and the caller's process context

Hello,

Microsoft’s documentation of PsCreateSystemThread states:
“Drivers for Windows 2000 […] must call PsCreateSystemThread only from the system process context.”

If I want to keep NT 5.0 compatibility, but cannot guarantee running in SYSTEM context, is this a sufficient solution?

KeStackAttachProcess(PsInitialSystemProcess, &ApcState);
PsCreateSystemThread(…);
KeUnstackDetachProcess(&ApcState);

KeStackAttachProcess requires PKPROCESS type, but PsInitialSystemProcess is PEPROCESS.
However, EPROCESS’ first member is a KPROCESS structure, but I wouldn’t treat it as opaque then.

Thanks.

A work-item always runs in the System context. You can always queue a
work-item to create your thread.

Other activities also occur in the System context explicitly. I recall that
loading a driver is one of these so DriverEntry is always guaranteed to be
executed in the System context (If I recall correctly, that is).

So without knowing just where in the life-cycle of your driver you are in
need of creating this thread, it is hard to say exactly how to achieve being
in the System context.

I also recall that the Parallel Port drivers create a worker thread. You
might study this to determine how it meets these requirements.

Good Luck,
Dave Cattley

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hushmail.com
Sent: Tuesday, July 31, 2007 9:48 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] PsCreateSystemThread and the caller’s process context

Hello,

Microsoft’s documentation of PsCreateSystemThread states:
“Drivers for Windows 2000 […] must call PsCreateSystemThread only from the
system process context.”

If I want to keep NT 5.0 compatibility, but cannot guarantee running in
SYSTEM context, is this a sufficient solution?

KeStackAttachProcess(PsInitialSystemProcess, &ApcState);
PsCreateSystemThread(…);
KeUnstackDetachProcess(&ApcState);

KeStackAttachProcess requires PKPROCESS type, but PsInitialSystemProcess is
PEPROCESS.
However, EPROCESS’ first member is a KPROCESS structure, but I wouldn’t
treat it as opaque then.

Thanks.


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

Thanks for your reply.

I have considered (and am still considering) using work items instead, but there are a few benefits from spawning my own thread(s), like priority control and exclusiveness.

The thread(s) will be spawned in my IOCTL dispatch routine which usually runs in the (user-mode) caller’s process context.

wrote in message news:xxxxx@ntdev…
> Thanks for your reply.
>
> I have considered (and am still considering) using work items instead,
> but there are a few benefits from spawning my own thread(s), like
> priority control and exclusiveness.
>
> The thread(s) will be spawned in my IOCTL dispatch routine which usually
> runs in the (user-mode) caller’s process context.

Thread creation is a fairly heavyweight operation. Many drivers do the
creation at DriverEntry or AddDevice time, and then just pend the threads
till needed.


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

Don Burn wrote:

Thread creation is a fairly heavyweight operation.

I use the device control request to make the driver read user-supplied registry settings.
In accordance with some of these settings, the driver will need up to 16 threads for its exclusive, long-term usage.

The actual number of required threads depends on the settings, so I wanted to spawn only as many of them as needed without leaving the majority idling.

Sixteen may sound much, but this is only the most extreme scenario. I expect the number to be between 0 and 3 for common usage.

The suggestion is not to substitute your threads for work items, but
rather queue one work item and then create your threads from the work
item. The work item is guaranteed to be in the system context when it
runs. By using the work item, you don’t have the very expensive
operation of attaching to the system process nor do you have to get a
PKPROCESSS through undocumented means.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@hushmail.com
Sent: Tuesday, July 31, 2007 7:37 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] PsCreateSystemThread and the caller’s process
context

Thanks for your reply.

I have considered (and am still considering) using work items instead,
but there are a few benefits from spawning my own thread(s), like
priority control and exclusiveness.

The thread(s) will be spawned in my IOCTL dispatch routine which usually
runs in the (user-mode) caller’s process context.


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

Alyah Nihal wrote:

Microsoft’s documentation of PsCreateSystemThread states:
“Drivers for Windows 2000 […] must call PsCreateSystemThread only from the
system process context.”

I’m not sure the docs are correct. If you check old DDK versions you will see that this limitation is not mentioned. I asked about this some time ago in the managed newsgroup. I couldn’t get an authoritative answer.

My guess it is either a doc err (and the limitation should be for Win 98 only), or it was later found that there is a bug in W2k (say, it does work when invoked from a non-system context but it could expose a security hole).

Ah… this is often mis-understood. It’s a problem of naming.

The docs stating you must call PsCreateSystemThread in the system context are trying to save you from “doing the wrong thing” unintentionally. While there’s no prohibition against creating a system thread in process context, you best be sure that’s what you want… most people expect a “system thread” to always execute in the context of the system process, and to do this, the thread must be created in that context.

Let’s start with what a “system thred” is… it’s a thread that doesn’t have any user-mode context associated with it. Thus, it’s a kernel-mode only thread. A “system thread” as created by PsCreateSystemThread, must be associated with some process. It is NOT automatically associated with the system process.

If you call PsCreateSystemThread in the context of a specific process, that thread becomes part of the process in which the thread was created. This carries with it all that “process context” implies – memory mapping in the low half of Kernel Virtual address space, for example.

Moral of the story: If you want a thread that always runs in the context of the system process, you need to call PsCreateSystemThread in the context of the system process. As Don, I believe, suggested earlier, the place to do this is in DriverEntry or AddDevice, both of which are architecturally guaranteed to be called in the context of the system process.

Peter
OSR

> Other activities also occur in the System context explicitly. I recall that

loading a driver is one of these so DriverEntry is always guaranteed to be
executed in the System context (If I recall correctly, that is).

Yes.

So are most PnP IRPs and AddDevice - see the particular PnP IRP docs.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Peter Viscarola (OSR) wrote:

Let’s start with what a “system thred” is… it’s a thread that doesn’t have any
user-mode context associated with it. Thus, it’s a kernel-mode only thread. A
“system thread” as created by PsCreateSystemThread, must be associated with some
process. It is NOT automatically associated with the system process.

If you call PsCreateSystemThread in the context of a specific process, that
thread becomes part of the process in which the thread was created. This
carries with it all that “process context” implies – memory mapping in the low
half of Kernel Virtual address space, for example.

Peter, that’s not what the docs claim. The docs claim that the created thread will be associated with the process specified in the “ProcessHandle” parameter. And if that parameter is NULL, it will be (according to the docs) automatically associated with the system process. Otherwise, what’s the purpose of the “ProcessHandle” parameter?

What the docs claim (and only in later versions), is that under W2k and W98 it must be called from the system process context. It *can be called in any context* in XP and later.

But again, it looks like a docerr or at least misleading. I am suspecting that what might be happening is, that if called under a non-system context in Win2K, it would work but it might expose a security hole (perhaps the OBJ_KERNEL_HANDLE attribute is ignored). Or may be the limitation is for Win98 only.

To add to this, this also means that you have to deal with things like the
process you created your thread in being terminated and other
unpleasantness. It is very often not the right thing to do due to this (and
other reasons). Also, neglecting to set OBJ_KERNEL_HANDLE while not running
in the system process and calling PsCreateSystemThread will open up an ugly
security hole (much like careless use of other handle creation functions in
a user process context).


Ken Johnson (Skywing)
Windows SDK MVP
http://www.nynaeve.net
wrote in message news:xxxxx@ntdev…
> Ah… this is often mis-understood. It’s a problem of naming.
>
> The docs stating you must call PsCreateSystemThread in the system context
> are trying to save you from “doing the wrong thing” unintentionally.
> While there’s no prohibition against creating a system thread in process
> context, you best be sure that’s what you want… most people expect a
> “system thread” to always execute in the context of the system process,
> and to do this, the thread must be created in that context.
>
> Let’s start with what a “system thred” is… it’s a thread that doesn’t
> have any user-mode context associated with it. Thus, it’s a kernel-mode
> only thread. A “system thread” as created by PsCreateSystemThread, must
> be associated with some process. It is NOT automatically associated with
> the system process.
>
> If you call PsCreateSystemThread in the context of a specific process,
> that thread becomes part of the process in which the thread was created.
> This carries with it all that “process context” implies – memory mapping
> in the low half of Kernel Virtual address space, for example.
>
> Moral of the story: If you want a thread that always runs in the context
> of the system process, you need to call PsCreateSystemThread in the
> context of the system process. As Don, I believe, suggested earlier, the
> place to do this is in DriverEntry or AddDevice, both of which are
> architecturally guaranteed to be called in the context of the system
> process.
>
> Peter
> OSR
>
>

Oh, sorry, Ijor… Typing too quickly and thinking too little. My mistake. How embarassing. Thanks for pointing this out.

The owning process definitely is defined by the handle… of course, you are correct.

That having been said, LOL… I don’t know what the issue is calling this function outside the system process context in Win2K. Never mind :slight_smile:

Gosh! Sometimes I wonder where my mind’s gone. Too many drivers, I suspect,

Peter
OSR

Peter,

Ah… this is often mis-understood. It’s a problem of naming.

The docs stating you must call PsCreateSystemThread in the system context are
trying to save you from “doing the wrong thing” unintentionally. While there’s
no prohibition against creating a system thread in process context, you best be
sure that’s what you want… most people expect a “system thread” to always
execute in the context of the system process, and to do this, the thread must be
created in that context.

Let’s start with what a “system thred” is… it’s a thread that doesn’t have any
user-mode context associated with it. Thus, it’s a kernel-mode only thread. A
“system thread” as created by PsCreateSystemThread, must be associated with some
process. It is NOT automatically associated with the system process.

If you call PsCreateSystemThread in the context of a specific process, that
thread becomes part of the process in which the thread was created. This
carries with it all that “process context” implies – memory mapping in the low
half of Kernel Virtual address space, for example.

Moral of the story: If you want a thread that always runs in the context of the
system process, you need to call PsCreateSystemThread in the context of the
system process.

I am afraid the above is not entirely correct…

Indeed, it is safer to create a kernel thread in context of the system process. However, context of a process that newly-created thread will belong to has nothing to do with a caller’s context. Instead, it is defined by ‘ProcessHandle’ parameter, which is optional - if you specify NULL, newly-created thread will run in context of a system process. The doc in question, indeed, tries to save you from “doing the wrong thing” unintentionally - it says that drivers should specify NULL for ‘ProcessHandle’ , and it says so in absolutely all versions of DDK, as well as in WDK.

Therefore, taking into account the above, W2K DDK’s statement that the OP has mentioned either means that under W2K newly-created threadalways runs in a caller context, regardless of ‘ProcessHandle’ parameter, or is nothing more than just another bug in W2K DDK documentation that got subsequently fixed in WDK.

I believe the latter is much more likely to be the case here…

Anton Bassov

Someone else can be more specific, but the caution about creating a worker
thread under Windows 2000, 98, & Me in any context other than the system
process still exists in the WDK 6000 docs.

On XP and later the OBJ_KERNEL_HANDLE bit can be used to keep even handles
created in a user process context from being accessed while in user mode. A
thread creates a handle to itself (ok, the OS creates the handle for the
thread) and allowing access to that handle from user mode does appear to
offer far too much of a security threat to be permissible. On XP and later
the OBJ_KERNEL_HANDLE can be used to create the thread where the process
context is -1 (current) and no user mode code can refer to that thread’s
handle.

Maybe those bits of info above are why the documentation reads as it does
and why Doron said to just schedule a work item to the system worker thread
queue where your own worker thread can be created for subsequent use. I
have found upon occasion to use a worker thread that runs in the context of
the user process, but it was only for testing and not release. I generally
avoid using the system worker threads and prefer to create my own as OSR
published in the NT Insider around 1998. NT4 had a major restriction on the
number available and if you use work items run by the system threads in the
storage stack especially you could deadlock the system. Not a good idea in
the file system stack either on NT4. Since I became proficient in creating
my own, I just prefer them and they remain dedicated to me for whenever I
need them.


David J. Craig
Engineer, Sr. Staff Software Systems
Broadcom Corporation

wrote in message news:xxxxx@ntdev…
> Peter,
>
>>Ah… this is often mis-understood. It’s a problem of naming.
>
>>The docs stating you must call PsCreateSystemThread in the system context
>>are
>> trying to save you from “doing the wrong thing” unintentionally. While
>> there’s
>> no prohibition against creating a system thread in process context, you
>> best be
>> sure that’s what you want… most people expect a “system thread” to
>> always
>> execute in the context of the system process, and to do this, the thread
>> must be
>> created in that context.
>
>> Let’s start with what a “system thred” is… it’s a thread that doesn’t
>> have any
>> user-mode context associated with it. Thus, it’s a kernel-mode only
>> thread. A
>> “system thread” as created by PsCreateSystemThread, must be associated
>> with some
>> process. It is NOT automatically associated with the system process.
>
>> If you call PsCreateSystemThread in the context of a specific process,
>> that
>> thread becomes part of the process in which the thread was created. This
>> carries with it all that “process context” implies – memory mapping in
>> the low
>> half of Kernel Virtual address space, for example.
>
>> Moral of the story: If you want a thread that always runs in the context
>> of the
>> system process, you need to call PsCreateSystemThread in the context of
>> the
>> system process.
>
>
> I am afraid the above is not entirely correct…
>
> Indeed, it is safer to create a kernel thread in context of the system
> process. However, context of a process that newly-created thread will
> belong to has nothing to do with a caller’s context. Instead, it is
> defined by ‘ProcessHandle’ parameter, which is optional - if you specify
> NULL, newly-created thread will run in context of a system process. The
> doc in question, indeed, tries to save you from “doing the wrong thing”
> unintentionally - it says that drivers should specify NULL for
> ‘ProcessHandle’ , and it says so in absolutely all versions of DDK, as
> well as in WDK.
>
> Therefore, taking into account the above, W2K DDK’s statement that the OP
> has mentioned either means that under W2K newly-created threadalways
> runs in a caller context, regardless of ‘ProcessHandle’ parameter, or is
> nothing more than just another bug in W2K DDK documentation that got
> subsequently fixed in WDK.
>
>
> I believe the latter is much more likely to be the case here…
>
> Anton Bassov
>
>
>
>

David,

Someone else can be more specific, but the caution about creating a worker
thread under Windows 2000, 98, & Me in any context other than the system
process still exists in the WDK 6000 docs.

Probably, you remember that we had discussed it few months ago. Back then we attributed the whole thing to a bug in MSDN (actually, I checked the docs and found out that the statement in question turned up only in WDK- W2K DDK documentation does not have it, so that my previous post is a bit imprecise). In our previous discussion the fact that this statement was missing in W2K DDK, combined W2K documentation’s suggestion that drivers should specify NULL for ‘ProcessHandle’, lead us to a conclusion that WDK documentation is, apparently, not correct on this issue…

Anton Bassov

David J. Craig wrote:

On XP and later the OBJ_KERNEL_HANDLE bit can be used to keep even handles
created in a user process context from being accessed while in user mode. A
thread creates a handle to itself (ok, the OS creates the handle for the
thread) and allowing access to that handle from user mode does appear to
offer far too much of a security threat to be permissible. On XP and later
the OBJ_KERNEL_HANDLE can be used to create the thread where the process
context is -1 (current) and no user mode code can refer to that thread’s
handle.

That’s a *possible* way to interpret it. But once you check the old (WIN2K) version of the DDK, then you are not sure anymore. And then you start suspecting that the whole thing might be a docerr.

According to the help files in the *WIN2K DDK*, OBJ_KERNEL_HANDLE can be specified. That is, the possibility of creating a kernel mode handle with this call, worked back then with WIN2K. It is not (according to these old docs) something new for XP and later.

So it is possible that it was actually a docerr in the old version. It is possible that it wasn’t a docerr, but there is some kind of bug in WIN2K that was found later. Or it is possible that it is a docerr in the newer WDK docs. It is very difficult to be sure without an authoritative answer from Microsoft.

I considered doing some tests under W2K, but then it won’t be too useful. If I find that it doesn’t work, I don’t gain anything (except some curiosity info). If I find it that it *appears* to work correctly, I still won’t be able to use it under WIN2K. I could never be sure it works 100% in every possible case and situation.

> I considered doing some tests under W2K,

Based upon my own experience, I can tell you that a call to PsCreateSystemThread() from non-system thread works just fine under W2K - a couple of years ago I worked on a project where a system thread had to be created in response to IOCTL that was originated the user app, i.e. to call PsCreateSystemThread() in context of a user thread. The whole thing was required to be working on all OS versions, starting from W2K SP0 up to XP SP2. It was thoroughly (and successfully) tested under all service packs of W2K, and did not pose a *slightest* problem anywhere…

Anton Bassov

Doron Holan wrote:

The suggestion is not to substitute your threads for work items,
but rather queue one work item and then create your threads
from the work item.

I misread your post, David R. Cattley. Sorry.
The idea of using work items for that purpose is quite neat, thanks.

Ijor wrote:

I’m not sure the docs are correct.

Yes, it’d be nice if this was indeed a wrong statement and I can safely create system threads running in SYSTEM context by calling PsCreateSystemThread in an arbitrary process context.

Of course, I could also choose the dull alternative and create my 16 threads in DriverEntry (or the first time in AddDevice), let all of them idle and never use most of them.

In this case, should the waste of resources be a concern?

Define “idle”. If WaitForSingleObject with a timeout of 250 ms or larger so
termination can be checked before waiting again, it should not be a
significant impact on the system. Having more than one thread or maybe two
per processor is not usually required, though there can be times when it is
a good idea. Try one per processor, then two, and then more and profile the
results. That should help you optimize the logic properly.

I do recommend that you save the handles so when you need to terminate your
worker threads you can ObReferenceObjectByHandle and do a wait on each of
them in succession. As the WFSO becomes satisfied, dereference the object
and close the handle. As long as the handle remains valid, the signal for
WFSO will occur immediately if the thread has already terminated, so I only
use one flag for all threads to exit.


David J. Craig
Engineer, Sr. Staff Software Systems
Broadcom Corporation

wrote in message news:xxxxx@ntdev…
> Doron Holan wrote:
>> The suggestion is not to substitute your threads for work items,
>> but rather queue one work item and then create your threads
>> from the work item.
>
> I misread your post, David R. Cattley. Sorry.
> The idea of using work items for that purpose is quite neat, thanks.
>
>
> Ijor wrote:
>> I’m not sure the docs are correct.
>
> Yes, it’d be nice if this was indeed a wrong statement and I can safely
> create system threads running in SYSTEM context by calling
> PsCreateSystemThread in an arbitrary process context.
>
>
>
> Of course, I could also choose the dull alternative and create my 16
> threads in DriverEntry (or the first time in AddDevice), let all of them
> idle and never use most of them.
>
> In this case, should the waste of resources be a concern?
>

I wouldn’t use a timeout, but would let them sleep indefinitely and wake them via KeSetEvent for termination.

I have 16 different events of which 8 (no order) can occur simultaneously.
This “can occur” is merely a possibility, not something I expect to happen very often (or at all).

Each thread would be dedicated to one event, but although I would enable parallel processing of events, only one event instance at a time would be allowed.
If, for example, thread 1 is currently processing event 1, and event 1 occurs again, the first instance of event 1 would be canceled and thread 1 would begin processing the new instance.

In my case, “processing events” means walking through an (variable) array of instructions and taking appropriate actions.
So, I could use one thread for all events. Every event would be granted one instruction before switching to the next array.
However, such an instruction could also include KeDelayExecutionThread for a small, but variable interval, which would then affect the processing of all events.
A solution could be a substitution of KeDelayExecutionThread with KeQueryInterruptTime, but this would essentially be a busy wait.
As you can the, the biggest problems are those intentional delays which could be desired.

I hope I was able to make myself clear.