guest@6admin.io:~$

Les syscalls de Linux

Un programme en espace utilisateur ne fait rien directement: quand il lit un fichier, alloue de la mémoire ou envoie un paquet réseau, il demande au kernel de le faire. Cette demande est un syscall (system call): le programme exécute une instruction spéciale (int 0x80 ou sysenter sur x86), le kernel prend la main, exécute la demande et rend le contrôle au programme. C’est la frontière entre l’espace utilisateur (ring 3) et l’espace kernel (ring 0).

Les syscalls de base

Linux expose environ 300 syscalls. Les plus fréquents:

syscallce qu’il fait
readlire depuis un fd
writeécrire dans un fd
openouvrir un fichier
closefermer un fd
statles métadonnées d’un fichier
mmapmapper de la mémoire
fork/clonecréer un process
execvecharger un binaire
socketcréer un socket
connectse connecter à un socket distant
bindattacher un socket à un port
listenécouter sur un socket
acceptaccepter une connexion

Chaque syscall a un numéro (l’offset dans la sys_call_table) et des arguments passés dans les registres (eax = numéro, ebx/ecx/edx/esi/edi = arguments sur x86 32 bits).

strace: observer les syscalls

strace intercepte les syscalls d’un process (via ptrace) et les affiche:

strace ls
execve("/bin/ls", ["ls"], [/* 24 vars */]) = 0
brk(0)                                  = 0x805c000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f7a000
open("/etc/ld.so.preload", O_RDONLY)    = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=62350, ...}) = 0
mmap2(NULL, 62350, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f6b000
close(3)                                = 0
...

Chaque ligne est un syscall: le nom, les arguments et la valeur de retour (= 0 signifie succès, -1 signifie erreur avec errno). Le ENOENT après open("/etc/ld.so.preload") signifie que le fichier n’existe pas, ce qui est normal (ld.so.preload est optionnel).

strace sur un process existant

strace -p 12345

Attache strace à un process en cours (via ptrace, donc nécessite root ou être le propriétaire).

Les options qui changent tout

strace -f ls              # suivre aussi les processus enfants
strace -e trace=open,read ls  # seulement open et read
strace -e trace=network wget example.com  # seulement les syscalls réseau
strace -c ls              # compter les syscalls au lieu de les afficher
strace -t ls              # afficher les timestamps

strace -c est le plus instructif:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 39.87    0.000257         257         1           execve
 28.87    0.000186           3        62        13 open
 15.78    0.000102           2        55         2 read
 ...

62 appels à open pour lister un directory: c’est le chargement des librairies partagées (chaque librairie est cherchée dans chaque directory du LD_LIBRARY_PATH). Le errors montre 13 opens qui ont échoué: les directories où le fichier n’existe pas. C’est le mécanisme de recherche de ld.so.

Ce que strace révèle

strace révèle ce que le programme fait réellement, pas ce qu’il prétend faire. Un programme qui prétend lire un fichier de config révèle les directories où il cherche, l’ordre de recherche et les erreurs errno à chaque tentative. Un programme qui “ne fonctionne pas” révèle souvent un open sur un fichier qui n’existe pas avec un ENOENT. C’est l’outil de debug le plus under-rated de Linux.

[edit: 2026] strace n’a pas changé. Les syscalls ont augmenté (environ 450 en 2026, contre 300 en 2008, avec io_uring, bpf, clone3, openat2). ltrace (tracing des appels de librairie) complète strace (tracing des syscalls). strace -c reste l’outil de premier diagnostic et strace -f reste le seul moyen de savoir ce qu’un programme fait vraiment sans lire son code source. Le ptrace est toujours le mécanisme et ptrace est toujours la cible des durcissements de sécurité (Yama LSM).