linux c проблема с mmap/mprotect

Мне нужно сделать небольшой sw, который должен защищать страницу для чтения/записи, а затем, когда осуществляется доступ к памяти, ему нужно увеличить счетчик и разрешить чтение/запись, после чего ему нужно затем защитить память обратно

У меня есть этот код, но он вызывает бесконечный цикл

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static int alloc_size;
static char* memory;

void segv_handler (int signal_number) 
{
 printf ("memory accessed!\n");
 /* allow read and write */
 mprotect (memory, alloc_size, PROT_READ | PROT_WRITE);

 /* Protect memory back*/
 mprotect (memory, alloc_size, PROT_NONE);
} 

int main ()
{
 struct sigaction sa;

 /* Install segv_handler as the handler for SIGSEGV. */
 memset (&sa, 0, sizeof (sa));
 sa.sa_handler = &segv_handler;
 sigaction (SIGSEGV, &sa, NULL);

 alloc_size = 4096;
 memory = mmap (0, alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);   /* anonymous mapping doesn't need a file desc */

 /* Write to the page to obtain a private copy. */
 memory[0] = 0;
 memory[1] = 0;

 /* Make the memory unwritable. */
 mprotect (memory, alloc_size, PROT_NONE);
 /* Write to the allocated memory region. */
 memory[0] = 1; //--> this should trigger the SIGSEGV
 memory[1] = 1;

 /* All done; unmap the memory. */
 printf ("all done\n");
 munmap (memory, alloc_size);
 return 0;
}

person emalware    schedule 12.08.2012    source источник
comment
возможный дубликат Напишите обработчик сигнала для перехвата SIGSEGV   -  person Chris Dodd    schedule 12.08.2012
comment
Я читал это, но, если возможно, пример кода будет отличным, потому что у других ребят много других проблем, и, кроме того, у меня всего 2 недели кодирования на C.   -  person emalware    schedule 12.08.2012


Ответы (2)


Вы сказали, что хотите в основном (1) поймать недопустимый доступ к памяти, (2) временно снять защиту со страницы, (3) разрешить доступ к памяти, (4) повторно защитить страницу, (5) возобновить нормальное выполнение. Но это не то, что делает ваш код. Ваш segv_handler снимает защиту со страницы (шаг 2), а затем сразу же повторно защищает ее (шаг 4), поэтому к тому времени, когда ваш segv_handler вернется, будет слишком поздно для шага 3. Инструкция снова дает сбой, и вы получаете бесконечный цикл.

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

ptrace — это системный вызов, который вам понадобится для этого. Их много вопросы по SO, в которых говорится о ptrace и пошаговом режиме, но предупреждаю: ptrace не для слабонервных, это намного сложнее, чем обработчик сигнала.

person Celada    schedule 12.08.2012
comment
разве эта строка не разрешает чтение и запись mprotect (memory, alloc_size, PROT_READ | PROT_WRITE);. это часть домашнего задания, мне нужно использовать сигналы - person emalware; 13.08.2012
comment
да, это разрешит доступ, но уже следующая строка mprotect (memory, alloc_size, PROT_NONE); отменяет эффект. - person Celada; 13.08.2012
comment
тогда вы знаете какой-нибудь вариант с использованием сигналов? - person emalware; 13.08.2012
comment
Пожалуйста, прочитайте, что я написал в своем ответе: установка обработчика сигналов не поддерживает то, что вам нужно делать. - person Celada; 13.08.2012
comment
спасибо, Селада, я видел ваш ответ, но, по словам моего профессора операционной системы, это можно сделать с помощью mmap, mprotect и сигналов - person emalware; 13.08.2012

Я думаю, вы можете использовать какую-нибудь библиотеку дизассемблирования, такую ​​как Libasm, чтобы добиться этого, но это не так. выглядит так хорошо.

В вашем segv_handler,

  1. Разрешить чтение/запись на страницу
  2. Загрузите последнюю инструкцию, вызывающую SIGSEGV, поместите ее в исполняемую память и запустите.
  3. Применить защиту обратно
  4. Делайте что хотите (увеличивайте счетчик)
  5. Прежде чем segv_handler вернется, измените адрес возврата в стеке на следующую инструкцию, чтобы вам не приходилось запускать эту инструкцию дважды и снова ловить сигнал.
person ItsEddy    schedule 13.02.2015