Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C SIGSEGV Handler & Mprotect

I'm constructing a program which uses mprotect() to restrict a block of memory from accessing. When the memory is requested, a SIGSEGV is thrown which I listen for using a signal() call.

Once the SIGSEGV has been detected, I need to somehow access the pointer to the memory that was requested (that threw the fault) and the size of the segment requested. Is this 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);
}

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

like image 346
pws5068 Avatar asked Feb 27 '23 03:02

pws5068


2 Answers

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.

like image 139
bmargulies Avatar answered Mar 04 '23 03:03

bmargulies


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).

like image 32
Sergey L. Avatar answered Mar 04 '23 01:03

Sergey L.