Кошерный способ модификации защищённых от записи областей ядра LinuxИсточник: habrahabr milabs
Те, кто хоть однажды сталкивался с необходимостью поменять что-то в ядре на лету не понаслышке знают, что данный вопрос требует детальной проработки, ведь страницы памяти ядра, хранящие код и некоторые данные, помечены как "read-only" и защищены от записи!
Для x86 известным решением является временное отключение страничной защиты посредством сброса бита WP регистра CR0. Но следует применять это с осторожностью, ведь страничная защита является основой для многих механизмов ядра. Кроме того, необходимо учитывать особенности работы на SMP-системах, когда возможно возникновение разных неприятных ситуаций.
Отключение страничной защитыВ архитектуре x86 существует специальный защитный механизм, в соответствии с которым попытка записи в защищённые от записи области памяти может приводить к генерации исключения. Данный механизм носит название "страничной защиты" и является базовым для реализации многих функций ядра, таких, как например COW. Поведение процессора в этой ситуации определяется битом WP регистра CR0, а права доступа к странице описываются в соответствующей ей структуре-описателе PTE. При установленном бите WP регистра CR0 попытка записи в защищённые от записи страницы (cброшен бит RW в PTE) ведёт к генерации процессором соответствующего исключения (#GP). Простейшим решением данной проблемы является временное отключение страничной защиты сбросом бита WP регистра CR0. Это решение имеет место быть, однако применять его нужно с осторожностью, ведь как было отмечено, механизм страничной является основой для многих механизмов ядра. Кроме того, на SMP-системах, поток, выполняющийся на одном из процессоров и там же снимающий бит WP, может быть прерван и перемещён на другой процессор! Тем не менее, если очень хочется, нужно делать это отключая preemption так, как рекомендуют тут:
Использование отображенийБолее лучшим и в достаточной степени универсальным, является способ создания временных отображений. В силу особенностей работы MMU, для каждого физического фрейма памяти может быть создано несколько ссылающихся на него описателей, имеющих различные атрибуты. Это позволяет создать для целевой области памяти отображение, доступное для записи. Такой метод используется в проекте Ksplice (форк на github'е). Ниже приведена функция map_writable, которая и создаёт такое отображение:
Использование данной функции позволит создать доступное для записи отображение для любой области памяти. Освобождение созданного таким образом региона осуществляется с использованием функции vfree, аргументом которой должно служить выравненное на границу страницы значение адреса.
Стоп машина!Последним элементом, позволяющим сделать модификацию кода ядра безопасной, является механизм stop_machine:
Суть в том, что Из ограничений |