Manpages

名 前

mprotect − メ モ リ ー 領 域 の 保 護 を 設 定 す る

書 式

#include <sys/mman.h>

int mprotect(void *addr, size_t len, int prot);

説 明

mprotect() は 、 区 間 [addraddr+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_EXECPROT_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/ に 書 か れ て い る 。