Condividi tramite


Errore di convalida dei buffer Variable-Length

I driver spesso accettano buffer di input con intestazioni fisse e dati di lunghezza variabile finale, come nell'esempio seguente:

   typedef struct _WAIT_FOR_BUFFER {
      LARGE_INTEGER Timeout;
      ULONG NameLength;
      BOOLEAN TimeoutSpecified;
      WCHAR Name[1];
   } WAIT_FOR_BUFFER, *PWAIT_FOR_BUFFER;

   if (InputBufferLength < sizeof(WAIT_FOR_BUFFER)) {
      IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
      return( STATUS_INVALID_PARAMETER );
   }

   WaitBuffer = Irp->AssociatedIrp.SystemBuffer;

   if (FIELD_OFFSET(WAIT_FOR_BUFFER, Name[0]) +
          WaitBuffer->NameLength > InputBufferLength) {
       IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
       return( STATUS_INVALID_PARAMETER );
   }

Se WaitBuffer-NameLength> è un valore ULONG molto grande, l'aggiunta all'offset potrebbe causare un overflow integer. Al contrario, un driver deve sottrarre l'offset (dimensione dell'intestazione fissa) da InputBufferLength (dimensioni del buffer) e verificare se il risultato lascia spazio sufficiente per WaitBuffer-NameLength> (dati di lunghezza variabile), come nell'esempio seguente:

   if (InputBufferLength < sizeof(WAIT_FOR_BUFFER)) {
      IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
      Return( STATUS_INVALID_PARAMETER );
   }

   WaitBuffer = Irp->AssociatedIrp.SystemBuffer;

   if ((InputBufferLength -
         FIELD_OFFSET(WAIT_FOR_BUFFER, Name[0])  <
         WaitBuffer->NameLength) {
      IoCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
      return( STATUS_INVALID_PARAMETER );
   }

In altre parole, se la dimensione del buffer meno la dimensione dell'intestazione fissa lascia meno del numero di byte necessari per i dati a lunghezza variabile, viene restituito un errore.

La sottrazione precedente non può essere sottoposta a underflow perché la prima istruzione if garantisce che InputBufferLength sia maggiore o uguale alla dimensione di WAIT_FOR_BUFFER.

Di seguito viene illustrato un problema di overflow più complesso:

   case IOCTL_SET_VALUE:
      dwSize = sizeof(SET_VALUE);

      if (inputBufferLength < dwSize) {
         ntStatus = STATUS_BUFFER_TOO_SMALL;
         break;
      }

      dwSize = FIELD_OFFSET(SET_VALUE, pInfo[0]) +
                  pSetValue->NumEntries * sizeof(SET_VALUE_INFO);

      if (inputBufferLength < dwSize) {
         ntStatus = STATUS_BUFFER_TOO_SMALL;
         break;
      }

In questo esempio, un overflow integer può verificarsi durante la moltiplicazione. Se la dimensione della struttura SET_VALUE_INFO è un multiplo di 2, un valore NumEntries , ad esempio 0x80000000 genera un overflow, quando i bit vengono spostati a sinistra durante la moltiplicazione. Tuttavia, le dimensioni del buffer superano comunque il test di convalida, perché l'overflow causa la visualizzazione di dwSize piuttosto piccola. Per evitare questo problema, sottrarre le lunghezze come nell'esempio precedente, dividere per sizeof(SET_VALUE_INFO) e confrontare il risultato con NumEntries.