Condividi tramite


Errore di verifica delle dimensioni dei buffer

Quando si gestiscono IOCTLs e FSCTLs che implementano I/O buffer memorizzati nel buffer, un driver deve sempre controllare le dimensioni dei buffer di input e di output per garantire che i buffer possano contenere tutti i dati richiesti. Se la richiesta specifica FILE_ANY_ACCESS, come la maggior parte dei driver IOCTLs e FSCTLs, qualsiasi chiamante che dispone di un handle per il dispositivo ha accesso a richieste IOCTL o FSCTL memorizzate nel buffer e potrebbe leggere o scrivere dati oltre la fine del buffer.

Dimensioni del buffer di input

Si supponga, ad esempio, che il codice seguente venga visualizzato in una routine chiamata da una routine Dispatch e che il driver non abbia convalidato le dimensioni del buffer passate nell'IRP:

   switch (ControlCode)
      ...
      ...
      case IOCTL_NEW_ADDRESS:{
         tNEW_ADDRESS *pNewAddress = 
            pIrp->AssociatedIrp.SystemBuffer;

         pDeviceContext->Addr = RtlUlongByteSwap (pNewAddress->Address);

L'esempio non controlla le dimensioni del buffer prima dell'istruzione di assegnazione (evidenziata). Di conseguenza, il riferimento pNewAddress-Address> nella riga successiva può essere danneggiato se il buffer di input non è abbastanza grande per contenere una struttura tNEW_ADDRESS.

Il codice seguente controlla le dimensioni del buffer, evitando il potenziale problema:

   case IOCTL_NEW_ADDRESS: {
      tNEW_ADDRESS *pNewAddress =
         pIrp->AssociatedIrp.SystemBuffer;

      if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength >=
             sizeof(tNEW_ADDRESS)) {
         pDeviceContext->Addr = RtlUlongByteSwap (pNewAddress->Address);

Il codice per gestire altre operazioni di I/O con buffer, ad esempio richieste WMI che usano buffer di dimensioni variabili, può avere errori simili.

Dimensioni del buffer di output

I problemi del buffer di output sono simili ai problemi del buffer di input. Possono facilmente danneggiare il pool e i chiamanti in modalità utente potrebbero non essere consapevoli che si è verificato un errore.

Nell'esempio seguente il driver non riesce a controllare le dimensioni di 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;
   }

Supponendo che il campo NumIF del buffer di sistema specifica il numero di elementi di input, questo esempio può impostare IoStatus.Information su un valore maggiore del buffer di output e quindi restituire troppe informazioni al codice in modalità utente. Se un'applicazione viene codificata in modo errato e le chiamate con un buffer di output troppo piccolo, il codice precedente potrebbe danneggiare il pool scrivendo oltre la fine del buffer di sistema.

Tenere presente che il gestore di I/O presuppone che il valore nel campo Informazioni sia valido. Se un chiamante passa in un indirizzo in modalità kernel valido per il buffer di output e una dimensione pari a zero byte, i problemi gravi possono verificarsi se il driver non controlla le dimensioni del buffer di output e quindi trova l'errore.