Provided by: manpages-ja-dev_0.5.0.0.20180315+dfsg-1_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) static 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.79 の一部 である。プロジェクト の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。