Fichiers & E/S · Section 2
fcntl(2)
Multiplexeur de contrôle de descripteur — drapeaux, verrous, baux, tailles de tube et duplication.
Signature
#include <fcntl.h>
#include <unistd.h>
int fcntl(int fd, int cmd, ... arg);- fd
- Descripteur cible.
- cmd
- Code d'opération (voir le tableau).
- arg
- Propre à l'opération. Peut être un int (drapeaux F_SETFL, min-fd F_DUPFD), un pointeur sur struct flock (commandes F_*LK), ou absent (F_GETFL).
Description
fcntl() est un multiplexeur d'opérations par descripteur. L'argument cmd choisit l'opération ; le troisième argument est variadique et propre à l'opération. Commandes importantes : F_GETFL / F_SETFL lisent et modifient les drapeaux d'état d'ouverture (O_NONBLOCK, O_APPEND, O_ASYNC) — à noter que O_RDONLY/O_WRONLY/O_RDWR ne sont PAS modifiables via F_SETFL. F_GETFD / F_SETFD gèrent les drapeaux de descripteur (seul FD_CLOEXEC est défini). F_DUPFD duplique fd vers le plus petit numéro disponible ≥ arg ; F_DUPFD_CLOEXEC fait de même atomiquement avec close-on-exec. F_SETLK / F_SETLKW / F_GETLK implémentent les verrous d'enregistrement POSIX (par processus — fondamentalement cassés en multithread, raison de l'ajout de F_OFD_*). F_SETPIPE_SZ redimensionne le tampon noyau d'un tube. Le code moderne préfère de plus en plus des syscalls dédiés (dup3, pipe2) à fcntl() pour les mêmes opérations.
Numéros par architecture
| Architecture | Numéro | ABI | Point d'entrée |
|---|---|---|---|
| x86 (i386) | 55 | i386 | sys_fcntl |
| x64 (x86_64) | 72 | common | sys_fcntl |
Historique noyau
Introduit dans Linux 1.0.
1.0
fcntl() est présent dans Linux depuis 1.0 avec la sémantique POSIX.
2.6.0
Les baux de fichier (F_SETLEASE) et le contrôle de taille de tube (F_SETPIPE_SZ) ont été ajoutés — les baux permettent à l'espace utilisateur de coopérer avec le noyau sur la rupture de bail pour la cohérence de cache ; le contrôle de taille de tube donne du tampon supplémentaire aux producteurs/consommateurs à fort débit.
3.15
Les verrous OFD (F_OFD_SETLK, F_OFD_SETLKW, F_OFD_GETLK) ont été ajoutés pour corriger un défaut séculaire des verrous d'enregistrement POSIX — liés au PID, libérés silencieusement à la fermeture de *n'importe quel* descripteur sur le fichier, donc inutilisables en multithread. Les verrous OFD sont liés à la description d'ouverture et se comportent sainement.
seccomp & conteneurs
Docker default profile
Autorisé
Podman default profile
Autorisé
fcntl() est dans tout profil par défaut et en pratique impossible à bloquer : tout chargeur dynamique utilise F_GETFD/F_SETFD sur les fd hérités. Le filtrage d'arguments sur cmd est théoriquement possible (autoriser F_GETFL, F_SETFL, F_GETFD, F_SETFD, F_DUPFD, F_DUPFD_CLOEXEC ; refuser F_SETOWN, F_SETLEASE, F_NOTIFY) mais les gains sont minces sans modèle de menace spécifique.
libseccomp
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 0);Exemple strace
$ strace -e fcntl bash -c 'true'
fcntl(0, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
fcntl(0, F_DUPFD, 10) = 10
fcntl(255, F_SETFD, FD_CLOEXEC) = 0Les lignes fcntl() décodent cmd symboliquement et les drapeaux pour F_GETFL/F_SETFL. La séquence de démarrage de tout binaire non trivial contient 5-20 appels fcntl() de la glibc configurant le buffering stdio, le CLOEXEC sur les fd runtime, et l'E/S signal-driven pour le GC de certains runtimes.
Sécurité & observabilité
fcntl() avec F_SETOWN peut délivrer SIGIO à un PID cible — historiquement un moyen d'envoyer des signaux à des processus non possédés, en grande partie fermé depuis le durcissement 2.6. F_NOTIFY (déprécié) exposait jadis des fuites d'information. F_SETLEASE laisse l'espace utilisateur participer à l'invalidation du cache noyau ; un mauvais usage peut interbloquer le système de fichiers. Pour le durcissement conteneur, l'hygiène la plus actionnable est fcntl(F_SETFD, FD_CLOEXEC) sur tout fd à longue vie ; les outils checkpoint/restore (CRIU) s'y appuient.
Erreurs
- EACCES
- F_SETLK / F_SETLKW sur fd en conflit (sémantique de verrou par mode).
- EAGAIN
- F_SETLK : un autre processus détient un verrou en conflit et on n'a pas demandé d'attendre.
- EBADF
- fd n'est pas un descripteur ouvert (ou, pour F_DUPFD, arg hors plage).
- EDEADLK
- F_SETLKW provoquerait un interblocage avec un autre détenteur.
- EFAULT
- —
- EINTR
- —
- EINVAL
- cmd non reconnue, ou arg invalide pour cmd.
- EMFILE
- —
- ENOLCK
- Noyau à court de ressources pour la table de verrous.
- EPERM
- F_SETLEASE / F_SETOWN : appelant sans le privilège/capacité requis.
Drapeaux
- F_DUPFD
- 0
- —
- F_GETFD
- 1
- —
- F_SETFD
- 2
- —
- F_GETFL
- 3
- Retourne les drapeaux d'état d'ouverture (O_ACCMODE | autres). Utilisé pour passer un fd bloquant en non bloquant via 'flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | O_NONBLOCK)'.
- F_SETFL
- 4
- Positionne les drapeaux d'état. Ne peut changer O_RDONLY/O_WRONLY/O_RDWR ni O_CREAT/O_EXCL/O_TRUNC — fixés à l'ouverture.
- F_GETLK
- 5
- —
- F_SETLK
- 6
- —
- F_SETLKW
- 7
- —
- F_DUPFD_CLOEXEC
- 1030
- Comme F_DUPFD mais positionne atomiquement FD_CLOEXEC sur le nouveau descripteur. À utiliser dans tout programme qui fork.
- F_SETPIPE_SZ
- 1031
- Définit la taille du tampon noyau d'un tube. Plafonné à /proc/sys/fs/pipe-max-size (défaut 1 MiB).
- F_GETPIPE_SZ
- 1032
- —
- F_OFD_GETLK
- 36
- —
- F_OFD_SETLK
- 37
- Verrou d'enregistrement sur description d'ouverture. Contrairement à F_SETLK, le verrou est lié à la description (pas au PID), donc les programmes multithreads partageant le même fd voient une sémantique cohérente. Le correctif 2014 d'un des plus vieux pièges POSIX.
- F_OFD_SETLKW
- 38
- —
- FD_CLOEXEC
- 1
- Drapeau de descripteur : fermer à execve. Le drapeau le plus important pour tout fd qui ne doit pas fuir vers les enfants.