Штурм ядра 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 формат. И то, и другое легко найти в сети. |