Планы по усилению механизма защиты W^X в OpenBSD
Тео Де Раадт поделился планами по усилению механизма защиты памяти W^X (Write XOR Execute). Суть мехнизма в том, что страницы памяти процесса не могут быть одновременно доступны на запись и исполнение. Таким образом, код может быть исполнен только после запрещения записи, а запись в страницу памяти возможна только после запрета исполнения. Механизм W^X помогает защитить приложения в пространстве пользователя от типовых атак, осуществляемых через переполнение буфера, в том числе от переполнений стека и активен в OpenBSD по умолчанию.
С начала работ над W^X было понятно, что это долгая дорога, так как существует значительное количество приложений, использующих JIT. Реализации JIT можно разделить на три категории:
- Переключающие память между W и X состояниями, смиряясь со «стоимостью» системного вызова mprotect.
- Создающие псевдонимы между парой W и X отображений одной и той же памяти.
- Наиболее «грязный» вариант — требующие модели памяти W|X, допускающей одновременное осуществление записи и исполнения.
В настоящее время стало значительно меньше программ, использующих третий вариант и больше использующих первый и второй. Тем не менее, так как было необходимо запускать и программы с W|X JIT (главным образом, Chromium и Iridum), была добавлена опция монтирования файловой системы «wxallowed», которая позволяла использовать память одновременно и для записи и для исполнения, в случае, если исполняемый ELF-файл отмечен маркером «wxneeded», а сами приложения дополнительно защищались, используя механизмы pledge и unveil для ограничения списка используемых системных вызовов и доступных для приложения частей файловой системы соответственно.
Для дальнейшего усложнения эксплуатации уязвимостей в подобных приложениях предложено дополнение механизма MAP_STACK, которое проверяет, выполняется ли системный вызов из доступной для записи страницы памяти. Если страница доступна для записи, процесс принудительно завершается. Таким образом, злоумышленник не сможет использовать системные вызовы и будет вынужден пытаться найти нужные гаджеты или в реализации JIT или даже с более трудным обнаружением заглушек системных вызовов непосредственно внутри случайно связанного libc.
Процессы Chrome/Iridium и так достаточно надёжно защищены при помощи pledge и unveil, но лишение возможности использовать, например, системный вызов write (2), очевидно, имеет некоторое преимущество, так как создаёт атакующему дополнительные сложности. Впрочем, сложности могут возникнуть и в том случае, если реализация JIT использует нативные системные вызовы из W|X памяти. Однако, есть основания надеяться, что с подобным не придётся столкнуться, так как ABI неоднократно менялось, но никто никогда не сообщал о проблемах. Изменения уже доступны в регулярных снапшотах ветки OpenBSD-Сurrent, все заинтересованные приглашаются к тестированию.
Отдельного комментария со стороны Тео заслужили связанные новости про появление в Chrome/Iridium режима JITless. С его точки зрения, это приемлемо для некоторых моделей использования, однако, вероятно, не для всех, так как в данном режиме очевидно возрастёт нагрузка на процессор. Сейчас Chrome в основном будет работать, если отключить «wxallowed» для /usr/local, хотя и вероятны проблемы с некоторыми расширениями (в пример приводится ghostery). Так или иначе, Тео надеется, что полноценная работа в JITless-режиме будет доведена до полностью рабочего состояния в ближайшее время.
Полный текст статьи читайте на OpenNet