Необходимость исполняемого стека и кучи памяти

Поскольку мы знаем, что создание неисполняемого стека и области кучи виртуальной памяти может предотвратить выполнение вредоносного кода (например, шелл-кода) внутри памяти (метод называется Предотвращение выполнения данных). И самый простой способ внедрить вредоносный код внутрь памяти — это переполнить буфер. Таким образом, делая эти области памяти неисполняемыми, можно уменьшить серьезность атак переполнения.

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

Теперь мой вопрос: существуют ли какие-то конкретные операции или особые случаи, в которых части стека/кучи памяти должны быть исполняемыми?


person Rahil Arora    schedule 25.09.2013    source источник
comment
JIT легко реализуется, если куча является исполняемой. Хотя не уверен, как это делается в целом.   -  person    schedule 25.09.2013
comment
Код батута для вложенных функций GCC нуждается в исполняемом стеке, насколько мне известно.   -  person tangrs    schedule 25.09.2013


Ответы (1)


JIT сопоставляют доступные для записи и исполняемые области памяти или просто mprotect ранее выделенную память, чтобы сделать ее исполняемой.

Раньше GCC требовал системно-зависимого метода для пометки исполняемых частей стека для их кода батута. Хотя это было 12 лет назад, я не знаю, как это делается сейчас.

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

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

person Art    schedule 25.09.2013