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


Инъекция сбоев на основе стека

Примечание Инструкции по включению этой функции применяются только к WDK для Windows 8. Для Windows 8.1 эта функция интегрирована в средство проверки драйверов. На компьютерах под управлением Windows 8.1 используйте параметр симуляция с низким уровнем ресурсов.

Параметр инъекции сбоев на основе стека осуществляет сбои ресурсов в драйверах режима ядра. Этот параметр использует специальный драйвер KmAutoFail.sysвместе с Driver Verifier для изучения путей обработки ошибок драйвера. Тестирование этих путей исторически было очень трудным. Опция внедрения отказов на основе стека предсказуемо вызывает отказы ресурсов, что делает обнаруженные проблемы воспроизводимыми. Так как пути ошибок легко воспроизвести, это также упрощает проверку исправлений этих проблем.

Чтобы определить первопричину ошибки, предоставляется расширение отладчика, которое может точно определить, какие ошибки были внедрены и в каком порядке.

Если параметр внедрения отказов на основе стека включен для конкретного драйвера, он перехватывает некоторые вызовы от этого драйвера к ядру и Ndis.sys. Анализ стека вызовов для внедрения сбоев сосредоточен на той части стека вызовов, которая принадлежит драйверу, на котором он включен. Если это первый раз, когда он видел этот стек, вызов завершится ошибкой в соответствии с семантикой этого вызова. В противном случае, если он уже видел этот вызов, он передаст его без изменений. Внедрение ошибок на основе стека включает логику для обработки того факта, что драйвер можно загрузить и выгрузить несколько раз. Он распознает, что стек вызовов совпадает, даже если драйвер перезагрузится в другое расположение памяти.

активация этого параметра

Вы можете активировать функцию инъекции отказов на основе стека для одного или нескольких драйверов при развертывании драйверов на тестовом компьютере. При настройке свойств проверки драйвера в проекте пакета драйвера с, можно выбрать параметр внедрения отказов на основе стека. Чтобы активировать или отключить параметр «Внедрение сбоев на основе стека», необходимо перезапустить компьютер. Вы также можете запустить тестовую программу, чтобы включить средство проверки драйверов и эту функцию на тестовом компьютере.

Важные При активации внедрения сбоя на основе стека на тестовом компьютере убедитесь, что не следует также выбирать симуляцию низких ресурсов.

  • страница свойств проверяющего драйвера

    1. Откройте страницы свойств для пакета драйвера. Щелкните правой кнопкой мыши на проекте пакета драйвера в Solution Explorer и выберите Свойства.
    2. На страницах свойств пакета драйвера щелкните Свойства конфигурации, щелкните Установка драйвера, а затем щелкните Средство проверки драйвера.
    3. Выберите Включить средство проверки драйверов. При включении средства проверки драйверов на тестовом компьютере можно включить средство проверки драйверов для всех драйверов на компьютере, только для проекта драйвера или для списка указанных драйверов.
    4. В разделе Внедрение сбоев на основе стекавыберите (отметьте) внедрение сбоев на основе стека.
    5. Нажмите кнопку Применить или ОК.
    6. См. Развертывание драйвера на тестовом компьютере для получения дополнительной информации. Для активации этого параметра тестовый компьютер должен перезапуститься.
  • Использование теста "Включить и отключить проверку драйвера"

    1. Вы также можете включить средство проверки драйверов, выполнив служебную программу. Следуйте инструкциям, описанным в статье Как протестировать драйвер во время выполнения с помощью Visual Studio. В тестовой категории Все тесты\Средство проверки драйверов выберите тесты Включить средство проверки драйверов (возможно, требуется перезагрузка) и Отключить средство проверки драйверов (возможно, требуется перезагрузка).

    2. Выберите параметры средства проверки драйверов, щелкнув на имени теста Включить средство проверки драйверов (возможна перезагрузка) в окне Группа тестов драйверов.

    3. Выберите (отметьте) внедрение сбоев на основе стека.

    4. После добавления этих тестов в тестовую группу можно сохранить тестовую группу. Чтобы включить внедрение отказа на основе стека, запустите включите средство проверки драйверов (возможна перезагрузка) тест на компьютере, настроенном для тестирования.

      Чтобы отключить средство проверки драйверов, запустите тест Отключить средство проверки драйверов (возможен перезапуск требуется).

