Freigeben über


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

Bei der Behandlung von IOCTLs und FSCTLs, die gepufferte E/A implementieren, sollte ein Treiber immer die Größe 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 tun, 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

Gehen Sie beispielsweise davon aus, dass der folgende Code in einer Routine angezeigt wird, die von einer Dispatch-Routine aufgerufen wird, und dass der Treiber die in der 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 Zuordnungsanweisung (hervorgehoben) nicht überprüft. Daher kann der pNewAddress-Address-Verweis> in der nächsten Zeile fehlschlagen, wenn der Eingabepuffer nicht groß genug ist, um eine tNEW_ADDRESS Struktur zu enthalten.

Der folgende Code überprüft die Puffergrößen und vermeidet das potenzielle Problem:

   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 Behandeln anderer gepufferter E/A-Vorgänge, z. B. WMI-Anforderungen, die Puffer mit variabler Größe verwenden, kann ähnliche Fehler aufweisen.

Ausgabepuffergröße

Ausgabepufferprobleme ähneln Eingabepufferproblemen. Sie können den Pool leicht beschädigen, und Anrufer im Benutzermodus 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;
   }

Angenommen, das NumIF-Feld des Systempuffers gibt die Anzahl der Eingabeelemente an, kann in diesem Beispiel IoStatus.Information 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 nicht ordnungsgemäß codiert ist und Aufrufe mit zu kleinen Ausgabepuffern ausgeführt werden, 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.