Just to understand how things work, I am trying to allocate some memory from the kernel with mmap
and then set the protection bits such that any memory access causes a segmentation fault, after that I want to try and set the protection bits to be such that the segmentation fault does not happen again.
The call to mprotect fails, and the address in si_addr
is wrong even though the linux man page for sigaction
says that the siginfo
struct's si_addr
function contains the address that causes the fault. And the address is not the address that was allocated in the main()
function. The code works fine on a mac
#define _XOPEN_SOURCE
#include <iostream>
#include <signal.h>
#include <ucontext.h>
#include <sys/mman.h>
#include <string.h>
#include <cstdlib>
using std::cout;
using std::cerr;
using std::endl;
void handle_signal(int signal_number, siginfo_t* signal_info, void* context);
void register_signal_handler();
int counter = 0;
int main() {
register_signal_handler();
int* page_mapped = (int*) mmap(nullptr, 100, PROT_NONE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (page_mapped == MAP_FAILED) {
cerr << "mmap failed" << endl;
}
cout << "page mapped is " << reinterpret_cast<uintptr_t>(page_mapped)
<< endl;
// cause the segmentation fault
cout << *page_mapped << endl;
return 0;
}
void handle_signal(int, siginfo_t* siginfo, void*) {
cout << "Handled a segmentation fault" << endl;
cout << "The segmentation fault was caused by the address "
<< reinterpret_cast<uintptr_t>(siginfo->si_addr) << endl;
if (mprotect(siginfo->si_addr, 100, PROT_READ | PROT_WRITE) == -1) {
cerr << "mprotect failed" << endl;
exit(1);
}
// stop an infinite loop
++counter;
if (counter == 3) {
cerr << "Counter got to 3, probably going into an infinite loop.. "
"stopping" << endl;
exit(1);
}
}
void register_signal_handler() {
struct sigaction sigaction_information;
memset(&sigaction_information, 0, sizeof(struct sigaction));
sigaction_information.sa_sigaction = &handle_signal;
sigaction(SIGSEGV, &sigaction_information, nullptr);
}