Dal  manuale : 
  On  Linux it is always permissible to call mprotect() on any address in
  a process's address space (except for the kernel  vsyscall  area).   In
  particular  it  can  be  used  to  change  existing code mappings to be
  writable.
 Ecco un esempio di programma da dimostrare. 
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#define PAGE_SIZE 4096
const unsigned char rodata[3*PAGE_SIZE] = {1,2,3};
int main(void)
{
    printf("rodata = %p\n", rodata);
    uintptr_t page_base = ((uintptr_t)rodata / PAGE_SIZE + 1) * PAGE_SIZE;
    unsigned char *p = (unsigned char *)rodata + PAGE_SIZE;
    //*p = '!'; // this would cause a segfault
    puts("Before mprotect:");
    system("cat /proc/$PPID/maps");
    if (mprotect((void*)page_base, 1, PROT_READ | PROT_WRITE) < 0) {
        perror("mprotect");
        return 1;
    }
    puts("After mprotect:");
    system("cat /proc/$PPID/maps");
    *p = '!';
    return 0;
}
 Ovviamente tutti i dati che scrivi nella pagina rimarranno in memoria. Linux vede che il processo sta scrivendo su una pagina attualmente mappata in sola lettura e ne fa una copia. Al momento della scrittura, il kernel non distingue questo da copia su scrittura dopo che un processo è stato biforcato. Puoi osservare questo attraverso biforcazione, scrittura in un processo e lettura nell'altro: l'altro processo non vedrà la scrittura poiché è una scrittura nella memoria del processo di scrittura, non nella memoria del processo di lettura. 
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#define PAGE_SIZE 4096
const unsigned char rodata[3*PAGE_SIZE] = {0};
void writer(char *p)
{
    if (mprotect(p, 1, PROT_READ | PROT_WRITE) < 0) {
        perror("mprotect");
        return 1;
    }
    puts("After mprotect:");
    system("cat /proc/$PPID/maps");
    *p = 1;
    printf("wrote %d\n", *p);
}
void reader(char *p)
{
    printf("read %d\n", *p);
}
int main(void)
{
    printf("rodata = %p\n", rodata);
    uintptr_t page_base = (((uintptr_t)rodata / PAGE_SIZE + 1) * PAGE_SIZE);
    volatile char *p = (volatile char *)page_base;
    //*p = '!'; // this would cause a segfault
    puts("Before mprotect:");
    system("cat /proc/$PPID/maps");
    if (fork() == 0) {
        writer(p);
    } else {
        sleep(1);
        reader(p);
    }
    return 0;
}
 Ho il sospetto che ci siano patch indurenti che impediscono a un processo di modificare i propri mapping della memoria, ma non ne ho uno da offrire.