Details
-
Bug
-
Resolution: Unresolved
-
Major
-
None
Description
Problem:
The syscall interface is aware of the number of parameters a function receives, and copies them to kernel space as necessary. It is not aware of each function's return type, though, and always returns the contents of the EAX register (or equivalent on other architectures) to user mode. If the prototype of a syscall function (Nt*/Zw*) specifies a return type smaller than 32 bits, the compiler may leave the unused high-order bits untouched. This may leak privileged kernel information to user mode, and must thus be avoided.
NB: returning 32 bit values on x64 is less of (not?) a problem because setting the EAX register will automatically zero out the top 32 bits of RAX. Not sure about ARM64/IA64
See: http://j00ru.vexillium.org/?p=762
Fix approach:
- Create a simple test for each function that calls it with a prototype that returns a 32 bit value and show that the upper bits are always 0 on Windows
- Change the function prototype to an equivalent 32 bit type
Incomplete list of functions known to be problematic (please add if you find more):
NtUserDestroyAcceleratorTable (BOOLEAN)
NtUserDestroyWindow (BOOLEAN)
NtUserGetAsyncKeyState (SHORT)
NtUserGetKeyState (SHORT)
NtUserGetTitleBarInfo (BOOLEAN)
NtUserNotifyWinEvent (VOID)
NtUserRegisterClassExWOW (RTL_ATOM)
NtUserSetClassWord (WORD)
NtUserSetWindowWord (WORD)
Note that BOOL is a 32 bit type and thus okay, while BOOLEAN is 8 bit and problematic in this context. Also note that returning VOID is equally as problematic as a small type – the full 32 bits would be leaked in this case.