Rechercher une page de manuel
mprotect
Langue: ja
Version: 2007-06-02 (fedora - 25/11/07)
Section: 2 (Appels système)
名前
mprotect - メモリ領域の保護を設定する書式
#include <sys/mman.h> int mprotect(const 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 に設定しようとした場合に発生する。
- EFAULT
- メモリがアクセス可能でない。
- EINVAL
- addr が有効なポインタでないか、 システムのページサイズの倍数でない。
- ENOMEM
- カーネル内部の構造体を割り当てることができなかった。 もしくは、 [addr, addr+len] という範囲のアドレスがプロセスのアドレス空間として不正であるか、 その範囲のアドレスがマップされていない 1 つ以上のページを指した。
準拠
SVr4, POSIX.1-2001. POSIX では、 mmap(2) 経由で獲得していないメモリ領域に対して mprotect() を行った場合の mprotect() の動作は未定義であるとされている。注意
Linux では、(カーネル vsyscall 領域以外の) 任意のプロセスアドレス空間に対して mprotect() を呼び出すことが、常に許されている。 これは特に既存のコードマッピングを書き込み可能にするために使われる。PROT_EXEC が 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); }
関連項目
mmap(2), sysconf(3)Contenus ©2006-2024 Benjamin Poulain
Design ©2006-2024 Maxime Vantorre