サンキングが必要な理由
カーネル モード ドライバーは、ユーザー モード アプリケーションから渡されるすべての 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 Length) | ObjectName (USHORT の最大長) | ObjectName (PWSTR バッファー) |
---|---|---|---|
32 ビット | 16 ビット | 16 ビット | 32 ビット |
(4 バイト) | (2 バイト) | (2 バイト) | (4 バイト) |
64 ビット Windows では、DRIVER_DATA 構造体のサイズは 24 バイトです。 (構造体のパディングの 4 バイトが必要です。 バッファー メンバーは、8 バイトの境界に配置できます)。
イベント | ObjectName (USHORT Length) | 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 Length) | ObjectName (USHORT の最大長) | ULONG バッファー |
---|---|---|---|
32 ビット | 16 ビット | 16 ビット | 32 ビット |
(4 バイト) | (2 バイト) | (2 バイト) | (4 バイト) |