Защита исполняемого пространства

Защита исполняемого пространства помечает области памяти компьютера как неисполняемые, так что попытка выполнить машинный код в этих областях приводит к исключению. Защита основывается на аппаратной поддержке, такой как NX bit (бит запрета выполнения), или на программной эмуляции, если аппаратная поддержка отсутствует. Программная эмуляция зачастую выражается в уменьшении производительности или накладных расходах (дополнительное процессорное время или ресурсы), в то время как реализация на аппаратном NX бите не имеет никакого измеримого влияния.

Burroughs large systems (большие системы Burroughs — серия 48-битных майнфреймов), начиная с Burroughs 5000, запущенной в 1961 году, реализовала защиту исполняемого пространства с помощью теговой архитектуры. Любой доступ к кодам или данным происходит через дескрипторы, которые имеют тэги памяти, защищающие память от попыток изменения. Дескрипторы для кодов не разрешают изменить код программы и дескрипторы для данных, которые не разрешают выполнять данные как инструкции.

В настоящее время операционные системы используют защиту исполняемого пространства, помечая доступные для записи области память, такие как стэк и куча, как невыполняемые, помогая предотвратить взлом с использованием переполнения буфера. Эти атаки опираются на некоторые части памяти, обычно на стек, если он позволяет запись и выполнение. Атака проваливается, если таких разрешений нет.

Реализация в операционной системе

Многие операционные системы реализуют или имеют доступную политику защиты исполняемого пространства. Ниже приведён список таких систем в алфавитном порядке и для каждой системы указаны технологии от новейших к старым.

Технология, обеспечивающая эмуляцию, не зависящую от архитектуры, будет работать на всех процессорах, которые не поддерживаются аппаратно. Строка «Другие поддерживаемые» относится к процессорам, которые позволяют некоторый методов из «серой зоны», когда явный бит NX не существует, но аппаратные средства позволяют его эмулировать каким-либо образом.

Android

Android 2.3 и более поздние версии имеют в архитектурах, которые это поддерживают, неисполняемые страницы по умолчанию, включая неисполняемый стек и кучу[1][2][3].

FreeBSD

Первоначальная поддержка бита NX на процессорах x86-64 и IA-32 впервые появилась в FreeBSD 8 июня 2004 года и присутствует в версиях 5.3 и выше.

Линукс

Ядро Linux поддерживает бит NX на процессорах x86-64 и IA-32, которые его поддерживают, например, на современных 64-битных процессорах производства AMD, Intel, Transmeta и VIA. Поддержка этой функции в 64-битном режиме на процессорах x86-64 была добавлена в 2004 году Анди Клином, а позднее в том же году Инго Молнар добавил поддержку для 32-битного режима 64-битных процессоров. Эти возможности являются частью основного ядра Linux с момента выхода версии ядра 2.6.8 в августе 2004 года[4].

Доступность бита NX для 32-битных x86 ядер, которые могут работать как на 32-битных x86 ЦПУ, так и 64-битных IA-32-совместимых ЦПУ, существенна, поскольку 32-битное ядро x86 обычно не ожидает наличия бита NX, который предоставляют процессоры AMD64 или IA-64. Патч, включающий поддержку 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 и более поздние версии предоставляют пакет kernel-PAE, который поддерживает PAE и NX.

NX защита памяти всегда была доступна в Ubuntu для любых систем, имеющих аппаратную поддержку и работающие под управлением 64-битного ядра или 32-битного серверного ядра. 32-битное ядро для настольных систем с поддержкой PAE (linux-image-generic-pae) в Ubuntu 9.10 и более поздних также обеспечивает режим PAE, необходимый для оборудования с функцией NX. Для систем, в которых отсутствует аппаратная поддержка NX, 32-битные ядра теперь предоставляют программную эмуляцию, имитирующую NX процессора, что может блокировать многие лазейки для атак на стек и кучу.

Функциональность запрета выполнения также присутствовала для других процессоров, отличных от x86, поддерживающих эту возможность, на протяжении многих выпусков.

Exec Shield

