Connexion Premium

Dans le noyau Linux 7.2, la suppression du vieux strncpy a réclamé un audit gigantesque

Depuis des décennies, les développeurs Linux utilisent une fonction nommée strncpy pour copier du texte. Développée en C, elle est étiquetée comme dangereuse par la propre documentation du noyau. Problème, elle est omniprésente.

Pour comprendre le problème, on peut utiliser une analogie. Supposons que la mémoire de l’ordinateur est comme une série de casiers. Quand un programme veut enregistrer un texte, il réserve une boite d’une certaine taille et y écrit le texte. En langage C, l’ordinateur n’a pas de moyen « naturel » pour savoir quand le mot s’arrête. Il y a donc une règle simple : quand le programme écrit un texte, il faut qu’un point rouge (caractère de fin de chaîne \0) en signale la fin.

Photographie retouchée de Long Ma pour Unsplash
Long Ma pour Unsplash

Et c’est là que les ennuis commencent. La fonction strncpy() est responsable de la copie des textes, mais elle a un gros défaut : quand le texte est trop long, elle coupe la séquence de caractères, mais oublie d’ajouter un point. Et quand le texte est trop court ? Elle ajoute autant de points rouges que nécessaire pour remplir le champ réservé. Les conséquences vont du gaspillage d’énergie à la fuite de secrets, car l’absence de point rouge entraine l’application ou le service à lire ce qui se trouve au-delà, donc des informations présentes dans d’autres « casiers ».

Ces problèmes sont connus depuis longtemps, mais leur résolution a demandé un vaste effort d’ingénierie. Des développeurs ont ainsi passé les six dernières années à référencer toutes les occurrences de la fonction strncpy dans l’intégralité du code du noyau, totalisant 362 commits (des participations, en quelque sorte), rapporte Phoronix. La version 7.2 à venir sera donc la première à ne plus posséder strncpy, remplacé par des variantes modernes et beaucoup plus sécurisées.

Dans la plupart des cas, il s’agira de strscpy, qui possède le comportement adapté : l’outil copie du texte, mais si la séquence est trop longue, il la tronçonne en ajoutant systématiquement un point rouge à la fin de chaque morceau. Strncpy est donc supprimé définitivement à partir du prochain noyau, avec impossibilité d’y faire appel.

Commentaires (13)

votre avatar
Dans quels cas a-t-on besoin de strncopy dans un noyau ? Normalement, on ne manipule pas de chaînes de caractères ans un noyau.

Dans le commit en lien (qui est le dernier de ce chantier), il y a la fonction en assembleur pour plusieurs architectures et en C plus un programme de test (qui teste la fonction il me semble).
votre avatar
Note : je ne suis pas allé regarder donc à prendre avec des pincettes.

A priori, je dirais déjà dans tout ce qui a trait aux système de fichiers et en particulier les virtuels (comme /proc et /sys), un certain nombre de pilotes doit aussi y faire appel (je pense aux descripteurs USB mais il y a sans doute d’autres cas d’usage).

La curiosité l’a emporté donc après clone du dépôt (3.21 Gio téléchargés quand même) et recherche rapide, je trouve grossièrement les zones suivantes :

  • Effectivement plein de trucs dans drivers/ (video, crypto, nfc, net pour les derniers traités).

  • À vue de nez pas mal de trucs pour tout ce qui est traces (pour dmesg et compagnie).

  • Les système de fichiers dans fs/.

  • La gestion du son dans sound/.



J’ai arrêté de remonter l’historique vers début juillet 2025 et je n’ai pas regardé le détail de tous les commits mais les nom de périphérique et autres système apparaissent beaucoup, ce qui pourrait confirmer l’hypothèse /sys ou /dev aussi.
votre avatar
Ce n'est pas l'élément primordial, mais il y en a forcément. Ne serait ce que pour les messages d'erreur ou les chemins dans l'arborescence de fichiers, ...
votre avatar
Namespaces, noms de matériels détectés, noms de fichiers,...
Ca doit rentrer là-dedans, non ?
votre avatar
Tout le texte que tu vois dans le noyau (log, strace et co) est forcément une chaine de caractère.

