Why Thunking Is Necessary
Kernel-mode drivers must validate the size of any I/O buffer passed in from a user-mode application. If a 32-bit application passes a buffer containing pointer-precision data types to a 64-bit driver, and no thunking takes place, the driver will expect the buffer to be larger than it actually is. This is because pointer precision is 32 bits on 32-bit Microsoft Windows and 64 bits on 64-bit Windows. For example, consider the following structure definition:
typedef struct _DRIVER_DATA
{
HANDLE Event;
UNICODE_STRING ObjectName;
} DRIVER_DATA;
On 32-bit Windows, the size of the DRIVER_DATA structure is 12 bytes. This table shows the sizes of the Event member and ObjectName members of the DRIVER_DATA structure:
Event | ObjectName (USHORT Length) | ObjectName (USHORT Maximum Length) | ObjectName (PWSTR Buffer) |
---|---|---|---|
32 bits | 16 bits | 16 bits | 32 bits |
(4 bytes) | (2 bytes) | (2 bytes) | (4 bytes) |
On 64-bit Windows, the size of the DRIVER_DATA structure is 24 bytes. (The 4 bytes of structure padding are required so that the Buffer member can be aligned on an 8-byte boundary.)
Event | ObjectName (USHORT Length) | ObjectName (USHORT Maximum Length) | Empty (Structure Padding) | ObjectName (PWSTR Buffer) |
---|---|---|---|---|
64 bits | 16 bits | 16 bits | 32 bits | 64 bits |
(8 bytes) | (2 bytes) | (2 bytes) | (4 bytes) | (8 bytes) |
If a 64-bit driver receives 12 bytes of DRIVER_DATA when it expected 24 bytes, the size validation will fail. To prevent this, the driver must detect whether a DRIVER_DATA structure was sent by a 32-bit application, and if so, thunk it appropriately before performing the validation.
For example, a thunked version of the above DRIVER_DATA structure could be defined as follows:
typedef struct _DRIVER_DATA32
{
VOID *POINTER_32 Event;
UNICODE_STRING32 ObjectName;
} DRIVER_DATA32;
Because it contains only fixed-precision data types, this new structure is the same size on 32-bit Windows and 64-bit Windows.
Event | ObjectName (USHORT Length) | ObjectName (USHORT Maximum Length) | ULONG Buffer |
---|---|---|---|
32 bits | 16 bits | 16 bits | 32 bits |
(4 bytes) | (2 bytes) | (2 bytes) | (4 bytes) |