C SIGSEGV and Mprotect handler

I am creating a program that uses mprotect () to restrict access to a block of memory. When memory is requested, SIGSEGV is called, which I listen to to call the signal ().

After detecting SIGSEGV, I need to somehow access the pointer to the requested memory (which caused the error) and the size of the requested segment. Is it possible?

void fifoSigHandler(){ // Needs to only remove protection from requested block of virtual memory mprotect(fifoVm,(size_t)fifoVm_size,PROT_WRITE); printf("Caught Seg Fault"); } void fifo_init(void* vm, int vm_size, int n_frames, int page_size) { fifoVm = vm; fifoVm_size = vm_size; fifoFrames = n_frames; fifoPageSize = page_size; mprotect(fifoVm,(size_t)fifoVm_size,PROT_NONE); signal(SIGSEGV, fifoSigHandler); } 

Also, is there a way to determine the level of mprotect () that the memory block is currently assigned to (PROT_NONE, PROT_READ, etc.)?

+4
source share
3 answers

You must use sigaction instead of SA_SIGINFO instead of signal to set the handler, and then you will get a backlink with useful information in siginfo_t , including si_addr .

si_addr , as described in sigaction (2), will contain the address. As for the length, well, you're out of luck if you're not ready to take apart the instructions. The best you can do is take action for the page specified in si_addr , and then if that is not enough, you will get another signal soon enough. At least the way we did things in the ObjectStore.

+5
source

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

But be careful that calling mprotect is safe only for Linux, other POSIX systems may not support this.

I'm afraid that on Linux, the only way to get the memory protection bit is to read /proc/$pid/meminfo

On the side of the note (Linux only): if you are worried about memory consumption and intend to include pages with a large mapping one at a time, I would advise creating your mapping using mmap with MAP_NORESERVE , in which case you will get a mapping with zero copy-to-write pages that will allocate physical memory on the first recording. MAP_NORESERVE instructs the kernel not to support your memory with the swap space, allowing you to allocate up to 64 TB of virtual address space. The only drawback is that if you run out of memory, terrible things (oom-killer) can happen.

+1
source

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 descriptor SIGSEGV :

 sigaction(SIGSEGV, &act, NULL); 

(Optional) Step 3 : also process other memory signals:

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

Add error handling if necessary

Step 4 Define a 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 manual pages for ucontext_t and siginfo_t for more interesting data that your handler can extract.

0
source

Source: https://habr.com/ru/post/1307888/


All Articles