Поделиться через


Ошибка проверки размера буферов

При обработке IOCTLs и FSCTLs, реализующие буферный ввод-вывод, драйвер всегда должен проверять размеры входных и выходных буферов, чтобы убедиться, что буферы могут содержать все запрошенные данные. Если запрос указывает FILE_ANY_ACCESS, как это делают большинство запросов IOCTL и FSCTL драйвера, любой вызывающий, имеющий дескриптор устройства, получает доступ к буферизованным запросам IOCTL или FSCTL для этого устройства и может считывать либо записывать данные за пределами буфера.

Размер входного буфера

Например, предположим, что следующий код отображается в подпрограмме, вызываемой из подпрограммы диспетчера , и что драйвер не проверил размер буфера, переданный в IRP:

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

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

В примере не проверяется размер буфера перед операцией присваивания (выделено). В результате ссылка pNewAddress-Address> в следующей строке может вызывать ошибку, если входной буфер недостаточно велик, чтобы вместить структуру tNEW_ADDRESS.

Следующий код проверяет размеры буфера, избегая потенциальной проблемы:

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

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

Код для обработки других буферных операций ввода-вывода, таких как запросы WMI, использующие буферы размера переменных, могут иметь аналогичные ошибки.

Размер выходного буфера

Проблемы буфера вывода похожи на проблемы входного буфера. Они могут легко повредить пул, и вызывающие в пользовательском режиме пользователи могут не знать, что произошла ошибка.

В следующем примере драйвер не может проверить размер 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;
   }

При условии, что поле NumIF системного буфера указывает количество входных элементов, в этом примере можно задать значение IoStatus.Information , превышающее выходной буфер, и поэтому возвращает слишком много информации в код пользовательского режима. Если приложение неправильно программировано и используется слишком малый буфер вывода, предыдущий код может повредить пул, записав данные за пределы системного буфера.

Помните, что диспетчер ввода-вывода предполагает, что значение в поле "Информация " допустимо. Если вызывающий объект передает допустимый адрес в режиме ядра для выходного буфера и размер нулевых байтов, серьезные проблемы могут возникнуть, если драйвер не проверяет размер выходного буфера и таким образом находит ошибку.