Fichiers & E/S · Section 2
ioctl(2)
Appel système de contrôle de périphérique fourre-tout : exécute une opération définie par le pilote sur un descripteur.
Signature
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ... argp);- fd
- Descripteur ouvert vers un périphérique, un fichier spécial ou un autre objet supportant ioctl.
- request
- Requête encodée : les macros _IO/_IOR/_IOW/_IOWR de sys/ioctl.h ou des en-têtes spécifiques (par ex. <linux/kvm.h>) la construisent.
- argp
- Variadique. Souvent un pointeur de structure ; parfois un entier passé par valeur ; parfois absent.
Description
ioctl() déclenche une opération propre au pilote sur l'objet référencé par fd. L'argument request est une constante magique encodant le sous-système cible, un numéro d'opération et la taille et la direction des données dans argp. Le troisième argument est variadique — absent, entier passé par valeur ou pointeur sur une structure lue, écrite, ou les deux par le noyau. Des centaines de sous-systèmes exposent une interface ioctl() : terminaux (TCGETS, TIOCGWINSZ), périphériques blocs (BLKGETSIZE, BLKDISCARD), interfaces réseau (SIOCGIFADDR), KVM (KVM_RUN, KVM_CREATE_VCPU), perf (PERF_EVENT_IOC_ENABLE), systèmes de fichiers (FS_IOC_GETFLAGS), tun/tap, USB, DRM/GPU… Chaque code de requête étant en pratique un mini-appel système, ioctl() représente l'une des plus grandes surfaces d'attaque du noyau Linux.
Numéros par architecture
| Architecture | Numéro | ABI | Point d'entrée |
|---|---|---|---|
| x86 (i386) | 54 | i386 | sys_ioctl |
| x64 (x86_64) | 16 | 64 | sys_ioctl |
| ARM64 (aarch64) | 29 | — | — |
Historique noyau
Introduit dans Linux 1.0.
1.0
ioctl() est présent dans Linux depuis 1.0 et remonte à V7 Unix. Son absence de structure en fait l'interface fourre-tout pour tout ce qui n'entre pas dans la sémantique POSIX read/write.
2.6.36
La méthode pilote .ioctl a été dépréciée au profit de .unlocked_ioctl, appelée sans le Big Kernel Lock — changement majeur de scalabilité.
4.6
Le chemin compat_ioctl a été réorganisé pour que les appelants 32-bit sur 64-bit passent par la même répartition que les appelants natifs, éliminant une longue liste de code de traduction dupliqué.
seccomp & conteneurs
Docker default profile
Autorisé
Podman default profile
Autorisé
ioctl() figure dans les profils par défaut Docker / Podman car terminaux, sockets et de nombreuses bibliothèques en dépendent. Le vrai levier de durcissement est le filtrage par valeur de request : la plupart des charges n'ont besoin que de TCGETS, TCSETS, TIOCGWINSZ, FIONBIO, FIONREAD — une vingtaine de codes sur des milliers. Avec le filtrage d'arguments on autorise ce sous-ensemble et on refuse le reste, ce qui retire l'essentiel de la surface historique des CVE noyau (KVM, perf, drm, usbdev, tun/tap ont tous eu des bugs partiellement accessibles à distance). À combiner avec une liste blanche /dev pour étanchéifier.
libseccomp
// Allow ioctl only for common terminal and FIONBIO/FIONREAD operations;
// block device-specific ioctls (KVM_*, TUN*, USBDEV*) by request value.
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl),
1, SCMP_A1(SCMP_CMP_EQ, TCGETS));
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl),
1, SCMP_A1(SCMP_CMP_EQ, FIONBIO));Exemple strace
$ strace -e ioctl tput cols
ioctl(0, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, …}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=24, ws_col=120, ws_xpixel=0, ws_ypixel=0}) = 0strace décode nombre de codes ioctl usuels (TCGETS, TIOCGWINSZ, BLKGETSIZE…) et déploie la structure argument ; les codes inconnus sont affichés en hex avec la taille du tampon. Utiliser -e trace=ioctl et -e ioctls=… pour filtrer par code.
Sécurité & observabilité
ioctl() est l'une des interfaces Linux les plus pourvoyeuses de CVE : des dizaines de sous-systèmes ont chacun leur propre jeu de codes, et un bug dans l'un est accessible depuis tout processus qui peut ouvrir le périphérique correspondant. Usages malveillants notables : ioctls TUN/TAP (TUNSETIFF) pour créer des interfaces réseau furtives ; perf_event_open + PERF_EVENT_IOC_* pour des primitives de traçage côté noyau ; FS_IOC_SETFLAGS pour positionner FS_IMMUTABLE_FL sur des fichiers déposés (rendant leur suppression difficile pour un répondant non privilégié). Le tracepoint eBPF sys_enter_ioctl capture fd et request ; corréler fd à /proc/<pid>/fd identifie la cible. Pour la réponse à incident, une valeur de request inhabituelle sur /dev/net/tun ou /dev/kvm depuis une charge non-virtualisation est un signal fort.
Erreurs
- EBADF
- fd n'est pas un descripteur valide.
- EFAULT
- argp pointe hors de l'espace d'adressage du processus.
- EINVAL
- request est reconnue mais l'argument est invalide.
- ENOTTY
- fd n'est pas associé à un périphérique caractère (errno classique), OU la requête ne s'applique pas à ce périphérique — souvent utilisé pour signifier « ce périphérique n'implémente pas cette ioctl ».