Введение
Концепция компьютерной безопасности
В компьютерной безопасности защита исполняемого пространства помечает области памяти как неисполняемые, так что попытка выполнить машинный код в этих областях приведет к исключению. Она использует аппаратные средства, такие как бит NX (бит запрета исполнения), или, в некоторых случаях, программную эмуляцию этих средств. Однако технологии, эмулирующие или обеспечивающие бит NX, обычно создают измеримые накладные расходы, в то время как аппаратный бит NX не создает измеримых накладных расходов. Burroughs 5000 обеспечивала аппаратную поддержку защиты исполняемого пространства при ее представлении в 1961 году; эта возможность сохранялась в ее преемниках как минимум до 2006 года. В ее реализации архитектуры с тегами каждое слово памяти имело связанный скрытый бит тега, определяющий, является ли оно кодом или данными. Таким образом, пользовательские программы не могут записывать или даже читать слова программы, а слова данных не могут быть выполнены. Если операционная система может пометить некоторые или все записываемые области памяти как неисполняемые, она может предотвратить выполнение кода в областях памяти стека и кучи. Это помогает предотвратить некоторые эксплойты переполнения буфера, особенно те, которые внедряют и выполняют код, такие как черви Sasser и Blaster. Эти атаки полагаются на то, что какая-то часть памяти, обычно стек, является одновременно доступной для записи и для исполнения; если это не так, атака не удается.
Android
Начиная с Android 2.3 и более поздних версий, архитектуры, поддерживающие эту функцию, по умолчанию имеют неисполняемые страницы, включая неисполняемый стек и кучу.
FreeBSD
Первоначальная поддержка бита NX на процессорах x86-64 и IA-32, поддерживающих его, впервые появилась в FreeBSD CURRENT 8 июня 2004 года. Она включена в релизы FreeBSD, начиная с версии 5.3.
Линукс
Ядро Linux поддерживает бит NX на процессорах x86-64 и IA-32, которые его поддерживают, таких как современные 64-битные процессоры от AMD, Intel, Transmeta и VIA. Поддержка этой функции в 64-битном режиме на процессорах x86-64 была добавлена в 2004 году Энди Клином, а позднее в том же году Инго Мольнар добавил поддержку в 32-битном режиме на 64-битных процессорах. Эти функции включены в основную ветку ядра Linux с момента выпуска версии 2.6.8 в августе 2004 года. Наличие бита NX в 32-битных ядрах x86, которые могут работать как на 32-битных процессорах x86, так и на 64-битных процессорах, совместимых с IA-32, имеет важное значение, поскольку 32-битное ядро x86 обычно не предполагает наличия бита NX, предоставляемого AMD64 или IA-64; патч для включения NX гарантирует, что эти ядра будут пытаться использовать бит NX, если он доступен. Некоторые настольные дистрибутивы Linux, такие как Fedora, Ubuntu и openSUSE, не активируют опцию HIGHMEM64 по умолчанию в своих стандартных ядрах, что необходимо для доступа к биту NX в 32-битном режиме, поскольку режим PAE, требуемый для использования бита NX, может вызывать сбои при загрузке на процессорах Pentium Pro (включая Pentium MMX) и Celeron M и Pentium M без поддержки NX. Другие процессоры, не поддерживающие PAE, включают AMD K6 и более ранние модели, Transmeta Crusoe, VIA C3 и более ранние модели, а также Geode GX и LX. Версии VMware Workstation старше 4.0, Parallels Workstation старше 4.0, а также Microsoft Virtual PC и Virtual Server не поддерживают PAE в гостевой системе. Fedora Core 6 и Ubuntu 9.10 и более поздние версии предоставляют пакет ядра PAE, который поддерживает PAE и NX. Защита памяти NX всегда была доступна в Ubuntu для систем, имеющих необходимое аппаратное обеспечение и работающих на 64-битном ядре или 32-битном серверном ядре. 32-битное настольное ядро PAE (linux image generic pae) в Ubuntu 9.10 и более поздних версиях также предоставляет режим PAE, необходимый для оборудования с функцией NX CPU. Для систем, не имеющих аппаратной поддержки NX, 32-битные ядра теперь предоставляют программную эмуляцию функции NX CPU, которая может помочь блокировать многие эксплойты, которые злоумышленник может запустить из памяти стека или кучи. Функциональность запрета выполнения также присутствует для других процессоров, не относящихся к x86, поддерживающих эту функцию на протяжении многих выпусков.
macOS
macOS для Intel поддерживает бит NX на всех процессорах, поддерживаемых Apple (начиная с Mac OS X 10.4.4 – первой версии для Intel и далее). Mac OS X 10.4 поддерживала только защиту стека NX. В Mac OS X 10.5 все 64-битные исполняемые файлы имеют защиту стека и кучи NX; применяется защита W^X. Это относится к x86 64 (Core 2 и более поздним моделям) и 64-битному PowerPC на компьютерах Mac G5.
NetBSD
Начиная с NetBSD 2.0 и более поздних версий (9 декабря 2004 года), архитектуры, поддерживающие эту функцию, имеют неисполняемый стек и кучу. Архитектуры с гранулярностью на уровне страницы включают: alpha, amd64, hppa, i386 (с PAE), powerpc (ibm4xx), sh5, sparc (sun4m, sun4d), sparc64. Архитектуры, которые могут поддерживать эту функцию только с гранулярностью области: i386 (без PAE), другие powerpc (например, macppc). Для остальных архитектур не предусмотрена защита неисполняемого стека и кучи; NetBSD по умолчанию не использует программную эмуляцию для обеспечения этих функций на этих архитектурах.
Солярис
Solaris поддерживает глобальное отключение выполнения кода на стеке для процессоров SPARC, начиная с Solaris 2.6 (1997); в Solaris 9 (2002) была добавлена возможность отключения выполнения кода на стеке для отдельных исполняемых файлов.
Xbox
В Xbox от Microsoft, несмотря на отсутствие бита NX в процессоре, новые версии XDK устанавливают лимит сегмента кода в начало секции данных ядра (в нормальных условиях после этой точки код не должен располагаться). Начиная с версии 51xx, это изменение было также внедрено в ядро новых Xbox. Это привело к неработоспособности техник, которые использовались в старых эксплойтах для превращения в программу, завершающуюся и остающуюся в памяти. Однако новые эксплойты были оперативно разработаны с поддержкой этой новой версии ядра, поскольку фундаментальная уязвимость в ядре Xbox осталась нетронутой.
Ограничения
В тех случаях, когда код записывается и выполняется во время выполнения – ярким примером является JIT-компилятор – компилятор потенциально может быть использован для генерации эксплойта (например, с помощью JIT Spray), который был помечен как предназначенный для исполнения и, следовательно, не был бы заблокирован. Return-oriented programming (ROP) позволяет злоумышленнику выполнять произвольный код даже при включенной защите пространства исполняемого кода.