What is kernel mode?


Posted by: Sue Loh


I’ve talked about this before but I want to really highlight it because I still see people wrestling with it.


In Windows CE 5.0 and earlier, “kernel mode” is an access level attached to a thread.  If a thread is “in kernel mode” it can access kernel address space.  You could call SetKMode to put your thread into or out of kernel mode, whenever you wanted (it required trust, of course).  Most system APIs were not implemented by the kernel (nk.exe), so calling an API didn’t put your thread into kernel mode.  Unless you called an API that was implemented by nk.exe, in which case your thread would temporarily enter kernel mode for the duration of the call.


In Windows CE 6.0 the implementation is actually the same, except that the SetKMode API is no longer supported.  You can’t put threads into or out of kernel mode at a time of your choice.  However, most system APIs are implemented by modules that are now loaded into the kernel process, so calling an API usually puts your thread into kernel mode.


While the implementation is the same, the result is effectively different meanings.  In CE 5.0, “kernel mode” was a property a thread could acquire or release on demand.  In CE 6.0, the rule is fairly simple: your thread is in kernel mode while executing code inside the kernel process, and not in kernel mode when executing code inside a user process.  We use the term loosely, like talking about “kernel mode drivers,” “kernel mode code” and “kernel mode addresses.” Whenever people use these phrases they’re trying to talk about code and addresses that are only accessible to the kernel process, that are at addresses above 0x80000000.  (Side note, you also have to be clear about whether you’re talking about everything inside the kernel process vs. only the kernel module, kernel.dll.)


The one remaining gotcha in the CE 6.0 rule is callbacks.  If a user application passes a function pointer to kernel mode code, and the kernel mode code calls the function pointer directly, then the thread is STILL in kernel mode (remember it is still a property of the thread, just not so obviously) while executing user mode code.  And that is very bad for security.  Because the user mode code could do anything; it could access kernel addresses or call kernel-only APIs.  If you write a driver that takes a function pointer from the caller and later calls it, make sure your driver only does so by using the new CEDDK function, CeDriverPerformCallback.  That way your thread jumps back to the user process properly before calling the function, so that the function call can’t do anything that the user process itself couldn’t do already.  Or even better — find a different way to implement what you’re doing.  Ask yourself this: if an attacker passed me an evil function pointer, could they get me to do something bad on their behalf?  If you don’t know the answer, don’t take function pointers from your callers.


You might wonder about function pointers and memory marshalling.  “Marshalling” only applies to passing data buffers between processes — not to passing function pointers between processes.  You can’t “marshal” a function so that you can safely call it from kernel code.  The CeDriverPerformCallback function is the only way to shed the privileges that a kernel mode driver has, for the duration of the call.  I suppose you could consider that a form of “marshalling” but I don’t.


 


UPDATE Jan 31, 2007: Andrew Tuck, one of our support engineers, pointed out another detail that can lead to confusion.  (Thanks, Andrew!)  Often (at least in Windows environments, if not all OS’), the most privileged processor mode is referred to as “kernel mode.”  This usage of the term refers to when the CPU is operating with additional privileges, such as the ability to call special instructions that aren’t normally legal.  For example interrupt handling often happens in this CPU “kernel mode.”  This terminology is unrelated to the “kernel mode” concept I’ve been talking about in this article.  When a Windows CE thread is in “kernel mode” it is not running in the most privileged processor mode.  Only very restricted parts of the CE kernel and OAL run in that mode.  The Windows CE “kernel mode” thread property controls whether the page tables for kernel address space are mapped, and some other things. (For example, in CE 5.0 it controlled whether the thread could make fast-path API calls, like I described in the API call post I wrote a while back.)

Comments (5)

  1. Mukesh Modi says:

    Nice article

    thank you very much loh

  2. TM Ningen says:

    I actually have a question about the safety of 5.0 kernel mode. It looks like when an (untrusted) app makes a system call, e.g., FS_CreateFileW, the thread will execute in kernel mode (or with the premission of a priviledged process) but still uses the user stack. I presume the user stack is writable by the user code, since it lives in the application’s "memory slot".

    Wouldn’t it be possible for the user application to corrupt the stack (using another concurrent user thread) while one of its threads is in a system call? This seems quite scary to me. If you manage to modify a return address, you can start executing in kernel mode (or at least with the permissions of filesys.exe, in the case of FS_CreateFileW).

  3. ce_base says:

    Excellent question!

    I haven’t actually mentioned this fact before, but when a thread "jumps" into a system process to call an API, the kernel actually allocates a new stack inside the system process in order to execute the API call.  To prevent the caller from tampering with the stack asynchronously during the API call.  It switches back to the caller’s stack when the API call returns.

    This was not always true.  I had to ask Bor-Ming, our primary kernel developer, about it, and he tells me that this stack-switching was added in Windows CE 4.0.

    Sue

  4. Dean Ramsier says:

    Actually, in CE kernel mode threads do run with elevated processor privileges although you’re correct in saying that’s not how the term is normally used in CE.

    Exactly how kernel mode is implemented is processor architecture dependent.  On ARM processors, all processor modes except for the user mode are privileged.  The different privileged modes are not more or less privileged than the others, they are just different modes that allow fast switching between different contexts (interrupts, exceptions etc).  The privileged modes allow the caller to execute instructions that aren’t valid in the normal user mode.

    The vast majority of the time we are correct in saying that "kernel mode" just means having privileges in the upper 2GB of memory space, but there really is more to it than that and the differences are cpu architecture specific.  

    Regards,

    Dean

  5. ce_base says:

    Fair enough, thanks for the correction Dean!

    Sue