バッファーのサイズの確認エラー
バッファー化された I/O を実装する IOCTL と FSCTL を処理するとき、ドライバーは常に入力バッファーと出力バッファーのサイズをチェックし、バッファーが要求されたすべてのデータを確実に保持できるようにする必要があります。 要求で FILE_ANY_ACCESS が指定されている場合、ほとんどのドライバー IOCTL と FSCTL と同様、デバイスへのハンドルを持つ呼び出し元は、そのデバイスのバッファー内の IOCTL または FSCTL 要求にアクセスでき、バッファーの末尾を超えてデータを読み書きできます。
入力バッファー サイズ
たとえば、ディスパッチ ルーチンから呼び出されるルーチンに以下のコードが表示され、ドライバーが IRP で渡されたバッファー サイズを検証していないとします。
switch (ControlCode)
...
...
case IOCTL_NEW_ADDRESS:{
tNEW_ADDRESS *pNewAddress =
pIrp->AssociatedIrp.SystemBuffer;
pDeviceContext->Addr = RtlUlongByteSwap (pNewAddress->Address);
この例では、代入ステートメントの前でバッファー サイズをチェックしません (強調表示されています)。 その結果、次の行の pNewAddress->Address 参照は、入力バッファーが tNEW_ADDRESS 構造を格納するのに十分な大きさでない場合にエラーが発生する可能性があります。
以下のコードは、潜在的な問題を回避するため、バッファー サイズをチェックします。
case IOCTL_NEW_ADDRESS: {
tNEW_ADDRESS *pNewAddress =
pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(tNEW_ADDRESS)) {
pDeviceContext->Addr = RtlUlongByteSwap (pNewAddress->Address);
可変サイズ バッファーを使用する WMI 要求など、バッファー内の他の I/O を処理するコードでも、同様のエラーが発生する可能性があります。
出力バッファー サイズ
出力バッファーの問題は、入力バッファーの問題に似ています。 プールが簡単に破損する可能性があります。ユーザー モードの呼び出し元は、エラーが発生したことを認識できない可能性があります。
以下の例では、ドライバーが SystemBuffer のサイズをチェックできません。
case IOCTL_GET_INFO: {
Info = Irp->AssociatedIrp.SystemBuffer;
Info->NumIF = NumIF;
...
...
Irp->IoStatus.Information =
NumIF*sizeof(GET_INFO_ITEM)+sizeof(ULONG);
Irp->IoStatus.Status = ntStatus;
}
システム バッファーの NumIF フィールドで入力項目の数が指定されていると仮定すると、この例では、IoStatus.Information が出力バッファーより大きい値に設定されるため、ユーザー モード コードに大量の情報が返される可能性があります。 アプリケーションが不適切にコーディングされていて、呼び出しの出力バッファーが小さすぎる場合、上記のコードは、システム バッファーの末尾を超えて書き込むことによりプールを破損する可能性があります。
I/O マネージャーでは、情報フィールドの値が有効であると見なされている点に注意してください。 呼び出し元が出力バッファーの有効なカーネル モード アドレスと 0 バイトのサイズを渡した場合、ドライバーが出力バッファー サイズをチェックせずに、エラーが見つかると、重大な問題が発生する可能性があります。