썽킹이 필요한 이유
커널 모드 드라이버는 사용자 모드 애플리케이션에서 전달된 모든 I/O 버퍼의 크기를 확인해야 합니다. 32비트 애플리케이션이 포인터 정밀도 데이터 형식이 포함된 버퍼를 64비트 드라이버에 전달하고 썽킹이 발생하지 않는 경우 드라이버는 버퍼가 실제로보다 클 것으로 예상합니다. 포인터 정밀도는 32비트 Microsoft Windows에서 32비트, 64비트 Windows에서는 64비트이기 때문입니다. 예를 들어 다음 구조 정의를 고려합니다.
typedef struct _DRIVER_DATA
{
HANDLE Event;
UNICODE_STRING ObjectName;
} DRIVER_DATA;
32비트 Windows에서 DRIVER_DATA 구조체의 크기는 12바이트입니다. 다음 표에서는 DRIVER_DATA 구조체의 Event 멤버 및 ObjectName 멤버의 크기를 보여 줍니다.
이벤트 | ObjectName(USHORT 길이) | ObjectName(USHORT 최대 길이) | ObjectName(PWSTR 버퍼) |
---|---|---|---|
32비트 | 16비트 | 16비트 | 32비트 |
(4바이트) | (2바이트) | (2바이트) | (4바이트) |
64비트 Windows에서 DRIVER_DATA 구조체의 크기는 24바이트입니다. 버 퍼 멤버를 8바이트 경계에 맞출 수 있도록 4바이트 구조 패딩이 필요합니다.
이벤트 | ObjectName(USHORT 길이) | ObjectName(USHORT 최대 길이) | 비어 있음(구조 패딩) | ObjectName(PWSTR 버퍼) |
---|---|---|---|---|
64비트 | 16비트 | 16비트 | 32비트 | 64비트 |
(8바이트) | (2바이트) | (2바이트) | (4바이트) | (8바이트) |
64비트 드라이버가 24바이트를 예상할 때 12바이트의 DRIVER_DATA 받으면 크기 유효성 검사가 실패합니다. 이를 방지하려면 드라이버는 DRIVER_DATA 구조가 32비트 애플리케이션에서 전송되었는지 여부를 감지해야 하며, 이 경우 유효성 검사를 수행하기 전에 적절하게 썽크해야 합니다.
예를 들어 위의 DRIVER_DATA 구조체의 썽크된 버전은 다음과 같이 정의할 수 있습니다.
typedef struct _DRIVER_DATA32
{
VOID *POINTER_32 Event;
UNICODE_STRING32 ObjectName;
} DRIVER_DATA32;
고정 정밀도 데이터 형식만 포함하기 때문에 이 새로운 구조는 32비트 Windows 및 64비트 Windows에서 동일한 크기입니다.
이벤트 | ObjectName(USHORT 길이) | ObjectName(USHORT 최대 길이) | ULONG 버퍼 |
---|---|---|---|
32비트 | 16비트 | 16비트 | 32비트 |
(4바이트) | (2바이트) | (2바이트) | (4바이트) |