Использование параметра внедрения сбоев на основе стека

Одним из важных соображений при тестировании с помощью внедрения ошибок на основе стека является то, что большинство обнаруженных ошибок приведет к проверке ошибок. Это может оказаться несколько болезненным, если ваш драйвер является загрузочным. Из-за этого мы автоматически отключим внедрение ошибок на основе стека, если средство проверки драйверов отключено. Это означает, что во время загрузки через отладчик можно отключить внедрение ошибок, основанное на стеке, отключив средство проверки драйверов с помощью команды !verifier –disable.

Если это возможно, для первоначальных тестов с инъекцией отказов на основе стека настройте драйвер так, чтобы он не загружался при загрузке системы. Затем можно выполнить некоторые простые тесты загрузки и выгрузки. Многие ошибки, обнаруженные внедрением сбоев на основе стека, возникают во время инициализации или очистки. Многократная загрузка и разгрузка вашего драйвера — это хороший способ найти их.

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

Использование расширения отладчика для инжекции сбоев на основе стека (SBFI)

Большинство проблем, обнаруженных при внедрении сбой на основе стека, приводят к проверке ошибок. Чтобы определить причину этих ошибок кода, WDK предоставляет расширение отладчика на основе стека и необходимые символы. Процедура установки установит оба компонента на вашу систему отладки. Расположение по умолчанию — C:\Program Files (x86)\Windows Kits\8.0\Debuggers\<arch>.

Запуск расширения отладчика

  • В командной строке отладчика введите следующую команду: !<путь>\kmautofaildbg.dll.autofail. Например, если расширения отладчика установлены в c:\dbgext и kmautofail.pdb находится в пути к символам, введите следующую команду:

    !c:\dbgext\kmautofaildbg.dll.autofail
    

Это выгрузит информацию в ваш отладчик, показывающую стеки вызовов из недавно произошедших сбоев. Каждая запись выглядит примерно так, как в следующем примере из реального тестового запуска. В следующем примере функция Stack Based Failure Injection включена на Mydriver.sys.

Sequence: 2, Test Number: 0, Process ID: 0, Thread ID: 0
                 IRQ Level: 2, HASH: 0xea98a56083aae93c
 0xfffff8800129ed83 kmautofail!ShimHookExAllocatePoolWithTag+0x37
 0xfffff88003c77566 mydriver!AddDestination+0x66
 0xfffff88003c5eeb2 mydriver!ProcessPacketDestination+0x82
 0xfffff88003c7db82 mydriver!ProcessPacketSource+0x8b2
 0xfffff88003c5d0d8 mydriver!ForwardPackets+0xb8
 0xfffff88003c81102 mydriver!RoutePackets+0x142
 0xfffff88003c83826 mydriver!RouteNetBufferLists+0x306
 0xfffff88003c59a76 mydriver!DeviceSendPackets+0x156
 0xfffff88003c59754 mydriver!ProcessingComplete+0x4a4
 0xfffff88001b69b81 systemdriver2!ProcessEvent+0x1a1
 0xfffff88001b3edc4 systemdriver1!CallChildDriver+0x20
 0xfffff88001b3fc0a systemdriver1!ProcessEvent+0x3e
 0xfffff800c3ea6eb9 nt!KiRetireDpcList+0x209
 0xfffff800c3ea869a nt!KiIdleLoop+0x5a

В верхней части выходных данных порядковый номер подсчитывает количество ошибок, которые внедряются. В этом примере показан второй сбой, внедренный во время этого теста. Идентификатор процесса равен 0, поэтому это был системный процесс. IRQL — 2, поэтому это вызывается на уровне диспетчеризации.

