C SIGSEGV Handler & Mprotect

孤人 提交于 2019-11-29 07:54:43

You have to use sigaction with SA_SIGINFO instead of signal to establish your handler, and then you will get called back with useful information in a siginfo_t, including si_addr.

si_addr, as explained in sigaction(2), will contain the address. As for the length, well, you're out of luck unless you're willing to parse instructions. Best you can do is take action for the page reported in si_addr, and then if that's not enough, you'll get another signal soon enough. At least, that's how we did things in ObjectStore.

You are looking for libsigsegv http://libsigsegv.sourceforge.net/

But beware that calling mprotect is only signal-safe in Linux, other POSIX systems may not support this.

I am afraid that in Linux the only way to get memory protection bits is to read in /proc/$pid/meminfo

On a side note (Linux only): If you are worried about memory consumption and intend to enable pages of a larger mapping one by one then I would advise to create your mapping using mmap with MAP_NORESERVE in which case you will get a mapping to zero-filled copy-on-write pages which will allocate physical RAM on the first write. MAP_NORESERVE instructs the kernel not to back your memory with swap space allowing you to allocate up to 64TB of virtual address space. Only downside is that if you do run out of memory terrible things can happen (oom-killer).

Step 1: Init a sigaction:

struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;

Step 2: Make this sigaction handle SIGSEGV:

sigaction(SIGSEGV, &act, NULL);

(Optional) Step 3: Make it handle other memory signals too:

sigaction(SIGBUS, &act, NULL);
sigaction(SIGTRAP, &act, NULL);

Add error handling as necessary

Step 4: Define the handler function:

void handler(int signal, siginfo_t* siginfo, void* uap) {
    printf("Attempt to access memory at address %p\n", 
           siginfo->si_addr);
    #ifdef LINUX_64BIT
    printf("Instruction pointer: %p\n",
           (((ucontext_t*)uap)->uc_mcontext.gregs[16]));
    #elif LINUX_32BIT
    printf("Instruction pointer: %p\n",
           (((ucontext_t*)uap)->uc_mcontext.gregs[14]));
    #endif
}

You can refer to the man pages for ucontext_t and siginfo_t for more interesting data your handler can extract.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!