Freigeben über


Fehler beim Überprüfen von Variable-Length Puffern

Treiber akzeptieren häufig Eingabepuffer mit festen Headern und nachgestellten Variablenlängendaten, wie im folgenden Beispiel gezeigt:

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

Wenn WaitBuffer-NameLength> ein sehr großer ULONG-Wert ist, kann das Hinzufügen zum Offset zu einem Ganzzahlüberlauf führen. Stattdessen sollte ein Treiber den Offset (feste Headergröße) von InputBufferLength (Puffergröße) subtrahieren und testen, ob das Ergebnis genügend Platz für waitBuffer-NameLength> (Daten mit variabler Länge) lässt, wie im folgenden Beispiel gezeigt:

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

Anders ausgedrückt: Wenn die Puffergröße abzüglich der festen Headergröße weniger als die Anzahl von Bytes übrig lässt, die für die Daten mit variabler Länge erforderlich sind, geben wir einen Fehler zurück.

Die obige Subtraktion kann nicht unterlaufen, da die erste if-Anweisung sicherstellt, dass inputBufferLength größer oder gleich der Größe von WAIT_FOR_BUFFER ist.

Im Folgenden wird ein komplizierteres Überlaufproblem veranschaulicht:

   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 diesem Beispiel kann während der Multiplikation ein Ganzzahlüberlauf auftreten. Wenn die Größe der SET_VALUE_INFO-Struktur ein Vielfaches von 2 ist, führt ein NumEntries-Wert wie 0x80000000 zu einem Überlauf, wenn die Bits während der Multiplikation nach links verschoben werden. Die Puffergröße wird jedoch den Validierungstest bestehen, da der Überlauf dazu führt, dass dwSize recht klein erscheint. Um dieses Problem zu vermeiden, subtrahieren Sie die Längen wie im vorherigen Beispiel, dividieren Sie durch sizeof(SET_VALUE_INFO), und vergleichen Sie das Ergebnis mit NumEntries.