Жизнь после BSOD

Крис Касперски и Жирный Хомяк

Хакер, номер #085, стр. 085-114-1

С помощью отладчика и ассемблера заставим систему пережить голубой экран смерти

Все прекрасно знают, что означает BSOD (Blue Screen Of Death). Это последний вздох операционной системы, после которого она сбрасывает дамп и уходит на перезагрузку, теряя все несохраненные данные. Однако на самом деле BSOD - еще не конец, и если перезагрузку заменить реанимацией, то в 9 из 10 случаев можно возвратиться в нормальный режим и успеть зашатдаунить систему перед тем, как она умрет окончательно.

Синий экран появляется всякий раз, когда ядро возбуждает необрабатываемое исключение (скажем, обращение по нулевому указателю) или отлавливает заведомо левую операцию (освобождение уже освобожденной памяти, например). Во всех этих случаях управление передается функции KeBugCheckEx, описание которой можно найти в NT DDK. Она завершает работу системы в аварийном режиме, при необходимости сбрасывая дамп памяти, поковырявшись в котором, можно определить причину сбоя.

Функция KeBugCheckEx принимает четыре аргумента, важнейшим из которых является BugCheckCode, определяющий причину сбоя. Всего существует свыше сотни кодов ошибок, документированных в DDK (ищи их в руководстве по отладчику Using Microsoft Debugger), однако в действительности их намного больше. Дизассемблирование ядра W2K SP2 показывает, что KeBugCheckEx вызывается из 387 мест (с различными параметрами).

Разумеется, не все ошибки одинаковы по своей фатальности. В многоядерных осях это вообще не проблема. Падение одного ядра не затрагивает других. Все ядра работают в раздельных адресных пространствах и частично или полностью изолированы друг от друга. Разрушить такую систему очень трудно, многоядерная архитектура чрезвычайно устойчива к сбоям, но… как же при этом она тормозит! Межъядерный обмен съедает уйму процессорного времени. Если запихать все компоненты в одно ядро, то мы получим монолитное ядро по типу Linux (что, кстати говоря, явилось причиной яростной критики последнего со стороны многих теоретиков). В Linux, как и в BSD, все компоненты ядра (там они называются модулями) исполняются в едином адресном пространстве, и некорректно написанный модуль может непреднамеренно или умышленно надругаться над чужой собственностью (превратить данные в винегрет, например). Это факт! Однако при возникновении необрабатываемого исключения в ядре, Linux грохает только тот модуль, который это исключение и породил, не трогая все остальные. Аварийный останов системы происходит только по серьезному поводу, когда рушится что-то очень фундаментальное, делающее дальнейшую работу ядра действительно невозможной. Конечно, если полетел драйвер жесткого диска, - это кранты, но вот, например, без драйвера звуковой карты можно какое-то время и обойтись, сохранив все несохраненные данные, и только потом перезагрузиться.

Операционные системы семейства NT используют гибридную архитектуру, сочетающую сильные стороны монолитных и микроядер, что теоретически должно обеспечить превосходство над монолитным Linux'ом (кстати говоря, экспериментальное ядро GNU/HURD построено как раз по микроядерной архитектуре). Легендарно устойчивую NT/XP, которую, как говорят, можно уронить только вместе с сервером, на самом деле очень легко вогнать в голубой экран. Достаточно любому драйверу сделать что-то недозволенное, как система автоматически катапультирует пользователя. Хорошо, что Microsoft не строит авиалайнеры!

Содержание  Вперед на стр. 085-114-2
ttfb: 3.6029815673828 ms