Skip to content
/linux-syscalls

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

ArchitectureNuméroABIPoint d'entrée
x86 (i386)6i386sys_close
x64 (x86_64)3commonsys_close
ARM64 (aarch64)57—sys_close

Historique noyau

Introduit dans Linux 1.0.

  1. 1.0

    close() est présent dans Linux depuis 1.0 avec la sémantique POSIX.1, à la règle Linux EINTR près.

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

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

Syscalls liés