Может ли код ядра сделать вещи доступными только для чтения таким образом, что другой код ядра не может отменить? - PullRequest
3 голосов
/ 24 апреля 2020

У меня сложилось впечатление, что попытки ядра Linux защитить себя вращаются вокруг того, чтобы не дать вредоносному коду работать в пространстве ядра. В частности, если вредоносный модуль ядра будет загружен, это будет «игра окончена» с точки зрения безопасности. Однако недавно я наткнулся на пост , который противоречит этому убеждению и говорит, что ядро ​​может каким-то образом защитить свои части от других частей:

множество механизмов защиты от вредоносных модулей. Я пишу код ядра для удовольствия, поэтому у меня есть некоторый опыт в этой области; это в основном флаг в таблице страниц.

Что может помешать любому модулю ядра изменить этот флаг в таблице обратно? Единственная защита от вредоносных модулей вообще не дает им загружаться. После загрузки игра заканчивается.

Сделайте таблицу доступной только для чтения. Готово.

Модули ядра могут просто сделать его снова доступным для чтения и записи, так же, как ваш код сделал его доступным только для чтения, а затем продолжить свои изменения.

Вы может фактически заблокировать это так, чтобы режим ядра не мог изменить таблицу страниц, пока не произойдет прерывание. Если ваша IDT также доступна только для чтения, модуль не может ничего с этим поделать.

Это не имеет никакого смысла мне. Я что-то упускаю из-за того, как работает память ядра? Может ли код пространства ядра ограничить себя от изменения таблицы страниц? Это действительно предотвратит руткиты ядра? Если так, то почему ядро ​​Linux не делает этого сегодня, чтобы положить конец всем руткитам ядра?

1 Ответ

6 голосов
/ 24 апреля 2020

Если вредоносный код ядра загружается надежным способом (например, загружает модуль ядра и не использует уязвимость), тогда нет : код ядра - это код ядра.

Процессоры Intel делают иметь ряд механизмов для отключения доступа на чтение / запись к памяти ядра:

  • CR0.WP, если set запрещает доступ на запись как к пользовательским страницам, так и к страницам, доступным только для чтения ядру. Используется для обнаружения ошибок в коде ядра.
  • CR4.PKE если установлено (4-уровневая подкачка должна быть включена, обязательна в 64-битном режиме) запрещает ядру доступ (не включая выборки инструкций) к странице пользователя режим, если они не помечены правой клавишей (которая помечает их права доступа RW). Используется для разрешения ядру писать в структуры, такие как VSDO и KUSER_SHARED_DATA, но не в другие структуры пользовательского режима. Разрешения ключей находятся в MSR, а не в памяти; сами ключи находятся в записях таблицы страниц.
  • CR4.SMEP, если установлено, запрещает выбор инструкций ядра со страниц режима пользователя. Используется для предотвращения атак, когда указатель функции ядра перенаправляется на страницу, выделенную для пользовательского режима (например, эксплойт для повышения привилегий nelson.c).
  • CR4.SMAP, если установлен, запрещает доступ ядра к страницам пользовательского режима во время неявный доступ или во время любого типа (неявного или явного) доступа (если EFLAGS.AC=0, тем самым переопределяя ключи защиты). Используется для обеспечения более строгой политики доступа без пользовательского режима.
  • Конечно, биты R/W и U/S в структурах подкачки управляют, если элемент доступен только для чтения / чтения-записи и назначен пользователю или ядру.

Вы можете прочитать, как применяются разрешения для доступа в режиме супервизора в руководстве Intel:

Запись данных в супервизор -режимы адреса.
Права доступа зависят от значения CR0.WP:
- Если CR0.WP = 0, данные могут быть записаны на любой адрес в режиме супервизора.
- Если CR0.WP = 1, данные могут быть записаны на любой адрес в режиме супервизора с преобразованием, для которого флаг R / W (бит 1) равен 1 в каждой записи структуры пейджинга, управляющей преобразованием; данные не могут быть записаны на любой адрес в режиме супервизора с переводом, для которого флаг R / W равен 0 в любой записи структуры подкачки, управляющей переводом.

Так что даже если ядро ​​защищает страницу X как доступный только для чтения и затем защищающий сами структуры страниц как доступный только для чтения, вредоносный модуль может просто очистить CR0.WP.
Он также может изменить CR3 и использовать свои собственные структуры подкачки.

Обратите внимание, что Intel разработала SGX для решения модели угроз, когда само ядро ​​является злым.
Однако запуск компонентов ядра в анклавы безопасным способом (то есть без единой точки отказа) может не привести к быть тривиальным.

Другой подход заключается в виртуализации ядра с расширением VMX , хотя это ни в коем случае не тривиально для реализации.

Наконец, процессор имеет четыре уровня защиты на уровне сегментации, но подкачка имеет только два: супервизор (CPL = 0) и пользователь (CPL> 0).
Теоретически возможно запустить ядро ​​со mponent в «Ring 1», но тогда вам нужно будет создать интерфейс (например, что-то вроде шлюза вызова или syscall), чтобы он мог обращаться к другим функциям ядра.
Проще всего запустить его в пользовательском режиме ( так как вы не доверяете модулю в первую очередь).

Я понятия не имею, что это должно означать:

Вы можете заблокировать это, чтобы режим ядра не мог изменять таблицу страниц, пока не произойдет прерывание.

Я не помню ни одного механизма, с помощью которого обработка прерываний будет блокировать / разблокировать что-либо. Мне любопытно, что если кто-то может пролить свет на то, что они приветствуются.

Безопасность в процессорах x86 (но это может быть обобщено) всегда была иерархической : кто бы ни пришел первым, настроил ограничения для тех, кто придет позже.
Обычно защита от неизолированных компонентов на одном и том же уровне иерархии практически отсутствует.

...