名前
mprotect - メモリ領域のアクセス許可を制御する
書式
#include <sys/mman.h>
int mprotect(const void *addr, size_t len, int prot);
説明
mprotect() は区間 [addr,addr+len-1] の一部またはすべてを含む メモリページの所望のアクセス保護を指定する。 指定したアクセス保護で禁止されたアクセスを行なうと、 プログラムは SIGSEGV を受信する。
prot は以下の値のビットごとの論理和 (bitwize-or) である:
PROT_NONE | そのメモリには全くアクセスできない。 |
PROT_READ | そのメモリを読み取ることができる。 |
PROT_WRITE | そのメモリに書き込むことができる。 |
PROT_EXEC | そのメモリに実行コードを含むことができる。 |
返り値
成功した場合、 mprotect() は 0 を返す。エラーの場合は -1 が返り、 errno が適切に設定される。
エラー
EACCES | 指定されたアクセスをメモリに設定することができない。 これは、例えば ファイルを読み取り専用で mmap(2) しており、その領域に対して mprotect() を呼び出して PROT_WRITE に設定しようとした場合に発生する。 |
EFAULT | メモリがアクセス可能でない。 |
EINVAL | addr が有効なポインタでないか、PAGESIZE の倍数でない。 |
ENOMEM | カーネル内部の構造体を割り当てることができなかった。 もしくは、 [addr, addr+len] という範囲のアドレスがプロセスのアドレス空間として不正であるか、 その範囲のアドレスがマップされていない 1 つ以上のページを指した。 |
準拠
SVr4, POSIX.1-2001. POSIX では、 mprotect() は mmap(2) で獲得したメモリ領域に対してのみ使用できるとしている。
注意
Linux では、(カーネル vsyscall 領域以外の) 任意のプロセスアドレス空間において mprotect() を呼び出すことが、常に許されている。 これは特に既存のコードマッピングを書き込み可能にするために使われる。
PROT_EXEC が PROT_READ と異なる影響を持つか否かは、アーキテクチャとカーネルのバージョンに依存する。
例
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#include <limits.h> /* PAGESIZE を使用するため */
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif
int
main(void)
{
char *p;
char c;
/* バッファを確保する。デフォルトのアクセス保護
PROT_READ|PROT_WRITE になる。*/
p = malloc(1024+PAGESIZE-1);
if (!p) {
perror("Couldnt malloc(1024)");
exit(errno);
}
/* PAGESIZE の倍数にアラインメントをそろえる。
PAGESIZE は 2 の累乗であると仮定する。*/
p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
c = p[666]; /* 読み取り; 成功 */
p[666] = 42; /* 書き込み; 成功 */
/* バッファを読み取り専用に設定する。*/
if (mprotect(p, 1024, PROT_READ)) {
perror("Couldnt mprotect");
exit(errno);
}
c = p[666]; /* 読み取り; 成功 */
p[666] = 42; /* 書き込み; プログラムは SIGSEGV で強制終了する */
exit(EXIT_SUCCESS);
}