Разработчик ядра Red Hat Инго Молнар выпустил патч ядра Linux с именем Exec Shield для эмуляции и использования функциональности NX на 32-битных x86 ЦПУ. Заплата Exec Shield была опубликована в списке рассылки ядра Linux 2 мая 2003 года, но была отклонена для включения в основное ядро из-за необходимости внедрения некоторых изменений в основной код для обработки сложных аспектов эмуляции. Exec Shield обеспечивает поддержку устаревших процессоров, эмулируя NX путём отслеживания верхнего предела сегмента кода. Это требует незначительных накладных расходов для переключения контекста, которые практически неизмеримы. Для старых ЦПУ без бита NX Exec Shield не может защитить страницы ниже предела сегмента кода. Вызов mprotect() для установки флага выполнимости для памяти более высокого уровня, такого как стек, помечает всю память ниже этого уровня. Таким образом, в этих ситуациях схемы Exec Shield не работают. Это цена низких накладных расходов Exec Shield. Exec Shield проверяет два маркера в заголовке ELF, которые определяют, должен ли стек или куча быть исполняемыми. Эти маркеры называются PT_GNU_STACK и PT_GNU_HEAP соответственно. Exec Shield позволяет устанавливать эти элементы управления как для бинарных исполняемых файлов, так и для библиотек. Если исполняемый файл загружает библиотеку, требующую ослабления определённого ограничения, исполняемый файл унаследует эту маркировку и получит ослабленное ограничение.

  • Аппаратно поддерживаемые процессоры: Все, которые поддерживает Linux с NX
  • Эмуляция: Эмуляция NX, используя предел сегмента кодов на IA-32 (x86) и совместимых
  • Другие поддерживаемые: Нет
  • Стандартное распространение: Fedora Core и Red Hat Enterprise Linux
  • Дата выпуска: 2 мая 2003 г.

PaX

Технология PaX NX может эмулировать NX функциональность или использовать аппаратный NX бит. PaX работает на процессорах x86, которые не имеют бита NX, например, 32-битные x86. Ядро Linux по-прежнему не поставляется с PaX (по состоянию на май 2007 года), патч должен быть установлен вручную.

PaX обеспечивает два метода эмуляции бита NX, называемых SEGMEXEC и PAGEEXEC. Метод SEGMEXEC создаёт незначительную, но измеримую нагрузку, обычно менее 1%, являющуюся постоянным множителем и возникающую вследствие зеркалирования виртуальной памяти, используемого для разделения доступа к исполняемому коду и данным [5]. SEGMEXEC также приводит к уменьшению вдвое виртуального адресного пространства, что ограничивает объём доступной памяти. Это не является проблемой, пока задача не требует доступа к более чем половине обычного адресного пространства, что случается редко. SEGMEXEC не увеличивает потребление системной памяти (т.е. RAM) программами, а лишь ограничивает объём, к которому они могут получить доступ. На 32-разрядных процессорах это означает 1,5 ГБ вместо 3 ГБ.

PaX предлагает в PAGEEXEC для ускорения работы метод, аналогичный эмуляции Exec Shield. Однако, когда более высокая память помечена как исполняемая, этот метод теряет свою защитную функцию, В таких ситуациях PaX возвращается к старому методу с переменными накладными расходами, используемому PAGEEXEC для защиты страниц ниже предела CS, что может привести к значительным накладным расходам при определённых шаблонах доступа к памяти. Когда метод PAGEEXEC используется на процессоре с аппаратным битом NX, используется именно аппаратный бит NX, что не влечёт за собой существенных накладных расходов.

PaX накладывает ограничения на функцию mprotect() для предотвращения маркировки памяти программой, которая может быть использована для потенциальной атаки эксплойта. Эта политика может привести к некорректной работе некоторых приложений, но для них её можно отключить.

PaX позволяет индивидуальный контроль над следующими функциями технологии для каждого исполняемого бинарного файла:

  • PAGEEXEC
  • SEGMEXEC
  • mprotect() ограничения
  • Эмуляция трамплина
  • Случайная исполняемая база
  • Случайная база mmap()

PaX игнорирует как PT_GNU_STACK, так и PT_GNU_HEAP. В прошлом PaX имела возможность конфигурации этих опций, но они были удалены из соображений безопасности, поскольку эта возможность была признана бесполезной. Обычно те же результаты, что и при использовании PT_GNU_STACK, достигаются отключением ограничений mprotect(), поскольку программа обычно выполняет mprotect() для стека при загрузке. Это не всегда так. В ситуациях, когда это не удаётся, простое отключение PAGEEXEC и SEGMEXEC эффективно снимет все ограничения на исполняемое пространство, предоставив задаче такую же защиту исполняемого пространства, как и в системе без PaX.

  • Аппаратно поддерживаемые процессоры: Alpha, AMD64, IA-64, MIPS (32 и 64 битные), PA-RISC, PowerPC, SPARC
  • Эмуляция: IA-32 (x86)
  • Другие поддерживаемые: PowerPC (32 and 64 bit), SPARC (32 и 64 битные)
  • Стандартное распространение: Alpine Linux
  • Дата выпуска: 1 октября 2000 г.

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 на компьютерах Macs G5.

