2

我需要做一个小 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;
}
4

2 回答 2

0

You said you want to basically (1) catch the invalid memory access, (2) temporarily unprotect the page, (3) allow the memory access, (4) reprotect the page, (5) resume normal execution. But that's not what your code does. Your segv_handler unprotects the page (step 2) and then immediately reprotects it again (step 4), so by the time your segv_handler returns it's too late for step 3. The insruction faults again and you get an infinite loop.

Installing a signal handler does not support what you need to do. What you need to do is make some changes, execute a single instruction, then make some more changes. Only single-steping the program under a debugger will allow you to do this.

ptrace is the system call you will need to do this. There are many questions on SO that talk about ptrace and single stepping, but I warn you: ptrace is not for the faint of heart, it's a lot more complicated than a signal handler.

于 2012-08-12T22:26:24.910 回答
0

我认为您可以使用诸如Libasm之类的反汇编库来实现此目的,但看起来不会那么好。

在你的segv_handler,

  1. 允许读/写页面
  2. 加载导致 SIGSEGV 的最后一条指令,将其放入可执行内存并运行它。
  3. 应用保护回来
  4. 做你想做的事(增加一个计数器)
  5. segv_handler返回之前,将堆栈上的返回地址修改为下一条指令,这样您就不会运行该指令两次并再次捕获信号。
于 2015-02-13T16:31:55.663 回答