サンキングが必要な理由

カーネル モード ドライバーは、ユーザー モード アプリケーションから渡されるすべての 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 バイト)