Fehler beim Überprüfen der Größe von Puffern

Bei der Behandlung von IOCTLs und FSCTLs, die gepufferte E/A-Vorgänge implementieren, sollte ein Treiber immer die Größen der Eingabe- und Ausgabepuffer überprüfen, um sicherzustellen, dass die Puffer alle angeforderten Daten enthalten können. Wenn die Anforderung FILE_ANY_ACCESS angibt, wie die meisten Treiber-IOCTLs und FSCTLs, hat jeder Aufrufer, der über ein Handle für das Gerät verfügt, Zugriff auf gepufferte IOCTL- oder FSCTL-Anforderungen für dieses Gerät und kann Daten über das Ende des Puffers hinaus lesen oder schreiben.

Eingabepuffergröße

Angenommen, der folgende Code wird in einer Routine angezeigt, die von einer Dispatch-Routine aufgerufen wird, und dass der Treiber die im IRP übergebenen Puffergrößen nicht überprüft hat:

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

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

Im Beispiel werden die Puffergrößen vor der Zuweisungsanweisung (hervorgehoben) nicht überprüft. Daher kann der pNewAddress-Address-Verweis> in der nächsten Zeile fehlerbehaftet sein, wenn der Eingabepuffer nicht groß genug ist, um eine tNEW_ADDRESS-Struktur zu enthalten.

Der folgende Code überprüft die Puffergrößen, um das potenzielle Problem zu vermeiden:

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

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

Code zum Verarbeiten anderer gepufferter E/A-Vorgänge, z. B. WMI-Anforderungen, die Puffer für variable Größe verwenden, kann ähnliche Fehler aufweisen.

Ausgabepuffergröße

Ausgabepufferprobleme ähneln Eingabepufferproblemen. Sie können den Pool leicht beschädigen, und Benutzermodusaufrufer wissen möglicherweise nicht, dass ein Fehler aufgetreten ist.

Im folgenden Beispiel kann der Treiber die Größe des SystemBuffer nicht überprüfen:

   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;
   }

Unter der Annahme, dass das Feld NumIF des Systempuffers die Anzahl der Eingabeelemente angibt, kann ioStatus.Information in diesem Beispiel auf einen Wert festgelegt werden, der größer als der Ausgabepuffer ist und somit zu viele Informationen an den Benutzermoduscode zurückgeben. Wenn eine Anwendung falsch codiert ist und mit einem zu kleinen Ausgabepuffer aufruft, kann der vorherige Code den Pool beschädigen, indem er über das Ende des Systempuffers hinaus schreibt.

Denken Sie daran, dass der E/A-Manager davon ausgeht, dass der Wert im Feld Information gültig ist. Wenn ein Aufrufer eine gültige Kernelmodusadresse für den Ausgabepuffer und eine Größe von null Bytes übergibt, können schwerwiegende Probleme auftreten, wenn der Treiber die Ausgabepuffergröße nicht überprüft und somit den Fehler findet.