Provided by: manpages-ja-dev_0.5.0.0.20140515+dfsg-2_all bug

名前

       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_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.65 の一部 である。プロジェクトの説明とバグ報告
       に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。