Par exemple dans le kernel, tu as la struct suivante pour la gestion des chaînes de caractères dans le cas du système de tracing.

struct seq_buf {
char *buffer;
size_t size;
size_t len;
loff_t readpos;
};

Et comme tu peux le voir, on a bien ici une chaine de caractère et sa taille (size).


Pour ta confusion, peut-être as-tu confondu avec les flottants et/ou les unités vectorielles, qui sont plus rarement présentes au sein d'un noyau.
votre avatar
Sur un source que j'ai sous la main:

grep -ri strncpy linux-6.12.68/ | wc -l
508

Donc, oui, y'a un besoin même si rapporté à tout le noyau et ses modules c'est pas si énorme et qu'il n'y a pas que du code et de quasi duplicats liés aux architectures supportées, dans ce chalutage. C'est surtout dans les tools, systèmes de traces/filtrage, variantes chaînes des copy to/from user...
votre avatar
Après strscpy ne remplace pas uniquement strncpy, j’ai vu strcpy, snprintf et potentiellement d’autres (ma recherche de commits était sur le remplaçant plus que le remplacé).
votre avatar
En fait, si, tu en manipules quand même quelques unes. Entre la lecture des device trees, l’export des différents fichiers virtuels liés à ton périphérique, un certain nombre d’ioctl qui peuvent nécessiter des chaînes, et tous les logs, ça fait pas mal d’endroits. On n’est pas sur un freertos où effectivement, à part quand tu commences à lire ou écrire sur une SD, t’as pas besoin de chaînes de caractères.

Dans un micro-noyau, probablement que beaucoup de ces trucs seraient effectivement dans l’espace utilisateur. Mais on parle de Linux ici…
votre avatar
C'est là que tu te dis que le principe des chaînes Pascal (avec la taille puis la chaîne) pouvait avoir du sens :D
Du coup pourquoi strncpy n'a pas été dépréciée, depuis le temps?
votre avatar
Ça l’est (je crois que tous les compilos peuvent te faire des warnings, avec les bonnes options), mais il y a du code qui l’utilise, et du code qui repose sur le fait que strncpy ne mets pas le terminal si ça ne tient pas. Donc la transition prend du temps car il faut tout vérifier.

Pour les chaines pascal, oui c’est une bonne idée, mais au final ça génère du code légèrement plus gros (un pointeur + une taille au lieu d’un pointeur à passer en paramètre). Le meilleur compromis aujourd’hui serait plutôt les german strings, mais il faut faire une analyse sur la topologie des chaînes utilisées pour voir si ça vaut vraiment le coup. Sur des mots, c’est hyper rentable, sur des descripteurs comme ceux utilisés dans le noyau linux, c’est peut-être plus discutable.
votre avatar
Ca peut avoir du sens, mais c'est moins efficace (calculs supplémentaires qui peuvent être requis) qu'un caractère nul de fin et peut poser d'autres pb (définition de la taille max du type pouvant obliger à tronquer de longues chaînes?).
votre avatar
parce qu'il y a plein de fonctions C qui ne fonctionneraient plus si on changeait le mode de représentation des chaînes (strtok serait bien plus compliqué par exemple)
votre avatar
M'enfin c'est ce qu'on fait pour n'importe quelle méthode dépréciée non ?
Ici il doit y avoir des appels par centaines, pour atteindre 362 commits. Mais je vois pas où est la nouveauté.
Sur mon projet au taf (projet qui a plus de 20 ans, ~2M de lignes de codes sans compter les dépendances) on a déjà eu à faire ce chantier. C'est surtout le service test qui a transpiré, ces feignasses de dévs ont des outils pour automatiser la recherche et le remplacement :-D