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/ に書かれている。