Reputation: 444
My aim is to change the permission on a virtual memory zone, from read-only
to read-write
. This should happen only after a SIGSEGV signal has happened.
I have registered a handler for the SIGSEGV signal, and also found a way of changing the permission to read-write
.
The current issue that I am facing is that the handler doesn't get executed.
Any ideas?
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <stdlib.h>
void sigint_handler(int signo, siginfo_t *var, void *unused){
mprotect(var->si_addr, 4, PROT_WRITE);
}
const char str[4] = "abc";
int main(){
struct sigaction act;
act.sa_sigaction = sigint_handler;
sigfillset(&act.sa_mask);
sigaction(SIGSEGV, &act, NULL);
printf("%s\n", str);
//printf("-->%d\n",str[-1000]);
memcpy(str, "123", strlen("123"));
printf("%s\n", str);
return (0);
}```
Upvotes: 0
Views: 500
Reputation: 58142
Two main bugs:
When calling sigaction
, you have to set the SA_SIGINFO
flag in act.sa_flags
in order to have the second argument passed to your signal handler. As it stands that field is just uninitialized.
mprotect
requires that its addr
argument be page aligned. (This will also require you to recompute the len
argument accordingly to ensure the desired region is covered.) As a quick-and-dirty example, assuming the page size is 4096, you can mask off the corresponding low bits by ANDing with the bitwise complement of 4095.
uintptr_t orig = (uintptr_t)var->si_addr;
uintptr_t aligned = orig & ~4095UL;
mprotect((void *)aligned, orig + 4 - aligned, PROT_WRITE) < 0);
Both requirements are explained in the corresponding man pages. Checking for error returns from your system calls would also have helped you narrow down the problem (you'd have seen that your signal handler does execute but the mprotect
call fails because of invalid arguments).
With these fixed, the program works as intended for me under Linux.
Upvotes: 2