Память ниже %esp
может быть засорена асинхронно (обработчиком сигнала 1 ), но поведение вашей программы не зависит от значений, которые вы читаете / записываете с addl $5, -8(%ebp)
или movl -8(%ebp), %eax
, в этом 4-байтовом слоте стека прямо под ESP.
В Linux не является ошибкой касаться памяти ниже ESP, вплоть до предела максимального размера стека (ulimit -s
, по умолчанию 8192 КБ).Если память еще не отображена, отображение стека автоматически расширяется, чтобы отобразить все страницы между ними и отображаемой в данный момент страницей стека с наименьшим адресом.(Или для стека потоков он уже будет полностью выделен, а не увеличен на лету. Но начальный стек процессов является специальным.)
Если вы запустили push
вцикл (без pop
или чего-либо еще, чтобы уравновесить его), стек будет расти до тех пор, пока ESP не уменьшится, чтобы указать на не отображенную страницу за пределами того места, где ядро будет наращивать стек для вас.Тогда следующий push
(или call
или любой другой) будет segfault, и мы назовем это переполнением стека.
переполнение буфера будет, если вы это сделаетеsub $12, %esp
чтобы зарезервировать место для int arr[3]
, но затем написал int arr[5]
: это перезапишет ваш обратный адрес, так что возможный ret
будет прыгать туда, куда злоумышленник хотел, чтобы вы прыгнули.
# arg in EAX: how many array elements to store into arr[3]
vulnerable_function:
sub $12, %esp
mov %esp, %ecx
.Lloop:
mov %eax, (%ecx)
add $4, %ecx
dec %eax
jnz
add $12, %esp
ret
Сноска 1 : вы не установили никаких обработчиков сигналов, поэтому (в Linux) ничто не может использовать стековую память асинхронно, и у вас есть неограниченная красная зона ниже ESP.
Но это особый случай, когда вы пишете законченную программу и не используете никаких библиотек, обычно вам просто нужно встроить небольшие функции, если дополнительные инструкции по резервированию и освобождению стекового пространства имеют нетривиальную стоимость.