Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #80, АВГУСТ 2005 г.

Штурм ядра Linux

Крис Касперски ака мыщъх

Хакер, номер #080, стр. 080-106-5


Вот пять основных источников ошибок — спинлоки (spin lock), неожиданные выходы из функции, ELF-загрузчик, менеджер виртуальной памяти и TCP/IP-стек. Рассмотрим всех кандидатов поподробнее.

Спинлоками называют ячейки памяти, защищающими многозадачный код от воздействия посторонних потоков. При входе в охраняемую зону процессор устанавливает специальный флаг, а при выходе его сбрасывает. До тех пор, пока флаг не будет сброшен, остальные потоки топчутся у выхода и не могут выполнять код. На многопроцессорных ядрах спинлоки начинаются с префикса LOCK, который легко найти в дизассемблерном тексте, если нажать <ALT-T>. Как мы уже говорили в статье "Захват нулевого кольца", поддержка многозадачности очень сложная задача, и ошибок здесь просто тьма, так что жаловаться на то, что "все баги пофиксены до нас", никому не приходится. К сожалению, большинство "многозадачных" ошибок имеют многоступенчатый характер, наглядно продемонстрированный в уже упомянутой статье (см. раздел "Проблемы многопоточности"), поэтому никаких универсальных методик их поиска не существует. Это работа для настоящих хакеров, способных удержать все ядро в голове и сложить разрозненную мозаику в единую картину. В общем, настоящий хардкор. Это сложно? Ну еще бы! Но мы ведь не ищем легких путей, верно? Зато и удовлетворение от найденной дыры намного больше, чем от успешного использования публичного сплоита.

Пример классического спинлока

kernel:C010A65E loc_C010A65E: ; CODE XREF: sub_C010A984+108vj

kernel:C010A65E lock dec byte ptr [ebx-3FCE77F0h]

kernel:C010A665 js loc_C010AA81

Неожиданные выходы из функции (они же преждевременные) происходят всякий раз, когда из-за какой-то ошибки функция уже не может (не хочет) продолжить работу и делает немедленный return. Часть работы к этому моменту уже выполнена, а часть еще нет. Если программист допустит даже крошечную оплошность, структуры данных превратятся в кашу. Одна из таких ошибок содержится в функции create_elf_tables(), описанной в прошлой статье.

Для поиска внеплановых выходов достаточно перейти в конец функции и проанализировать перекрестные ссылки, которые ведут наверх. Чем их больше, тем выше вероятность, что здесь окажется что-то не так. Ну а там и до дыры уже недалеко.

Перекрестные ссылки в конце функции ведут к местам внезапного выхода

kernel:C010A810 loc_C010A810: ; CODE XREF: kernel:C010A7F1^j

kernel:C010A810 mov eax, 0FFFFFFEAh

kernel:C010A815

kernel:C010A815 loc_C010A815: ; CODE XREF: kernel:C010A7CF^j

kernel:C010A815 ; kernel:C010A809^j

kernel:C010A815 pop ebx

kernel:C010A816 pop esi

kernel:C010A817 pop edi

kernel:C010A818 pop ebp

kernel:C010A819 pop ecx

kernel:C010A81A retn

Загрузчик ELF-файлов, менеджер виртуальной памяти и TCP/IP стек — это настоящие айсберги, которые словно ледяные горы точат из ядра кишками наружу, но основная масса скрыта в глубине воды. Это сотни тысяч строк кода, сложным образом взаимодействующего между собой. Это плодотворная почва для всевозможных багов, кочующих из одну версию ядра в другую. Некоторые из них уже выявлены, некоторые только предстоит найти. В первую очередь следует обратить внимание на обработку нестандартных полей или дикое сочетание различных атрибутов (см. раздел "Эльфы падают в дамп"). Чтобы действовать не вслепую, имеет смысл скачать свежую подшивку RFC и обзавестись спецификацией на ELF формат. И то, и другое легко найти в сети.

Назад на стр. 080-106-4  Содержание  Вперед на стр. 080-106-6