Provided by: manpages-ja-dev_0.5.0.0.20210215+dfsg-1_all bug

名前

       memfd_create - 無名ファイル (anonymous file) を作成する

書式

       #include <sys/memfd.h>

       int memfd_create(const char *name, unsigned int flags);

説明

       memfd_create()  は、 無名ファイル (anonymous file) を作成し、 そのファイルを参照するファイ
       ルディスクリプターを返す。  このファイルは通常のファイルと同様に振る舞い、  変更、切り詰め
       (truncate)、 メモリーマップなどを行うことができる。 しかし、 通常のファイルとは違い、 この
       ファイルは RAM 上に置かれ、 格納されるストレージは揮発性である。  このファイルへの参照がす
       べてなくなると、  ファイルは自動的に解放される。  このファイルが置かれるページには無名メモ
       リー (anonymous memory) が使用される。  したがって、  memfd_create()  で作成されたフィアル
       は、 他の無名メモリーの割り当て (MAP_ANONYMOUS フラグ付きの mmap(2) を使って割り当てられた
       無名メモリーなど) と同じ動作をする。

       ファイルの初期サイズは 0 に設定される。 呼び出しの後に、 ftruncate(2) を使ってファイルサイ
       ズを設定すべきである (代わりに、 write(2) や同様の関数を呼び出してファイルにデータを書き込
       むこともできる)。

       name に指定された名前はファイル名として使用され、 ディレクトリ /proc/self/fd/ で対応するシ
       ンボリックリンクのリンク先として表示される。 表示される名前の前には常に memfd: が付き、 こ
       の名前はデバッグ用途としてのみ機能する。    名前はファイルディスクリプターの動作には影響せ
       ず、 複数のファイルが同じ名前を持っても副作用はない。

       以下の値をビット論理和で flags に指定して、 memfd_create() の動作を変更できる。

       MFD_CLOEXEC
              新しいファイルディスクリプターに close-on-exec (FD_CLOEXEC) フラグをセットする。 こ
              れが有用な理由については open(2) の O_CLOEXEC フラグの説明を参照のこと。

       MFD_ALLOW_SEALING
              このファイルに対して  sealing   操作を許可する。   fcntl(2)   の   F_ADD_SEALSF_GET_SEALS  操作の議論を参照。 下記の「注意」も参照。 初期の seal 集合は空となる。
              このフラグを指定しなかった場合、 初期の seal 集合は F_SEAL_SEAL となり、 これはこの
              ファイルには他の seal をセットできないことということである。

       flags の未使用のビットは 0 でなければならない。

       返り値として  memfd_create()  は、  作成したファイルを参照するのに使用できる新しいファイル
       ディスクリプターを返す。 このファイルディスクリプターは読み書き両用 (O_RDWR)  でオープンさ
       れ、 O_LARGEFILE がこのファイルディスクリプターにセットされる。

       fork(2)  と execve(2) に関しては、 memfd_create() で作成したファイルディスクリプターについ
       ても通常の動作が適用される。 ファイルディスクリプターのコピーは fork(2) で生成される子プロ
       セスに継承され、  同じファイルを参照する。  close-on-exec フラグがセットされていない限り、
       execve(2) の前後でファイルディスクリプターは保持される。

返り値

       成功の場合、 memfd_create() は新しいファイルディスクリプターを返す。 エラーの場合、-1 を返
       し、 errno にエラーを示す値を設定する。

エラー

       EFAULT name のアドレスが無効なメモリーを指している。

       EINVAL サポートされていない値がいずれかの引き数で指定された。 flags に未知のビットが含まれ
              ていたか、 name が長過ぎた。

       EMFILE オープンされているファイルディスクリプターのプロセス単位の上限に達した。

       ENFILE システム全体でオープンされているファイルの総数が上限に達した。

       ENOMEM 新しい無名ファイルを作成するのに十分なメモリーがなかった。

バージョン

       memfd_create() システムコールは Linux 3.17 で初めて登場した。 GNU C ライブラリでのサポート
       は検討中である。

準拠

       memfd_create()  システムコールは Linux 固有である。

