Интересный вопрос; большинство переполнений буфера проходят мимо конца, а не до начала, так что это почти наверняка поможет. Компиляторы могли поместить локальные массивы с наивысшим адресом в стеке стека, поэтому не было бы никаких скалярных локалей, чтобы перезаписать их после массива.
По-прежнему существует опасность, если вы передадите адрес локального массива на другую функцию. Поскольку обратный адрес вызываемой функции будет располагаться чуть позже конца массива.
unsafe() {
char buf[128];
gets(buf); // stack grows upward: exploit happens when gets executes `ret`
// stack grows down: exploit happens when the `ret` at the end of *this* function executes.
}
Так, вероятно, много переполнения буфера все еще будет возможно. Эта идея только побеждает переполнение буфера, когда небезопасный код записи массива встроен, поэтому переполнение происходит с чем-то большим, чем над массивом.
Однако некоторые другие распространенные причины переполнения буфера могут быть легко встроены, например, strcat
. Восходящие стеки помогут иногда.
Меры безопасности не должны быть надежными, чтобы быть полезными, поэтому это определенно поможет иногда. Вероятно, недостаточно для того, чтобы кто-то захотел изменить существующую архитектуру, такую как x86, но интересная идея для новых архитектур. Тем не менее, Stack-grows-down является почти универсальным стандартом для процессоров. Использует ли что-нибудь растущий стек вызовов вверх? Насколько программное обеспечение действительно зависит от этого предположения? Надеюсь, не так много ...
Традиционная планировка оставляло место для кучи и/или в стеке, чтобы расти, только вызывает проблемы, если они встречаются в середине.
Предсказуемые адреса кода/данных более важны, чем предсказуемые адреса стека, поэтому компьютер с большим количеством ОЗУ может уложить стек дальше от данных/кода, а при загрузке кода/данных с постоянным адресом. (Это очень волнительно. Я считаю, что мне повезло не писать реальные 16-битные программы, а только узнавать, но не использовать сегментацию. Возможно, кто-то, кто все еще помнит DOS, может пролить свет на то, почему он хорошо работает, чтобы стек с высоким адресом, вместо растущего вверх уровня в нижней части вашего сегмента и данных/кода вверху, например, с «крошечной» моделью кода, где все находится в одном сегменте).
Единственный реальный шанс изменить это поведение было с AMD64, который в первый раз x86 когда-либо действительно сломана обратной совместимости. Современные процессоры Intel по-прежнему поддерживают 8086 недокументированных кодов операций, таких как D6
: SALC
(Set AL from Carry Flag), что ограничивает пространство для кодирования для расширений ISA. (например.SSSE3 and SSE4 instructions would be 1 byte shorter, если Intel отказалась от поддержки недокументированных кодов операций.
Даже тогда это будет только для нового режима; Процессоры AMD64 по-прежнему должны поддерживать устаревший режим, а в 64-битном режиме они должны смешивать длинный режим с режимом сопоставления (обычно для запуска 32-разрядных процессов пользовательского пространства из 32-разрядных двоичных файлов).
Возможно, AMD64 добавила флаг направления в стек, но это сделало бы оборудование более сложным. Как я уже говорил выше, я не думаю, что это было бы большой выгодой для безопасности. В противном случае, возможно, архитекторы AMD бы это рассмотрели, но все же маловероятны. Они определенно стремились к минимальным навязчивым действиям и не были уверены, что это уловится. Они не хотели зацикливаться на дополнительном багаже, чтобы поддерживать совместимость с AMD64 в своих процессорах, если в мире в основном просто хранились 32-разрядные ОС и 32-битный код.
Это позор, потому что есть много мелких вещей, которые они могли бы сделать, которые, вероятно, не требовали бы слишком большого количества дополнительных транзисторов в исполнительных устройствах. (например, в длинном режиме, замените setcc r/m8
на setcc r/m32
).
Возможно, ваш вопрос лучше подходит для [Security StackExchange.] (Http://security.stackexchange.com/) –
@RyanB Я так не думаю. Вопрос в том, почему стек растет, несмотря на * проблему безопасности (та, которая на самом деле не существовала «назад», когда был разработан x86). –
Учитывая, что 8086 был просто рожден как скромный микроконтроллер, я сомневаюсь, что кто-то рассмотрел последствия для безопасности растущего стека для защиты от ненадежных данных, поступающих от злоумышленников во всемирной сети. ;-) –