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

名前

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

書式

       #define _GNU_SOURCE         /* feature_test_macros(7) 参照 */
       #include <sys/mman.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  をセットできないことということで
              ある。

       MFD_HUGETLB (Linux 4.14 以降)
              The  anonymous  file  will be created in the hugetlbfs filesystem using huge pages.  See the Linux
              kernel  source  file  Documentation/admin-guide/mm/hugetlbpage.rst  for  more  information   about
              hugetlbfs.   Specifying  both  MFD_HUGETLB and MFD_ALLOW_SEALING in flags is supported since Linux
              4.16.

       MFD_HUGE_2MB, MFD_HUGE_1GB, ...
              Used in conjunction with MFD_HUGETLB to select alternative hugetlb page sizes (respectively, 2 MB,
              1 GB,  ...)  on systems that support multiple hugetlb page sizes.  Definitions for known huge page
              sizes are included in the header file <linux/memfd.h>.

              For details on encoding huge page sizes not included in the header file, see the discussion of the
              similarly named constants in mmap(2).

       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 included unknown bits.

       EINVAL name was too long.  (The limit is 249 bytes, excluding the terminating null byte.)

       EINVAL Both MFD_HUGETLB and MFD_ALLOW_SEALING were specified in flags.

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

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

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

バージョン

       memfd_create() システムコールは Linux 3.17 で登場した。 glibc でのサポートは glibc バージョン 2.27 で追加
       された。

準拠

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

注意

       memfd_create() システムコールは、 手動で tmpfs(5) ファイルシステムをマウントして、 そのファイルシステムに
       ファイルをオープンするという操作の、    簡単な代替手段を提供している。    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(5) ファイルを作成する。 memfd_create() はこれ以降のス
          テップで使用するファイルディスクリプターを返す。

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

       3. The  first process uses the fcntl(2)  F_ADD_SEALS operation to place one or more seals on the file, in
          order to restrict further modifications on the file.  (If placing the seal F_SEAL_WRITE, then it  will
          be  necessary  to  first  unmap  the shared writable mapping created in the previous step.  Otherwise,
          behavior similar to F_SEAL_WRITE can be achieved by  using  F_SEAL_FUTURE_WRITE,  which  will  prevent
          future  writes  via  mmap(2)   and  write(2)   from  succeeding while keeping existing shared writable
          mappings).

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

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

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

          *  二つ目のプロセスは /proc/<pid>/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(5) ファイルを作成し、 そのファイルの
       サイズを設定し、 メモリーにマッピングし、 要求された場合にはそのファイルに seal を設定する。 このプログラ
       ムは最大で  3 つのコマンドライン引数を取り、 最初の 2 つは必須である。 最初の引数はファイルに関連付けられ
       る名前で、 2 番目の引数はファイルに設定されるサイズである。 省略可能な 3 番目の引数は、  このファイルに設
       定する seal を指定する文字列である。

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

       以下のシェルのセッションはこれらのプログラムの使用例を示したものである。  まず  tmpfs(5)   ファイルを作成
       し、そのファイルに 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

       #define _GNU_SOURCE
       #include <stdint.h>
       #include <sys/mman.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\tW - F_SEAL_FUTURE_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: %jd; fd: %d; /proc/%jd/fd/%d\n",
                   (intmax_t) getpid(), fd, (intmax_t) 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, 'W') != NULL)
                   seals |= F_SEAL_FUTURE_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

       #define _GNU_SOURCE
       #include <sys/mman.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_FUTURE_WRITE)
               printf(" FUTURE_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 プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告
       に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。