Aracılığıyla paylaş


Variable-Length Arabelleklerini Doğrulama Hatası

Sürücüler genellikle aşağıdaki örnekte olduğu gibi sabit başlık bilgilerine ve sonunda değişken uzunlukta verilere sahip girdi tamponlarını kabul eder.

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

WaitBuffer-NameLength> çok büyük bir ULONG değeriyse, bunu ofsete eklemek tamsayı taşmasına neden olabilir. Bunun yerine, bir sürücü aşağıdaki örnekte olduğu gibi farkı (sabit üst bilgi boyutu) InputBufferLength'ten (arabellek boyutu) çıkarmalı ve sonucun WaitBuffer-NameLength> (değişken uzunluk verileri) için yeterli alan bırakıp bırakmadiğini test etmelidir:

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

Özetle, arabellek boyutu eksi sabit üst bilgi boyutu, değişken uzunluklu veri için gereken bayt sayısından daha azsa, fonksiyon başarısızlıkla sonuçlanır.

Yukarıdaki çıkarma işlemi, ilk if deyimi InputBufferLength değerinin WAIT_FOR_BUFFER boyutundan büyük veya buna eşit olmasını sağladığından alt taşma meydana gelmez.

Aşağıda daha karmaşık bir taşma sorunu gösterilmektedir:

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

Bu örnekte, çarpma sırasında bir tamsayı taşması oluşabilir. SET_VALUE_INFO yapısının boyutu 2'nin katıysa, 0x80000000 gibi bir NumEntries değeri, çarpma sırasında bitler sola kaydırıldığında taşmayla sonuçlanır. Ancak arabellek boyutu yine de doğrulama testini geçer çünkü taşma dwSize değerinin oldukça küçük görünmesine neden olur. Bu sorunu önlemek için, önceki örnekte olduğu gibi uzunlukları çıkarın, sizeof(SET_VALUE_INFO) bölümüne bölün ve sonucu NumEntries ile karşılaştırın.