Стековый кадр

Сте́ковый кадр (от англ. stack frame) — механизм передачи аргументов и выделения временной памяти (в процедурах языков программирования высокого уровня) с использованием системного стека.

Технология

Типичный случай использования стека языком высокого уровня на примере вызова процедуры с аргументами «A, B, C» (с соглашениями вызова cdecl) в сравнении с языком ассемблера

Обычно системный стек используется для сохранения адресов возврата при вызове подпрограмм, а также сохранения/восстановления значений регистров процессора.

Передача аргументов

При вызове процедуры аргументы отправляются в стек, и только потом производится вызов подпрограммы. Таким образом, процедура получает стек, на вершине которого лежит адрес возврата, а под ним — аргументы, с которыми она была вызвана.

При возвращении из процедуры (или после него, см. ниже) аргументы должны быть сняты со стека.

Выделение временной памяти

Если указатель стека сместить «выше» (в сторону увеличения стека), то часть памяти в стеке окажется незадействованной (в том числе и при вызове третьей процедуры) и может использоваться процедурой по своему усмотрению, вплоть до момента возврата в вызвавшую её процедуру. Таким образом, языки высокого уровня организуют переменные, существующие только внутри процедуры (язык Си называет их «автоматическими»).

Перед возвратом процедура должна вернуть указатель стека в оригинальное положение (то есть на адрес возврата).

Соглашения для разных языков программирования

Различные компиляторы языков высокого уровня по-разному подходят к организации стекового кадра в зависимости от особенностей аппаратной платформы и стандартов конкретного языка. Основные отличия касаются порядка передачи аргументов в стек и их снятия со стека при возврате.

Недостатки стекового кадра

Стековый кадр — удобная технология выделения временной памяти для передачи произвольного числа аргументов или внутреннего использования. Однако она имеет ряд недостатков.

Производительность

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

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

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

Безопасность

Стековый кадр перемежает данные приложения с критическими данными — указателями, значениями регистров и адресами возврата. Это, в сочетании с архитектурными особенностями некоторых процессоров (а именно — направлением роста стека), делает злонамеренное перекрытие критических данных в результате переполнения буфера очень легко достижимым (разумеется, прежде всего, программа должна содержать ошибку, которая позволит выполнить переполнение).

Такое «неудачное», с точки зрения переполнения буфера, направление роста машинного стека имеют аппаратные платформы: X86.

Атака по переполнению буфера в стеке обычно реализуется следующим образом:

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

См. также

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.