Skip to content
/linux-syscalls

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

ArchitectureNuméroABIPoint d'entrée
x86 (i386)55i386sys_fcntl
x64 (x86_64)72commonsys_fcntl

Historique noyau

Introduit dans Linux 1.0.

  1. 1.0

    fcntl() est présent dans Linux depuis 1.0 avec la sémantique POSIX.

  2. 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. 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)         = 0

Les 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.

Syscalls liés