The new 1-bit exploit of "all" windows versions uses a bug in the kernel code that handles scrollbars. That got me thinking. Why does windows handle scrollbars in kernel, rather than user mode? Historical reasons? Does any other OS do this?
-
1The server side of USER32 and GDI32 used to run in user mode. It was hosted in the client-server subsystem process, CSRSS.EXE, which runs as the SYSTEM account. NT 4 moved them to kernel mode (win32k.sys) for performance reasons. – Eryk Sun Feb 15 '15 at 23:19
-
1IIRC, Microsoft also claimed it simplified the way in which transitions from user-mode to kernel-mode occurred during GUI operation. Apparently the graphics subsystem prior to NT 4 had specially paired user-mode and kernel-mode threads and there was some custom mechanism for the transition from one to the other. Apparently it was difficult to prove security properties for this transition, and getting rid of it made the certification process easier. (I'm not sure which certification they were going for at the time; might have been Orange Book.) – Harry Johnston Feb 16 '15 at 03:12
1 Answers
TL;DR: Microsoft sacrificed security for performance.
Scrollbars are a bit special on Windows. Most scrollbars are not real windows but are implemented as decorations on the "parent" window. This leads us to a more general question; why are windows implemented in kernel mode on Windows?
Lets look at the alternatives:
- Per-process in user mode.
- Single "master" process in user mode.
Alternative 1 has a big advantage when dealing with your own windows; no context switch/kernel transition. The problem is of course that windows from different processes live on the same screen and somebody has to be responsible for deciding which window is active and coordinate changes when the user switches to a different window. This somebody would have to be a special system process or the kernel because this information cannot be per-process, it has to be stored somewhere global. This dual information design is going to be complicated because the per-process information cannot be trusted by the global window manager. I'm sure there are a ton of other downsides to this theoretical design but I'm not going to spend more time on it here.
Windows NT 3 implemented a variant of alternative 2. The window manager was moved into kernel mode in NT 4 mainly for performance reasons:
...the Window Manager (USER) and Graphics Device Interface (GDI) have been moved from the Win32 subsystem to the Windows NT Executive. Win32 user-mode device drivers, including graphics display and printer drivers, have also been moved to the Executive. These changes are designed to simplify graphics handling, reduce memory requirements, and improve performance.
...and further down in the same document there are more technical details and justifications:
When Windows NT was first designed, the Win32 environment subsystem was designed as a peer to the environment subsystems supporting applications in MS-DOS, POSIX, and OS/2. However, applications and other subsystems needed to use the graphics, windowing, and messaging functions in the Win32 subsystem. To avoid duplicating these functions, the Win32 subsystem was used as a server for graphics functions to all subsystems.
This design worked respectably for Windows NT 3.5 and 3.51, but it underestimated the volume and frequency of graphics calls. Having functions as basic as messaging and window control in a separate process generated substantial memory overhead from client/server message passing, data gathering, and managing multiple threads. It also required multiple context switches, which consume CPU cycles as well as memory. The volume of graphics support calls per second degraded the performance of the system. It was clear that a redesign of this facet in Windows NT 4.0 could reclaim these wasted system resources and improve performance.
The other subsystems are not that relevant these days but the performance issues remain.
If we look at a simple function like IsWindowVisible then there is not a lot of overhead when the window manager is in kernel mode: The function will execute a couple of instructions in user mode and then switch the CPU to ring 0 where the entire operation (validate the window handle passed in and if valid, retrieve the visible property) is performed in kernel mode. It then switches back to user mode and that is about it.
If the window manager lives in another process then you will at least double the amount of kernel transitions and you must somehow pass the functions input and output to and from the window manager process and you must somehow cause the window manager process to execute while you wait for the result. NT 3 did this by using a combination of shared memory, LPC and a obscure feature called paired threads.

- 97,548
- 12
- 110
- 164