Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
При обработке 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 , превышающее выходной буфер, и поэтому возвращает слишком много информации в код пользовательского режима. Если приложение неправильно программировано и используется слишком малый буфер вывода, предыдущий код может повредить пул, записав данные за пределы системного буфера.
Помните, что диспетчер ввода-вывода предполагает, что значение в поле "Информация " допустимо. Если вызывающий объект передает допустимый адрес в режиме ядра для выходного буфера и размер нулевых байтов, серьезные проблемы могут возникнуть, если драйвер не проверяет размер выходного буфера и таким образом находит ошибку.