注意

       memfd_create() システムコールは、 手動で tmpfs ファイルシステムをマウントして、 そのファイ
       ルシステムにファイルをオープンするという操作の、            簡単な代替手段を提供している。
       memfd_create() の主な目的は、 fcntl(2) が提供する file-sealing API で使用できる、 ファイル
       とそれに関連付けられるファイルディスクリプターを作成することである。

       memfd_create()  システムコールは、   file   sealing   なしでも用途がある   (これが明示的に
       MFD_ALLOW_SEALING フラグが要求されない限り、 file-sealing が無効になる理由である)。 特に、
       ファイルシステムに実際にファイルを残す意図がない場合、 tmp にファイルを作成したり  open(2)
       O_TMPFILE を使ったりする際の代替手段として使用できる。

   file sealing
       file sealing がない場合、 共有メモリー経由で通信するプロセスは、 互いに信頼するか、 信頼し
       ていない相手が共有メモリー領域を問題がある方法で操作する可能性に対処するための対策を講じな
       ければならない。  例えば、 信頼していない相手は、 いつでも共有メモリーの内容を変更したり、
       共有メモリー領域を縮小したりする可能性がある。 前者の場合は、 ローカルプロセスでは、  デー
       タの確認時点と使用時点の競合条件の問題が起こり得る (通常はこの問題への対処は共有メモリー領
       域からデータをこぴーしてからデータを確認、使用することである)。 後者の場合は、  ローカルプ
       ロセスでは、      共有メモリー領域の存在しなくなった場所にアクセスしようとした際にシグナル
       SIGBUS が発生する可能性がある (この可能性に対処するにはシグナル SIGBUS  に対してハンドラー
       を使用する必要がある)。

       信頼していない相手への対処により、  共有メモリーを利用するコードに余計な複雑性が増すことに
       なる。 メモリー sealing により余計な複雑性をなくすことができる。  相手が望まない方法で共有
       メモリーを変更できないことを知っていることで、 プロセスは安全に動作できるようになる。

       sealing 機構の使い方の例は以下のとおりである。

       1. 最初のプロセスは memfd_create() を使って tmpfs ファイルを作成する。 memfd_create() はこ
          れ以降のステップで使用するファイルディスクリプターを返す。

       2. 最初のプロセスは  ftruncate(2)   を使って直前のステップで作成したファイルのサイズを変更
          し、  mmap(2)  を使ってそのファイルをマッピングし、  共有メモリーに所望のデータを配置す
          る。

       3. 最初のプロセスは、   このファイルに対する今後の変更を制限するために、    fcntl(2)    の
          F_ADD_SEALS  操作を使って、 そのファイルに seal をいくつか設定する。 (seal F_SEAL_WRITE
          を設定する場合、 直前のステップで作成した書き込み可能な共有マッピングをまずアンマップす
          る必要が出てくる。)

       4. 二つ目のプロセスは  tmpfs  ファイルのファイルディスクリプターを入手し、  そのファイルを
          マップする。 以下に示す方法を使用することができる。

          *  memfd_create() を呼び出したプロセスは、 得られたファイルディスクリプターを二つ目のプ
             ロセスに  UNIX  ドメインソケット経由で渡すことができる (unix(7) と cmsg(3) を参照)。
             それから、二つ目のプロセスは mmap(2) を使ってファイルをマップする。

          *  二つ目のプロセスを fork(2) を使って作成する。 そうすると、  自動的にファイルディスク
             リプターとマッピングが継承される。  (この方法と次の方法では、 二つのプロセス間で自然
             な信頼関係が存在することになる。 なぜなら、 二つのプロセスは同じユーザー ID。 の元で
             実行されているからである。 したがって、 file sealing は通常は不要であろう。)

          *  二つ目のプロセスは   /proc/<pd>/fd/<fd>   をオープンする。   <pid>  は最初のプロセス
             (memfd_create()  を呼び出したプロセス)  の  PID   で、   <fd>   は最初のプロセスでの
             memfd_create() の呼び出しで返されたファイルディスクリプター番号である。 それからこの
             ファイルを mmap(2) を使ってマッピングする。

       5. 二つ目のプロセスは fcntl(2) の F_GET_SEALS 操作を使って、  そのファイルに適用されている
          seal のビットマスクを取得する。 このビットマスクを調べて、 ファイルの変更に関してどのよ
          うな制限が適用されているかを知ることができる。 (F_SEAL_SEAL seal がそれまでに適用されて
          いない限りは) 必要であれば、 二つ目のプロセスはさらに seal を設定して追加の制限をかける
          ことができる。

       以下では memfd_create() と file sealing API の使用例を示すサンプルプログラムを 2  つとりあ
       げる。

       最初のプログラム t_memfd_create.c は、 memfd_create() を使って tmpfs ファイルを作成し、 そ
       のファイルのサイズを設定し、   メモリーにマッピングし、   要求された場合にはそのファイルに
       seal  を設定する。 このプログラムは最大で 3 つのコマンドライン引き数を取り、 最初の 2 つは
       必須である。 最初の引き数はファイルに関連付けられる名前で、 2 番目の引き数はファイルに設定
       されるサイズである。  省略可能な 3 番目の引き数は、 このファイルに設定する seal を指定する
       文字列である。

       2 つめのプログラム t_get_seals.c を使うと、 memfd_create()  を使って作成された既存のファイ
       ルをオープンし、 そのファイルに適用されている seal の集合を調査できる。

       以下のシェルのセッションはこれらのプログラムの使用例を示したものである。 まず tmpfs ファイ
       ルを作成し、そのファイルに seal をいくつか設定している。

           $ ./t_memfd_create my_memfd_file 4096 sw &
           [1] 11775
           PID: 11775; fd: 3; /proc/11775/fd/3

       この時点では、 t_memfd_create プログラムはバックグラウンドで動作し続ける。  もう一つのプロ
       グラムから、 memfd_create() がオープンしたディスクリプターに対応する /proc/PID/fd ファイル
       をオープンすることで、 memfd_create() で作成されたファイルのファイルディスクリプターを取得
       できる。  そのパス名を使って、 /proc/PID/fd シンボリックリンクの内容を調査し、 t_get_seals
       プログラムを使ってそのファイルに設定されている seal を見ることができる。

           $ readlink /proc/11775/fd/3
           /memfd:my_memfd_file (deleted)
           $ ./t_get_seals /proc/11775/fd/3
           Existing seals: WRITE SHRINK

   プログラムのソース: t_memfd_create.c

       #include <sys/memfd.h>
       #include <fcntl.h>
       #include <stdlib.h>
       #include <unistd.h>
       #include <string.h>
       #include <stdio.h>

       #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                               } while (0)

       int
       main(int argc, char *argv[])
       {
           int fd;
           unsigned int seals;
           char *addr;
           char *name, *seals_arg;
           ssize_t len;

           if (argc < 3) {
               fprintf(stderr, "%s name size [seals]\n", argv[0]);
               fprintf(stderr, "\t'seals' can contain any of the "
                       "following characters:\n");
               fprintf(stderr, "\t\tg - F_SEAL_GROW\n");
               fprintf(stderr, "\t\ts - F_SEAL_SHRINK\n");
               fprintf(stderr, "\t\tw - F_SEAL_WRITE\n");
               fprintf(stderr, "\t\tS - F_SEAL_SEAL\n");
               exit(EXIT_FAILURE);
           }

           name = argv[1];
           len = atoi(argv[2]);
           seals_arg = argv[3];

           /* Create an anonymous file in tmpfs; allow seals to be
              placed on the file */

           fd = memfd_create(name, MFD_ALLOW_SEALING);
           if (fd == -1)
               errExit("memfd_create");

           /* Size the file as specified on the command line */

           if (ftruncate(fd, len) == -1)
               errExit("truncate");

           printf("PID: %ld; fd: %d; /proc/%ld/fd/%d\n",
                   (long) getpid(), fd, (long) getpid(), fd);

           /* Code to map the file and populate the mapping with data
              omitted */

           /* If a 'seals' command-line argument was supplied, set some
              seals on the file */

           if (seals_arg != NULL) {
               seals = 0;

               if (strchr(seals_arg, 'g') != NULL)
                   seals |= F_SEAL_GROW;
               if (strchr(seals_arg, 's') != NULL)
                   seals |= F_SEAL_SHRINK;
               if (strchr(seals_arg, 'w') != NULL)
                   seals |= F_SEAL_WRITE;
               if (strchr(seals_arg, 'S') != NULL)
                   seals |= F_SEAL_SEAL;

               if (fcntl(fd, F_ADD_SEALS, seals) == -1)
                   errExit("fcntl");
           }

           /* Keep running, so that the file created by memfd_create()
              continues to exist */

           pause();

           exit(EXIT_SUCCESS);
       }

   プログラムのソース: t_get_seals.c

       #include <sys/memfd.h>
       #include <fcntl.h>
       #include <unistd.h>
       #include <stdlib.h>
       #include <string.h>
       #include <stdio.h>

       #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                               } while (0)

       int
       main(int argc, char *argv[])
       {
           int fd;
           unsigned int seals;

           if (argc != 2) {
               fprintf(stderr, "%s /proc/PID/fd/FD\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           fd = open(argv[1], O_RDWR);
           if (fd == -1)
               errExit("open");

           seals = fcntl(fd, F_GET_SEALS);
           if (seals == -1)
               errExit("fcntl");

           printf("Existing seals:");
           if (seals & F_SEAL_SEAL)
               printf(" SEAL");
           if (seals & F_SEAL_GROW)
               printf(" GROW");
           if (seals & F_SEAL_WRITE)
               printf(" WRITE");
           if (seals & F_SEAL_SHRINK)
               printf(" SHRINK");
           printf("\n");

           /* Code to map the file and access the contents of the
              resulting mapping omitted */

           exit(EXIT_SUCCESS);
       }

関連項目

       fcntl(2), ftruncate(2), mmap(2), shmget(2), shm_open(3)

この文書について

       この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部  である。プロジェクト
       の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。