Fichiers & E/S · Section 2
read(2)
Lit jusqu'à count octets depuis un descripteur dans un tampon.
Signature
#include <unistd.h>
ssize_t read(int fd, void * buf, size_t count);- fd
- Descripteur ouvert en O_RDONLY ou O_RDWR (ou tout type de descripteur supportant la lecture, par ex. socket ou tube).
- buf
- Tampon utilisateur d'au moins count octets. Le noyau y écrit.
- count
- Nombre maximum d'octets à lire. Le noyau plafonne à 0x7ffff000 par appel ; les lectures partielles sont explicitement autorisées.
Description
read() tente de lire jusqu'à count octets depuis le fichier référencé par fd dans le tampon débutant à buf. Le nombre d'octets effectivement lus est renvoyé ; il peut être inférieur à count pour de nombreuses raisons — le fichier est plus court que la demande, le support est lent, un signal interrompt l'appel, le fichier est un tube dont le producteur n'a pas encore fourni plus de données, ou le descripteur est en O_NONBLOCK. Un retour de 0 signifie fin de fichier. -1 avec errno indique un échec. read() est l'appel système le plus fréquent sur la plupart des systèmes Linux et la base canonique de tout chemin d'entrée : fichiers, sockets, tubes, terminaux, périphériques caractères.
Numéros par architecture
| Architecture | Numéro | ABI | Point d'entrée |
|---|---|---|---|
| x86 (i386) | 3 | i386 | sys_read |
| x64 (x86_64) | 0 | common | sys_read |
| ARM64 (aarch64) | 63 | — | sys_read |
Historique noyau
Introduit dans Linux 1.0.
1.0
read() est présent dans Linux depuis 1.0 et suit POSIX.1, avec de petites extensions spécifiques Linux autour du plafond de 0x7ffff000 et du comportement des fichiers /proc (qui peuvent retourner -1/EAGAIN ou des lectures partielles de façon surprenante).
seccomp & conteneurs
Docker default profile
Autorisé
Podman default profile
Autorisé
read() est dans tous les profils par défaut et en pratique impossible à bloquer : tout chemin d'entrée sous Linux y passe. Le levier seccomp pour les E/S n'est pas read() lui-même — c'est restreindre *quels fd peuvent être ouverts* (via filtrage de openat(), Landlock, ou un bac à sable chroot/bind-mount). Pour filtrer au niveau read, faire ça côté espace utilisateur avec un wrapper qui audite l'identité du fd.
libseccomp
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);Exemple strace
$ strace -e read head -c 16 /etc/hostname
read(3, "linux-syscalls\n", 4096) = 15
read(3, "", 4081) = 0strace tronque le contenu du tampon à 32 octets par défaut — utiliser -s 4096 (ou plus) pour voir les lectures complètes. -e read=<set_fd> affiche le contenu des lectures sur des fd spécifiques. Pour savoir pourquoi un programme bloque, s'attacher avec -p <pid> et chercher un read(N, ...) inachevé — c'est l'appel qui tient tout.
Sécurité & observabilité
read() apparaît dans trois contextes de sécurité. (1) Divulgation : l'exfiltration de données passe forcément par un read() avant le write() ailleurs — mais les deux étant universels, le monitoring à ce niveau est bruyant. (2) Les exploits par canal auxiliaire impliquent souvent un read() de /proc/self/maps, /proc/self/mem ou /proc/<pid>/auxv pour apprendre les offsets ASLR — alerter sur les lectures /proc depuis des contextes inhabituels est à fort signal. (3) Les rootkits qui hookent read() peuvent filtrer le contenu en vol (par ex. retirer leurs entrées de /proc/net/tcp). Le tracepoint eBPF sys_enter_read se déclenche à chaque appel ; pour la supervision, échantillonner ou filtrer par catégorie de fd (corréler fd à /proc/<pid>/fd) pour éviter la saturation. lsm/file_read est un point d'observation plus ciblé.
Erreurs
- EAGAIN
- fd ouvert avec O_NONBLOCK et aucune donnée immédiatement disponible. L'appelant doit poller, epoll_wait ou io_uring pour la disponibilité.
- EBADF
- fd n'est pas un descripteur valide ou n'est pas ouvert en lecture.
- EFAULT
- buf pointe hors de l'espace d'adressage du processus.
- EINTR
- L'appel a été interrompu par un signal avant qu'aucune donnée ne soit lue.
- EINVAL
- —
- EIO
- Erreur d'E/S — bloc défectueux sur disque, serveur NFS planté, etc.
- EISDIR
- fd désigne un répertoire. Utiliser getdents()/getdents64() pour lire les entrées de répertoire.