Fichiers & E/S · Section 2
close(2)
Libère un descripteur de fichier.
Signature
#include <unistd.h>
int close(int fd);- fd
- Descripteur à fermer. Après un retour réussi, fd est invalide dans ce processus ; ne plus l'utiliser.
Description
close() libère le descripteur fd, permettant sa réutilisation par le prochain open()/socket()/pipe()/etc. Si fd est la dernière référence à sa description d'ouverture sous-jacente, le noyau libère aussi le fichier — vidant les écritures en tampon, relâchant les verrous d'enregistrement détenus par ce processus, retirant les projections mmap sur le descripteur, et (pour les sockets) initiant la séquence d'arrêt TCP. close() retourne 0 en succès et -1 avec errno sinon. Le conseil traditionnel de réessayer close() sur EINTR est faux sous Linux : une fois close() retourné, le descripteur est libéré quelle que soit la valeur de retour. La valeur de retour signale une erreur asynchrone (typiquement un écho différé) mais ne donne pas une seconde chance de fermer.
Numéros par architecture
| Architecture | Numéro | ABI | Point d'entrée |
|---|---|---|---|
| x86 (i386) | 6 | i386 | sys_close |
| x64 (x86_64) | 3 | common | sys_close |
| ARM64 (aarch64) | 57 | — | sys_close |
Historique noyau
Introduit dans Linux 1.0.
1.0
close() est présent dans Linux depuis 1.0 avec la sémantique POSIX.1, à la règle Linux EINTR près.
5.9
close_range(first, last, flags) a été ajouté pour fermer une plage contiguë de descripteurs en un appel — utile dans le code enfant post-fork() qui veut tout fermer sauf une petite liste, remplaçant le motif lent de scan /proc/self/fd.
seccomp & conteneurs
Docker default profile
Autorisé
Podman default profile
Autorisé
close() est dans tous les profils par défaut et bloquer est inutile : tout programme ferme des descripteurs. Le filtrage intéressant porte sur close_range() et le drapeau CLOSE_RANGE_UNSHARE (Linux 5.11+), qui permet de fermer sélectivement des descripteurs après partage de la table — le restreindre complique certains motifs de bac à sable. Pour les charges normales, autoriser les deux.
libseccomp
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);Exemple strace
$ strace -e openat,close cat /etc/hostname > /dev/null
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
close(3) = 0
close(1) = 0La sortie close() est sur une ligne et peu informative seule ; l'associer à openat() dans le set -e pour voir le cycle complet ouvrir/fermer. Un processus qui fuit des fd apparaît comme de longues séquences openat() sans close() correspondant — facile à repérer en mode strace -c.
Sécurité & observabilité
close() en soi est rarement un événement de sécurité, mais son absence l'est : un processus qui ouvre des fichiers sensibles (/etc/shadow, /proc/<pid>/mem) sans jamais les fermer peut préparer un exploit. La comptabilité de fd via /proc/<pid>/fd est la surface d'audit la plus simple. Le vrai piège est le motif de retry sur EINTR — un code antérieur à 2008 qui boucle sur close() peut fermer un fd que le noyau a déjà réémis à un autre thread, fuitant des données sensibles au mauvais consommateur. Toujours traiter close() comme fire-and-forget sous Linux.
Erreurs
- EBADF
- fd n'est pas un descripteur ouvert valide.
- EINTR
- Sous Linux, EINTR après close() signifie que le descripteur a déjà été libéré — NE PAS réessayer le close avec le même fd. (D'autres Unix se comportent autrement ; la sémantique Linux est documentée dans close(2).)
- EIO
- Erreur d'E/S — typiquement un échec d'écriture différée révélé à la fermeture. La donnée est perdue ; le fd est néanmoins fermé.
- ENOSPC
- Sur NFS et quelques autres systèmes de fichiers, l'écho à la fermeture peut révéler ENOSPC alors que le write() initial avait réussi.