NetBSD

Начиная с NetBSD 2.0 (9 декабря 2004 г.) архитектуры, поддерживающие эту функцию, имеют неисполняемые стек и кучу[6].

К архитектурам с гранулярностью на уровне страниц относятся: alpha, amd64, hppa, i386 (with PAE), powerpc (ibm4xx), sh5, sparc (sun4m, sun4d), sparc64.

Архитектуры, которые могут поддерживать это только с гранулярностью на уровне областей памяти: i386 (без PAE), другие powerpc (например, macppc).

Остальные архитектуры не получают преимуществ от неисполняемых стека или кучи. NetBSD по умолчанию не использует программную эмуляцию для предоставления этих функций на таких архитектурах.

OpenBSD

Технология в операционной системе OpenBSD, известная как W^X, помечает страницы с разрешением на запись неисполняемыми по умолчанию на процессорах, поддерживающих это. На 32-битных процессорах x86 сегмент кода устанавливается так, чтобы включать только часть адресного пространства, чтобы обеспечить некоторую степень защиты исполняемого пространства.

OpenBSD 3.3, выпущенный 1 мая 2003 года, был первым выпуском с W^X.

  • Аппаратно поддерживаемые процессоры: Alpha, AMD64, HPPA, SPARC
  • Эмуляция: IA-32 (x86)
  • Другие поддерживаемые: Нет
  • Стандартное распространение: Да
  • Дата выпуска: 1 мая 2003 года

Solaris

Solaris поддерживает глобальное отключение выполнения стека на процессорах SPARC с версии Solaris 2.6 (1997 года). В Solaris 9 (2002 года) была добавлена поддержка отключения выполнения стека для каждого исполняемого файла отдельно.

Windows

Первая реализация неисполняемого стека для Windows (NT 4.0, 2000 и XP) была выпущена компанией SecureWave в 2001 году под названием SecureStack и она основана на функциях PaX[7][8].

Начиная с Windows XP Пакет обновления 2 (2004) и Windows Server 2003 Пакет обновления 1 (2005), функции NX были впервые реализованы на архитектуре x86. Защита исполняемого пространства в Windows называется «Предотвращение выполнения данных» (англ. Data Execution Prevention, DEP).

В Windows XP и Server 2003 защита NX применялась по умолчанию только к критически важным [[Служба Windows|службам Windows]]. Если процессор x86 поддерживал эту функцию аппаратно, то NX защита включалась автоматически в Windows XP/Server 2003 по умолчанию. Если процессор не поддерживал NX, защита не предоставлялась.

Ранние реализации DEP не обеспечивали рандомизации размещения адресного пространства (англ. address space layout randomization, ASLR), что позволяло проводить атаки типа «возврат в библиотеку», которые могли быть использованы для отключения DEP[9]. Документация PaX подробно объясняет, почему ASLR необходима[10]. Был представлен концептуальный пример, демонстрирующий способ обхода DEP при отсутствии ASLR[11]. Успешная атака может быть возможна, если злоумышленник знает адрес подготовленных данных, таких как повреждённые изображения или MP3 файлы.

Микрософт добавил функциональность ASLR в Windows Vista и Windows Server 2008. На этой платформе DEP реализована посредством автоматического использования ядра PAE в 32-разрядных версиях Windows и нативной поддержки в 64-битных ядрах. В Windows Vista функция DEP работает путём маркировки определённых участков памяти как предназначенных только для хранения данных. Процессор с поддержкой бита NX или XD распознаёт такие участки как неисполняемые[12]. В Windows, начиная с версии Vista, в диспетчере задач Windows на Processes/Details (Процесс/Подробно) можно видеть, включена или отключена функция DEP для конкретного процесса.

Windows реализует программное DEP (не используя NX bit) через «безопасную структурированную обработку исключений» Microsoft (SafeSEH). Для корректно скомпилированных приложений SafeSEH гарантирует, что при возникновении исключения во время выполнения программы обработчик этого исключения будет одним из тех, что были определены приложением при его первоначальной компиляции. Эта защита предотвращает возможность злоумышленника подменить штатный обработчик своим собственным, размещённым на странице данных, полученным через непроверенный ввод программы[12][13].

