(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Кошерный способ модификации защищённых от записи областей ядра 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 так, как рекомендуют тут:

static inline unsigned long native_pax_open_kernel(void) { unsigned long cr0; preempt_disable(); barrier(); cr0 = read_cr0() ^ X86_CR0_WP; BUG_ON(unlikely(cr0 & X86_CR0_WP)); write_cr0(cr0); return cr0 ^ X86_CR0_WP; } static inline unsigned long native_pax_close_kernel(void) { unsigned long cr0; cr0 = read_cr0() ^ X86_CR0_WP; BUG_ON(unlikely(!(cr0 & X86_CR0_WP))); write_cr0(cr0); barrier(); preempt_enable_no_resched(); return cr0 ^ X86_CR0_WP; }

Использование отображений

Более лучшим и в достаточной степени универсальным, является способ создания временных отображений. В силу особенностей работы MMU, для каждого физического фрейма памяти может быть создано несколько ссылающихся на него описателей, имеющих различные атрибуты. Это позволяет создать для целевой области памяти отображение, доступное для записи. Такой метод используется в проекте Ksplice (форк на github'е). Ниже приведена функция map_writable, которая и создаёт такое отображение:

/* * map_writable creates a shadow page mapping of the range * [addr, addr + len) so that we can write to code mapped read-only. * * It is similar to a generalized version of x86's text_poke. But * because one cannot use vmalloc/vfree() inside stop_machine, we use * map_writable to map the pages before stop_machine, then use the * mapping inside stop_machine, and unmap the pages afterwards. */ static void *map_writable(void *addr, size_t len) { void *vaddr; int nr_pages = DIV_ROUND_UP(offset_in_page(addr) + len, PAGE_SIZE); struct page **pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL); void *page_addr = (void *)((unsigned long)addr & PAGE_MASK); int i; if (pages == NULL) return NULL; for (i = 0; i < nr_pages; i++) { if (__module_address((unsigned long)page_addr) == NULL) { pages[i] = virt_to_page(page_addr); WARN_ON(!PageReserved(pages[i])); } else { pages[i] = vmalloc_to_page(page_addr); } if (pages[i] == NULL) { kfree(pages); return NULL; } page_addr += PAGE_SIZE; } vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL); kfree(pages); if (vaddr == NULL) return NULL; return vaddr + offset_in_page(addr); }

Использование данной функции позволит создать доступное для записи отображение для любой области памяти. Освобождение созданного таким образом региона осуществляется с использованием функции vfree, аргументом которой должно служить выравненное на границу страницы значение адреса.

Стоп машина!

Последним элементом, позволяющим сделать модификацию кода ядра безопасной, является механизм stop_machine:

#include <linux/stop_machine.h> int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus)

Суть в том, что stop_machine осуществляет выполнение функции fn с заданным набором активных в момент выполнения процессоров, что задаётся соответствующей маской cpumask. Именно это позволяет использовать данный механизм для осуществления модификации кода ядра, т.к. задание соответствующей маски автоматически исключает необходимость отслеживания тех потоков ядра, выполнение которых может затрагивать модифицируемый код.

Из ограничений stop_machine стоит отметить, что выполняемая функция должна отрабатывать в atomic-контексте, что автоматически исключает возможность использования рассмотренного ранее механизма создания временных отображения через vmap. Однако это обстоятельство не является значимым, ведь требуемые отображения можно подготовить до вызова stop_machine

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 27.12.2013 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Контур.Доступ
GFI FaxMaker и 1 год поддержки (10-49 лицензий)
SAP CRYSTAL Server 2013 WIN INTL 5 CAL License
ABBYY Lingvo x6 Многоязычная Домашняя версия, электронный ключ
ABBYY Lingvo x6 Английская Профессиональная версия
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
Реестр Windows. Секреты работы на компьютере
Мир OLAP и Business Intelligence: новости, статьи, обзоры
Один день системного администратора
Компьютерная библиотека: книги, статьи, полезные ссылки
Проект mic-hard - все об XP - новости, статьи, советы
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100