В стеке драйвер инъекции сбоев на основе стека называется KmAutoFail. Имя функции KmAutoFail указывает, какая функция вызова из Mydriver.sys была перехвачена и в которую был внедрен сбой. Здесь функция, которая завершилась сбоем, была ExAllocatePoolWithTag. Все функции в KmAutoFail, которые перехватывают вызовы Ntoskrnl.sys или Ndis.sys, используют это соглашение об именовании. Далее мы видим стек вызовов с тестируемым драйвером (Mydriver.sys). Это часть стека вызовов, которая используется для определения уникальности стека. Таким образом, каждая запись, выгружаемая расширением для отладки, будет уникальной в этой части стека вызовов. Остальная часть стека вызовов указывает, кто вызвал драйвер. Главной важностью этого является вызов драйвера из пользовательского режима (с помощью IOCTL) или драйвера в режиме ядра.

Обратите внимание, что если драйвер вернул сбой из своей процедуры DriverEntry, попытка перезагрузки обычно будет выполняться в другом расположении памяти. В этом случае стек вызовов из прошлого местоположения, вероятно, будет содержать "мусор", а не информацию о стеке от драйвера. Но это не проблема; он сообщает, что драйвер правильно обработал инъектированную неисправность.

Следующая запись показывает вызов драйвера с помощью IOCTL из пользовательского режима. Обратите внимание на идентификатор процесса и уровень IRQ. Так как Mydriver.sys является драйвером фильтра NDIS, IOCTL прошел через Ndis.sys. Обратите внимание, что nt! NtDeviceIoControlFile находится в стеке. Любой тест, выполняемый на драйвере, использующий ioCTLs, будет проходить через эту функцию.

Sequence: 5, Test Number: 0, Process ID: 2052, Thread ID: 4588
                 IRQ Level: 0, HASH: 0xecd4650e9c25ee4
 0xfffff8800129ed83 kmautofail!ShimHookExAllocatePoolWithTag+0x37
 0xfffff88003c6fb39 mydriver!SendMultipleOids+0x41
 0xfffff88003c7157b mydriver!PvtDisconnect+0x437
 0xfffff88003c71069 mydriver!NicDisconnect+0xd9
 0xfffff88003ca3538 mydriver!NicControl+0x10c
 0xfffff88003c99625 mydriver!DeviceControl+0x4c5
 0xfffff88001559d93 NDIS!ndisDummyIrpHandler+0x73
 0xfffff88001559339 NDIS!ndisDeviceControlIrpHandler+0xc9
 0xfffff800c445cc96 nt!IovCallDriver+0x3e6
 0xfffff800c42735ae nt!IopXxxControlFile+0x7cc
 0xfffff800c4274836 nt!NtDeviceIoControlFile+0x56
 0xfffff800c3e74753 nt!KiSystemServiceCopyEnd+0x13

Анализ результатов инъекции отказов на основе стека

Вы выполняете тесты на вашем драйвере и вдруг столкнулись с проблемой. Скорее всего, это была проверка ошибок, но это также может быть связано с тем, что компьютер не отвечает. Как найти причину? Предположим, что это проверка ошибок, сначала используйте расширение выше для поиска списка внедренных сбоев, а затем используйте команду отладчика: !analyze –v.

Наиболее распространённая ошибка возникает из-за того, что не проверяется успешность выделения памяти. В этом случае стек из анализа проверки ошибок, вероятно, почти идентичен тому, что был вызван последним сбоем. В какой-то момент после неудачного выделения (часто в самой следующей строке) драйвер получит доступ к указателю NULL. Этот тип ошибки очень легко исправить. Иногда сбой в выделении памяти может быть на одну или две позиции выше в списке, но этот тип всё равно очень легко найти и исправить.

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

Ошибки, которые приводят к тому, что компьютер не отвечает, сложнее диагностировать, но процедура их отладки аналогична. Эти ошибки часто возникают из-за проблем со счетчиком ссылок или активной блокировкой. К счастью, Driver Verifier захватит множество проблем со спинлоками, прежде чем они приведут к проблемам. В таких случаях включите отладчик и используйте расширение отладчика для дампа списка ошибок, которые были внедрены с помощью внедрения сбоев на основе стека. Краткий обзор кода около последних сбоев может показать учёт ссылок, который берётся до сбоя, но не сбрасывается после. Если нет, найдите поток в драйвере, ожидающий спин-блокировки, или любой счетчик ссылок, который, очевидно, неверен.