memfd_create(2) | System Calls Manual | memfd_create(2) |
memfd_create - Créer un fichier anonyme
Bibliothèque C standard (libc, -lc)
#define _GNU_SOURCE /* Consultez feature_test_macros(7) */ #include <sys/mman.h>
int memfd_create(const char *name, unsigned int flags);
memfd_create() crée un fichier anonyme et renvoie un descripteur de fichier qui s'y rapporte. Le fichier se comporte comme un fichier normal, il peut donc être modifié, tronqué, projeté en mémoire, et ainsi de suite. Mais contrairement à un fichier normal, il réside dans la RAM et son stockage est volatile. Une fois que toutes les références au fichier ont disparu, il est automatiquement libéré. La mémoire anonyme est utilisée pour toutes les pages de sauvegarde du fichier. Les fichiers créés par memfd_create() ont donc la même sémantique que les autres allocations de mémoire anonyme telles que celles qui utilisent mmap(2) avec l'attribut MAP_ANONYMOUS.
La taille initiale du fichier est positionnée à 0. Après l'appel, elle devrait être définie en utilisant ftruncate(2) (ou le fichier peut être rempli par des appels à write(2) ou équivalent).
Le nom fourni dans name est utilisé comme nom de fichier et sera affiché en tant que cible du lien symbolique correspondant dans le répertoire /proc/self/fd/. Le nom affiché a toujours un préfixe memfd: et il ne sert que pour le débogage. Les noms ne changent pas le comportement du descripteur de fichier et en tant que tels plusieurs fichiers peuvent avoir le même nom sans effets de bord.
Les valeurs suivantes peuvent subir une opération OU logique bit à bit dans flags pour modifier le comportement de memfd_create() :
Les bits inusitées dans flags doivent valoir 0.
En code de retour, memfd_create() renvoie un nouveau descripteur de fichier qui peut être utilisé pour se référer au fichier. Ce descripteur de fichier est ouvert en lecture et en écriture (O_RDWR) et O_LARGEFILE est positionné pour le descripteur de fichier.
Par rapport à fork(2) et execve(2), la sémantique habituelle s'applique au descripteur de fichier créé par memfd_create(). Une copie du descripteur de fichier est récupérée par l'enfant produit par fork(2) et elle se rapporte au même fichier. Le descripteur de fichier est préservé pendant un execve(2), sauf si l'attribut close-on-exec a été positionné.
En cas de succès, memfd_create() renvoie un nouveau descripteur de fichier. En cas d'erreur, -1 est renvoyé et errno est positionné pour indiquer l'erreur.
L'appel système memfd_create() est apparu dans Linux 3.17 ; la prise en charge de la glibc a été ajouté dans la glibc 2.27.
L'appel système memfd_create() est spécifique à Linux.
L'appel système memfd_create() offre une alternative simple au montage manuel d'un système de fichiers tmpfs(5) et à la création et l'ouverture d'un fichier dans ce système de fichiers. Le premier objectif de memfd_create() est de créer des fichiers et leur descripteur associé, utilisés avec les API de verrou de fichiers fournis par fcntl(2).
L'appel système memfd_create() s'utilise également sans verrou de fichier (c'est pourquoi le verrouillage de fichier a été désactivé sauf demande explicite avec l'attribut MFD_ALLOW_SEALING). En particulier, il peut être utilisé comme alternative pour créer des fichiers dans tmp ou pour utiliser O_TMPFILE de open(2), si vous ne voulez pas rattacher le fichier résultant au système de fichiers.
En l'absence de verrou de fichier, les processus qui communiquent à travers la mémoire partagée doivent soit se faire confiance entre eux, soit prendre des mesures pour gérer la possibilité qu'un pair non fiable manipule la région de mémoire partagée de manière problématique. Par exemple, un pair non fiable pourrait modifier le contenu de la mémoire partagée n'importe quand ou rétrécir la zone de mémoire partagée. La première éventualité rend le processus local vulnérable aux conflits (race conditions) time-of-check-to-time-of-use (généralement gérés en copiant les données de la zone de mémoire partagée avant de les vérifier et de les utiliser). La deuxième éventualité rend le processus local vulnérable aux signaux SIGBUS quand on essaie d'accéder à un emplacement inexistant dans la zone de mémoire partagée (gérer cette éventualité implique d'utiliser un gestionnaire pour le signal SIGBUS).
La gestion de pairs non fiables impose une plus grande complexité du code qui utilise la mémoire partagée. Les verrous mémoire éliminent cette complexité, en permettant à un processus d'agir en toute sécurité en sachant que son pair ne peut pas modifier la mémoire partagée de manière non souhaitée.
Voici un exemple d'utilisation du mécanisme de verrouillage :
Voici deux exemples de programme montrant l'utilisation de memfd_create() et de l'API de verrou de fichier.
Le premier programme, t_memfd_create.c, crée un fichier tmpfs(5) en utilisant memfd_create(), donne une taille au fichier, le projette en mémoire et, en option, pose des verrous sur le fichier. Le programme accepte jusqu'à trois paramètres en ligne de commande, dont les deux premiers sont requis. Le premier paramètre est le nom à donner au fichier, le deuxième est la taille à lui donner, le troisième, optionnel, est une chaîne de caractères qui indique les verrous à poser sur le fichier.
Le deuxième programme, t_get_seals.c, peut être utilisé pour ouvrir un fichier existant créé à l'aide de memfd_create() et examiner les verrous qui y sont posés.
La session d'interpréteur suivant montre l'utilisation de ces programmes. Nous créons d'abord un fichier tmpfs(5) et nous posons des verrous dessus :
$ ./t_memfd_create my_memfd_file 4096 sw & [1] 11775 PID: 11775; fd: 3; /proc/11775/fd/3
À ce moment, le programme t_memfd_create continue à s'exécuter en tâche de fond. À partir d'un autre programme, nous pouvons obtenir un descripteur de fichier pour le fichier créé par memfd_create() en ouvrant /proc/pid/fd qui correspond au descripteur de fichier ouvert par memfd_create(). En utilisant ce chemin, nous examinons le contenu du lien symbolique /proc/pid/fd et nous utilisons notre programme t_get_seals pour voir les verrous posés sur le fichier :
$ readlink /proc/11775/fd/3 /memfd:my_memfd_file (deleted) $ ./t_get_seals /proc/11775/fd/3 Verrous existants : WRITE SHRINK
#define _GNU_SOURCE #include <err.h> #include <fcntl.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <unistd.h> int main(int argc, char *argv[]) { int fd; char *name, *seals_arg; ssize_t len; unsigned int seals; 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]; /* Créer un fichier anonyme dans tmpfs ; permet de poser des verrous sur le fichier. */ fd = memfd_create(name, MFD_ALLOW_SEALING); if (fd == -1) err(EXIT_FAILURE, "memfd_create"); /* Taille du fichier indiquée sur la ligne de commande. */ if (ftruncate(fd, len) == -1) err(EXIT_FAILURE, "truncate"); printf("PID: %jd; fd: %d; /proc/%jd/fd/%d\n", (intmax_t) getpid(), fd, (intmax_t) getpid(), fd); /* Code pour projeter le fichier et remplir la projection avec des données omises. */ /* Si un paramètre 'seals' de la ligne de commande est fourni, poser des verrous sur le fichier. */ 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) err(EXIT_FAILURE, "fcntl"); } /* Continuer l’exécution pour que le fichier créé par memfd_create() continue à exister. */ pause(); exit(EXIT_SUCCESS); }
#define _GNU_SOURCE #include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> 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) err(EXIT_FAILURE, "open"); seals = fcntl(fd, F_GET_SEALS); if (seals == -1) err(EXIT_FAILURE, "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 pour associer le fichier et l'accès au contenu de la projection résultante omise. */ exit(EXIT_SUCCESS); }
fcntl(2), ftruncate(2), memfd_secret(2), mmap(2), shmget(2), shm_open(3)
La traduction française de cette page de manuel a été créée par Christophe Blaess <https://www.blaess.fr/christophe/>, Stéphan Rafin <stephan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org>, David Prévot <david@tilapin.org> et Jean-Philippe MENGUAL <jpmengual@debian.org>
Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à debian-l10n-french@lists.debian.org.
5 février 2023 | Pages du manuel de Linux 6.03 |