MPROTECT(2) | Linux Programmer's Manual | MPROTECT(2) |
名前
mprotect -メモリ領域の保護を設定する書式
#include <sys/mman.h>
int mprotect(void * addr , size_t len , int prot );
説明
mprotect() は、区間 [ addr, addr+ len-1] のアドレス範囲を含む呼び出し元のプロセスのメモリページのアクセス保護を変更する。 addr はページ境界に一致していなければならない。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() を呼び出すことが、常に許されている。これは特に既存のコードマッピングを書き込み可能にするために使われる。例
以下のプログラムは、メモリページを 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.51 の一部である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。2012-08-14 | Linux |