Это Ubuntu 9.04, 2.6.28-11-server, 32bit x86
$ cat test.c
main() { int *dt = (int *)0x08049f18; *dt = 1; }
$ readelf -S ./test
...
[18] .dtors PROGBITS 08049f14 000f14 000008 00 WA 0 0 4
...
$ ./test
Segmentation fault
$
Для непосвященных: gcc создает сегмент деструктора .dtors
в исполняемом файле elf, который вызывается после main()
выхода. Эта таблица уже давно доступна для записи, и похоже, что так и должно быть в моем случае (см. readelf
Вывод). Но попытка записи в таблицу приводит к ошибке.
Я понимаю, что в последнее время произошло движение к readonly .dtors, plt, но чего я не понимаю, так это несоответствия между readelf
segfault.
memory
gcc
segmentation-fault
Fixee
источник
источник
Ответы:
Эти разделы помечены GNU_RELRO (перемещение только для чтения), что означает, что как только динамический загрузчик исправил (во время загрузки, там нет ленивых перемещений) все перемещения, он отмечает эти разделы только для чтения. Обратите внимание, что большая часть
.got.plt
находится на другой странице, поэтому не получает лечения.Вы можете увидеть скрипт компоновщика
ld --verbose
, если вы ищете RELRO, вы найдете что-то похожее на:это означает, что разделы RELRO заканчиваются 12 байтами в
.got.plt
(указатели на функции динамического компоновщика уже разрешены, поэтому могут быть помечены только для чтения).Закаленный проект Gentoo содержит некоторую документацию по RELRO по адресу http://www.gentoo.at/proj/en/hardened/hardened-toolchain.xml#RELRO .
источник
Я могу сказать, почему это терпит неудачу, хотя я фактически не знаю, какая часть системы ответственна. Хотя
.dtors
он помечен как записываемый в двоичном файле, похоже, что он (наряду с.ctors
GOT и некоторыми другими вещами) отображается на отдельной недоступной для записи странице в памяти. В моей системе.dtors
ставится на0x8049f14
:Если я запускаю исполняемый файл и проверяю
/proc/PID/maps
, я вижу:.data
/.bss
по-прежнему доступны для записи на своей странице, а остальные0x8049000-0x804a000
нет. Я предполагаю, что это функция безопасности в ядре (как вы сказали, «в последнее время наблюдается движение к readonly .dtors, plt, got»), но я не знаю, как именно это называется (в OpenBSD есть нечто очень похожее, называемое W ^ X ; Linux имеет PaX , но не встроен в большинство ядер)Вы можете обойти это с помощью
mprotect
, который позволяет вам изменять атрибуты в памяти страницы:При этом моя тестовая программа не завершается сбоем, но если я попытаюсь перезаписать конечный страж функции
.dtors
(0x8049f18
) адресом другой функции, эта функция все равно не будет выполнена; эту часть я не могу понять.Надеюсь, кто-то еще знает, что отвечает за то, чтобы сделать страницу доступной только для чтения, и почему изменение
.dtors
, похоже, ничего не делает в моей системеисточник
mprotect
не может сделать исполняемую страницу доступной для записи или сделать исполняемый файл страницы, который был доступен для записи раньше, если эта функция не отключена с помощьюpaxctl -m
.