Могу ли я защитить от записи каждую страницу в адресном пространстве процесса Linux? - PullRequest
5 голосов
/ 10 августа 2010

Мне интересно, есть ли способ защитить от записи каждую страницу в Linux адресное пространство процесса (изнутри самого процесса, посредством mprotect()). Под «каждой страницей» я имею в виду каждую страницу адресное пространство процесса, которое может быть записано обычным программа работает в пользовательском режиме - так, текст программы, константы, глобалы и куча - но я был бы счастлив только с константами, глобалы и куча. Я не хочу защищать от записи стек - это кажется плохой идеей.

Одна проблема в том, что я не знаю, с чего начать защиту от записи объем памяти. Глядя на /proc/pid/maps, который показывает разделы памяти в использовании для данного PID, они всегда, кажется, начинаются с адреса 0x08048000, с текстом программы. (В Linux, насколько я могу судить, память процесса выложена с текстом программы на снизу, затем константы выше этого, затем глобалы, затем куча, затем пустое пространство разного размера в зависимости от размера кучи или стек, а затем стек, растущий вниз от верхней части памяти в виртуальный адрес 0xffffffff.) Есть способ узнать, где находится верх куча (вызывая sbrk(0), которая просто возвращает указатель на текущий «перерыв», т. е. вершина кучи), но на самом деле не способ скажи, где начинается куча.

Если я попытаюсь защитить все страницы от 0x08048000 до перерыва, я в итоге получаю ошибку mprotect: Cannot allocate memory. Я не знаю, почему mprotect будет в любом случае выделять память - и Google не очень помогает. Есть идеи?

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

Спасибо!

Ответы [ 2 ]

6 голосов
/ 10 августа 2010

Вы получаете ENOMEM от mprotect(), если пытаетесь вызвать его на страницах, которые не отображаются.

Лучше всего открыть /proc/self/maps и прочитать по одной строке за раз с fgets(), чтобы найти все сопоставления в вашем процессе. Для каждого доступного для записи отображения (указано во втором поле), которое не является стеком (указано в последнем поле), вызовите mprotect() с правильными базовым адресом и длиной (рассчитанными из начального и конечного адресов в первом поле).

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

0 голосов
/ 10 августа 2010

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

...