【问题标题】:linux c mmap/mprotect issuelinux c mmap/mprotect问题
【发布时间】:2012-08-08 18:37:58
【问题描述】:

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

【问题讨论】:

  • 我读过这篇文章,但如果可能的话,一个代码示例会很棒,因为其他人还有很多其他问题,而且我只有 2 周的 C 编码时间

标签: c linux mmap mprotect


【解决方案1】:

你说你想基本上(1)捕获无效的内存访问,(2)暂时取消保护页面,(3)允许内存访问,(4)重新保护页面,(5)恢复正常执行。但这不是您的代码所做的。您的 segv_handler 取消保护页面(第 2 步),然后立即再次重新保护它(第 4 步),所以当您的segv_handler 返回时,第 3 步已经太晚了。指令再次出错,您将进入无限循环。

安装信号处理程序不支持您需要执行的操作。您需要做的是进行一些更改,执行一条指令,然后再进行一些更改。只有在调试器下单步执行程序才能执行此操作。

ptrace 是您需要执行此操作的系统调用。 SO上有manyquestions谈论ptrace和单步,但我警告你:ptrace不适合胆小的人,它比信号处理程序复杂得多。

【讨论】:

  • 这一行是不是允许读写 mprotect (memory, alloc_size, PROT_READ | PROT_WRITE);。这是作业的一部分,我需要使用信号
  • 是的,它会允许访问,但下一行 mprotect (memory, alloc_size, PROT_NONE); 会取消效果。
  • 那么,您知道使用信号的任何选项吗?
  • 请阅读我在回答中写的内容:“安装信号处理程序不支持您需要做的事情。”。
  • 感谢 Celada,我看到了你的回答,但根据我的操作系统教授的说法,这可以使用 mmap、mprotect 和信号来完成
【解决方案2】:

我认为你可以使用一些反汇编库如Libasm 来实现这一点,但它看起来不会那么好。

在你的segv_handler

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

【讨论】:

    猜你喜欢
    • 2012-03-05
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 2020-04-11
    • 1970-01-01
    相关资源
    最近更新 更多