JohnnyOnPc
JohnnyOnPc

Reputation: 444

Trying to catch SIGSEGV signal in C

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

Answers (1)

Nate Eldredge
Nate Eldredge

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

Related Questions