Skip to content
/linux-syscalls

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

ArchitectureNuméroABIPoint d'entrée
x86 (i386)54i386sys_ioctl
x64 (x86_64)1664sys_ioctl
ARM64 (aarch64)29——

Historique noyau

Introduit dans Linux 1.0.

  1. 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. 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é.

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

strace 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 ».

Syscalls liés