次の方法で共有


バッファーのサイズの確認エラー

バッファー化された 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 バイトのサイズを渡した場合、ドライバーが出力バッファー サイズをチェックせずに、エラーが見つかると、重大な問題が発生する可能性があります。