#include <sys/mman.h> int mprotect(const void *addr, size_t len, int prot);
呼び出し元のプロセスがアクセス保護に違反するようなメモリアクセスを 行おうとすると、カーネルはシグナル SIGSEGV をそのプロセスに対して生成する。
prot には、 PROT_NONE か、以下のリストの PROT_NONE 以外の値をビット毎の論理和 (bitwize-or) で指定する:
PROT_EXEC が PROT_READ と異なる影響を持つか否かは、アーキテクチャとカーネルのバージョンに依存する。 (x86 などの) いくつかのアーキテクチャでは、 PROT_WRITE をセットすると、暗黙のうちに PROT_READ がセットされる。
POSIX.1-2001 では、 prot で指定されていないアクセスを許可する実装を認めている。 ただし、最低限、 PROT_WRITE がセットされている場合にのみ書き込みアクセスが許可され、 PROT_NONE がセットされている場合にはアクセスは許可されない点だけは 満たす必要がある。
以下のプログラムは、メモリページを 4つ確保し、そのうち 3番目のページを 読み込み専用に設定する。その後で、確保した領域のアドレスの小さい方から 大きな方に向かって順番にバイト値を変更するループを実行する。
プログラムを実行した場合の一例を以下に示す。
$ ./a.out Start of region: 0x804c000 Got SIGSEGV at address: 0x804e000
#include <unistd.h> #include <signal.h> #include <stdio.h> #include <malloc.h> #include <stdlib.h> #include <errno.h> #include <sys/mman.h> #define die(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) char *buffer; static void handler(int sig, siginfo_t *si, void *unused) { printf("Got SIGSEGV at address: 0x%lx\n", (long) si->si_addr); exit(EXIT_FAILURE); } int main(void) { char *p; int pagesize; struct sigaction sa; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); sa.sa_sigaction = handler; if (sigaction(SIGSEGV, &sa, NULL) == -1) die("sigaction"); pagesize = sysconf(_SC_PAGE_SIZE); if (pagesize == -1) die("sysconf"); /* Allocate a buffer aligned on a page boundary; initial protection is PROT_READ | PROT_WRITE */ buffer = memalign(pagesize, 4 * pagesize); if (buffer == NULL) die("memalign"); printf("Start of region: 0x%lx\n", (long) buffer); if (mprotect(buffer + pagesize * 2, pagesize, PROT_NONE) == -1) die("mprotect"); for (p = buffer ; ; ) *(p++) = 'a'; printf("Loop completed\n"); /* Should never happen */ exit(EXIT_SUCCESS); }