bionic (2) mprotect.2.gz

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