Provided by: manpages-ja-dev_0.5.0.0.20131015+dfsg-2_all
名前
mprotect - メモリ領域の保護を設定する
書式
#include <sys/mman.h> int mprotect(void *addr, size_t len, int prot);
説明
mprotect() は、区間 [addr, addr+len-1] のアドレス範囲を含む 呼び出し元のプロセスのメモリ ページのアクセス保護を変更する。 addr はページ境界に一致していなければならない。 呼び出し元のプロセスがアクセス保護に違反するようなメモリアクセスを 行おうとすると、カーネ ルはシグナル SIGSEGV をそのプロセスに対して生成する。 prot には、 PROT_NONE か、以下のリストの PROT_NONE 以外の値をビット毎の論理和 (bitwize-or) で指定する: PROT_NONE そのメモリには全くアクセスできない。 PROT_READ そのメモリを読み取ることができる。 PROT_WRITE そのメモリを変更できる。 PROT_EXEC そのメモリは実行可能である。
返り値
成功した場合、 mprotect() は 0 を返す。エラーの場合は -1 が返り、 errno が適切に設定され る。
エラー
EACCES 指定されたアクセスをメモリに設定することができない。 これは、例えば ファイルを読み 取り専用で mmap(2) しており、その領域に対して mprotect() を呼び出して PROT_WRITE に設定しようとした場合に発生する。 EINVAL addr が有効なポインタでないか、 システムのページサイズの倍数でない。 ENOMEM カーネル内部の構造体を割り当てることができなかった。 ENOMEM [addr, addr+len-1] という範囲のアドレスがプロセスのアドレス空間として不正であるか、 その範囲のアドレスがマップされていない 1 つ以上のページを指している (カーネル 2.4.19 より前では、この状況でエラー EFAULT が間違って生成されていた)。
準拠
SVr4, POSIX.1-2001. POSIX では、 mmap(2) 経由で獲得していないメモリ領域に対して mprotect() を行った場合の mprotect() の動作は未定義であるとされている。
注意
Linux では、(カーネル vsyscall 領域以外の) 任意のプロセスアドレス空間に対して mprotect() を呼び出すことが、常に許されている。 これは特に既存のコードマッピングを書き込み可能にする ために使われる。 PROT_EXEC が PROT_READ と異なる影響を持つか否かは、アーキテクチャとカーネルのバージョンに 依存する。 (i386 などの) いくつかのアーキテクチャでは、 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 handle_error(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) handle_error("sigaction"); pagesize = sysconf(_SC_PAGE_SIZE); if (pagesize == -1) handle_error("sysconf"); /* Allocate a buffer aligned on a page boundary; initial protection is PROT_READ | PROT_WRITE */ buffer = memalign(pagesize, 4 * pagesize); if (buffer == NULL) handle_error("memalign"); printf("Start of region: 0x%lx\n", (long) buffer); if (mprotect(buffer + pagesize * 2, pagesize, PROT_READ) == -1) handle_error("mprotect"); for (p = buffer ; ; ) *(p++) = 'a'; printf("Loop completed\n"); /* Should never happen */ exit(EXIT_SUCCESS); }
関連項目
mmap(2), sysconf(3)
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.54 の一部 である。プロジェクト の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。