Если поддержка NX поддерживается, она включена по умолчанию. Операционная система Windows позволяет программам управлять тем, какие страницы памяти запрещают выполнение кода, как через свой программный интерфейс (API), так и через заголовки разделов в файлах формата PE. В API доступ к биту NX во время выполнения представляется через вызовы Win32 API VirtualAlloc[Ex] и VirtualProtect[Ex]. Каждая страница может быть индивидуально помечена как исполняемая или неисполняемая. Несмотря на отсутствие аппаратной поддержки x86 в прошлом, настройки для исполняемых и неисполняемых страниц присутствовали с самого начала. На процессорах без поддержки NX наличие атрибута «исполняемый» не имело никакого эффекта. Однако это было задокументировано так, будто оно работает, и, как следствие, большинство программистов использовали его правильно. В формате файлов PE каждый раздел может указывать свою исполняемость. Флаг исполнения существует с самого начала формата, и стандартные компоновщики всегда использовали его корректно, даже задолго до появления бита NX. Благодаря этому Windows может применять бит NX к старым программам. Если программист следовал «лучшим практикам», приложения должны работать корректно теперь, когда NX действительно принудительно применяется. Проблемы возникли лишь в немногих случаях. Среда выполнения .NET Runtime от Microsoft имела проблемы с битом NX и была обновлена.

  • Аппаратно поддерживаемые процессоры: x86-64 (AMD64 и Intel 64), IA-64, Efficeon, Pentium M (поздние версии), AMD Sempron (поздние версии)
  • Эмуляция: Да
  • Другие поддерживаемые: Нет
  • Стандартное распространение: После Windows XP
  • Дата выпуска: 6 августа 2004 года

Xbox

В игровой консоли Xbox от Microsoft, хотя ЦПУ не имеет NX бита, более новые версии XDK устанавливают предел сегмента кода в начале секции .data (в обычных условиях код не должен располагаться после этой точки). Начиная с версии 51xx, это изменение было также внедрено в ядро новых Xbox. Это нарушило работу старых эксплойтов, которые использовали этот механизм для превращения в резидентные программы, остающиеся в памяти после завершения. Однако, вскоре были выпущены новые эксплойты, работающие в этой новой версии ядра, поскольку фундаментальная уязвимость в ядре Xbox осталась неизменной.

Ограничения

В местах, где код пишется и выполняется во время работы (например, JIT-компиляция), компилятор может быть использован для создания эксплойтного кода (например, с помощью JIT Spray), который был помечен для выполнения и поэтому не будет заблокирован[14][15].

Возвратно-ориентированное программирование может позволить выполнить произвольный код, даже когда включена защита исполняемого пространства.

См. также

  • Переполнение буфера
  • Защита от переполнения буфера
  • Переполнение кучи
  • Защита от переполнения буфера
  • Неконтролируемая строка форматирования

Примечания

  1. "Memory Management Security Enhancements", Android Security Overview, retrieved 2012/07/29.
  2. Android code change enabling NX by default. Android Source Repository Change. Дата обращения: 27 августа 2019.
  3. Android Compatibility Requirement for NX. Android Code Review. Дата обращения: 27 августа 2019.
  4. Linux kernel 2.6.8. kernelnewbies.org (14 августа 2004). Дата обращения: 1 августа 2015.
  5. PaX SEGMEXEC documentation (TXT). pax.grsecurity.net (10 сентября 2004). Дата обращения: 25 января 2015.
  6. NetBSD, Non-executable stack and heap, retrieved 2011/07/14.
  7. SecureWave | SecureNT (31 марта 2001). Дата обращения: 27 декабря 2023. Архивировано из оригинала 31 марта 2001 года.
  8. Homepage of PaX - the PAGE_EXEC flag implementation for IA-32 (31 марта 2001). Дата обращения: 27 декабря 2023. Архивировано из оригинала 31 марта 2001 года.
  9. Blog on Cyberterror. Дата обращения: 8 января 2008. Архивировано из оригинала 9 февраля 2012 года.
  10. address space layout randomization. PaX project.
  11. Uninformed - vol 2 article 4. Дата обращения: 19 марта 2010. Архивировано из оригинала 12 марта 2016 года.
  12. 1 2 A detailed description of the Data Execution Prevention (DEP) feature in Windows XP Service Pack 2, Windows XP Tablet PC Edition 2005, and Windows Server 2003. Microsoft (26 сентября 2006). Дата обращения: 11 июля 2008. Архивировано 11 сентября 2014 года.
  13. Johnson, Peter. Yasm User Manual, win32: Safe Structured Exception Handling. Tortall Networks: Open Source and Free Software. Дата обращения: 27 сентября 2015. Архивировано из оригинала 2 января 2015 года.
  14. Dion Blazakis. Interpreter Exploitation: Pointer Inference And JIT Spraying.
  15. Alexey Sintsov. Writing JIT-Spray Shellcode for fun and profit (5 марта 2010). Архивировано 4 марта 2016 года.