【问题标题】:How to trigger a memory range access exception?如何触发内存范围访问异常?
【发布时间】:2017-08-06 11:12:53
【问题描述】:

程序在对可配置的内存区域进行写访问时如何发出信号?

这类似于某些调试器中的数据断点功能。需要 POSIX 合规性,但只要它在 Linux 上运行就不需要。

这里有一个我想要的说明性代码:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void configure_trap(void *FROM, void *TO){
  /*
  Set a trap on write access to any memory location from
    address FROM to address TO.
  When the trap is triggered, send SIGTRAP to the process.
  There is no need for an answer to have the full code, just
    an indication on how to proceed.
  */
}

char *ptr;

void trap_signal_handler(int signum){
  if(ptr[123] == 'x'){
    printf("Invalid value in ptr[123] !!!\n");
    /*
    Print a backtrace using libunwind. (Not part of this question.)
    */
  }
}

void some_function(){
  ptr[123] = 'x';
  /*
  This write access could be performed directly in this function or
    another function called directly or indirectly by this one and it
    could reside in this program or in an external library or could even
    be performed in a system call.
  trap_signal_handler should be called at this point.
  After the signal handler has been executed, program should resume
    normal operation.
  */
}

int main(){
  struct sigaction sa = { .sa_handler = trap_signal_handler };
  sigaction(SIGTRAP, &sa, NULL);
  ptr = malloc(1024);
  configure_trap(&ptr[123], &ptr[123]);
  some_function();
  return(0);
}

谢谢!

【问题讨论】:

    标签: c posix


    【解决方案1】:

    首先,使用mprotect() 将页面标记为只读。然后当它被写入时,SIGSEGV 将被提升。您将为此安装一个信号处理程序,如果使用sigaction 完成,您可以通过检查si_addr 知道访问了哪个地址。有关这方面的更多信息,请参阅:C SIGSEGV Handler & Mprotect

    请注意,mprotect() 的粒度为一页,这意味着如果您尝试保护单个字节,您实际上将保护 4 KB(如果这是您的页面大小)。

    【讨论】:

    • 写入完成后如何使用这种方法调用trap_signal_handler
    • @vicencb:你不能。
    • 在实践中,页面被标记为不可访问,因此对页面的所有访问都会导致 SIGSEGV;并且信号处理程序模拟指令。这是对多个(初始)访问可靠地工作的唯一方法。然后,信号处理程序可以引发另一个信号,或者直接调用另一个信号处理程序(使用修改后的siginfo_t 结构)。当然,所有这些都是特定于硬件的。
    • @JohnZwinck:感谢您的回答,它帮助我找到了解决方案。我已将其作为另一个答案发布。
    【解决方案2】:

    使用https://github.com/vicencb/qdbp 项目。

    1. 它首先将内存页mprotects 设为只读。
    2. 当出现SIGSEGV 时,它会单步执行您的程序,一次执行一条指令,直到导致写入只读内存的指令。
    3. 然后它会调用您的回调。

    【讨论】:

      猜你喜欢
      • 2021-05-20
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-23
      • 2014-04-05
      • 2015-07-10
      • 2023-04-08
      相关资源
      最近更新 更多