Microsoft considère très sérieusement le Rust comme successeur aux C et C++ pour sa propre programmation système. Une déclaration importante, qui jette une nouvelle lumière sur le langage créé par Mozilla et veut sensibiliser les développeurs aux problèmes de sécurité liés à la mémoire.
La firme s’est lancée dans une série d’articles portant sur la sécurité du code informatique. L’éditeur en dresse un tableau peu reluisant, avec un objectif en tête : réduire, et si possible se débarrasser des erreurs liées à la gestion de la mémoire.
Le constat s’établit sur la base de plusieurs études et d’une longue série de statistiques. Conséquence, la question se pose : par quoi remplacer les langages C et C++ couramment utilisés pour l’écriture du code natif ?
Les langages dits « memory safe » existent depuis longtemps. Microsoft donne bien sûr les exemples maison – C# et F# – on citera aussi l’un des plus connus : Java. Mais l’éditeur, même en citant leurs qualités intrinsèques, ne semble pas satisfait, pour une raison principale : leur coût en performances.
Il se tourne donc vers un langage open source créé par Mozilla, initialement pour ses propres besoins : Rust. Ce n’est plus vraiment un jeune langage (2010), mais il reste récent, posant des problématiques que nous exposerons. En dépit des défauts inhérents à son âge, l’entreprise s’intéresse de très près au Rust comme successeur de C/C++ dans ses propres produits, jusqu’à citer indirectement le noyau de Windows.
70 % des failles de sécurité liées à la mémoire
Dans une présentation donnée à la conférence BlueHat IL, Matt Miller, du MSRC (Microsoft Security Response Center), faisait un drôle de constat : l’immense majorité (70 %) des failles corrigées par Microsoft – et pour lesquelles une identification CVE avait été fournie – provenaient de bugs de corruption de mémoire introduits dans le code C ou C++ par les développeurs. Cette statistique s’est avérée stable sur la décennie écoulée.
Exemple le plus courant, très souvent croisé dans les comptes rendus de sécurité ? Les dépassements de mémoire tampon (buffer overflows). Ils surviennent quand un processus, censé écrire dans un espace mémoire spécifique, écrit dans un autre. Si ce dernier n’est pas libre, des données sont écrasées, pouvant entrainer un comportement imprévisible de l’ensemble du système.
Dans la plupart des cas, le symptôme est un plantage de l’application ou du système. Mais un dépassement de mémoire tampon peut aussi être détourné et utilisé à des fins de piratage informatique. La technique consiste alors à écrire dans une zone un code exécutable.
Notez tout de même que ces soucis sont connus depuis bien longtemps. C’est ce qui explique l’apparition de technologies comme l’ASLR (Adress Space Layout Randomization). Le principe en est simple : déplacer de manière aléatoire les données critiques pour que leur emplacement soit imprévisible. Ces techniques ne sont toutefois pas infaillibles et ne font que limiter les risques, sans jamais les réduire à zéro.
Les langages « memory safe »
Ces fautes sont courantes en C et C++ car ils n’incluent pas dès l’origine de mécanismes de sûreté pour la mémoire. Les pointeurs utilisés peuvent cibler n’importe quelle zone mémoire et requièrent donc de multiples précautions, reposant sur les épaules des développeurs.
« Le boulot principal d’un développeur n’est pas de se préoccuper de la sécurité mais de travailler sur les fonctionnalités », explique Gavin Thomas, ingénieur responsable au MSRC. « Plutôt que d’investir dans toujours plus d’outils, formations et correctifs, pourquoi pas dès le départ un langage où ils ne pourraient pas introduire de problèmes de sûreté mémoire dans leurs fonctionnalités ? ».
C’est déjà le cas de langages comme C# ou Java qui sont de haut niveau, c’est-à-dire centrés sur la résolution de problèmes spécifiques, sans se soucier (en général) des composants de la machine. Parmi leurs caractéristiques, on trouve en particulier le typage sûr. Le compilateur valide alors (statiquement) les types en vérifiant qu’ils n’ont pas été affectés de manière erronée. Cet attribut permet à lui seul d’éviter la plupart des erreurs menant à une corruption de la mémoire.
Mais ils ont un désavantage : ils requièrent la présence d’un runtime pour fonctionner. Cette machine virtuelle a un coût en performances, pas nécessairement visible dans un cadre applicatif (potentiellement au lancement, souvent un peu plus long), mais clairement plus sensible pour un système d’exploitation, a fortiori un noyau.
C et C++ restent donc largement utilisés pour leurs performances. On se souvient que Google avait même lancé son NaCl (Native Client) pour permettre aux développeurs web d’écrire du code C/C++, chargé avec le reste du site. Principal bénéfice, la rapidité d’exécution. Le projet a depuis été supplanté par les nombreux travaux sur WebAssembly, autour duquel s’est organisé un consortium (voir notre article).
Le C++ en particulier n’est pas démuni contre les éventuels soucis de corruption de la mémoire. Plusieurs mesures ont été implémentées avec les années. Par exemple, les pointeurs intelligents peuvent prévenir en partie les risques. Cependant, même si un développeur au meilleur de sa forme et avec les bonnes compétences peut faire attention à toujours utiliser les techniques à sa disposition, la difficulté devient exponentielle quand le projet prend une taille importante.
Ce qu’aimerait Microsoft ? La synthèse de ces avantages : « Si seulement les développeurs pouvaient avoir toutes les garanties de sécurité pour la mémoire des langages comme C# combinées à toute l’efficacité de C++ ». C’est là qu’intervient le Rust, qui pour l’éditeur réunit le meilleur des deux mondes.
La solution dans l’open source
Le simple fait de regarder en direction du langage de Mozilla n’est pas anodin : le Rust est open source (licence Apache 2.0). Microsoft le considère-t-il sérieusement comme une solution d’avenir pour ses propres besoins ? Il semblerait bien.
Dans son dernier billet de blog, l’éditeur évoque les langages « memory safe » comme C#, F#, Swift, Go et Python. Aucun d’entre eux ne se veut universel et est donc à utiliser en fonction du contexte. Python est par exemple un langage de script et n’est pas fait pour la situation qui intéresse Microsoft.
« Nous discutons cependant du besoin d’un langage sûr pour la programmation système (un langage pouvant construire des systèmes sur lesquels d’autres logiciels vont fonctionner, comme un noyau). De telles charges de travail nécessitent la vitesse et les performances prévisibles que C, C++ et Rust fournissent. Les langages capables d’assurer la sûreté de la mémoire via le ramasse-miettes ne sont pas idéaux puisque leurs runtimes peuvent conduire à des performances imprévisibles et une surcharge inutile ».
Parmi les avantages du Rust, Microsoft cite en particulier son runtime minimal et surtout optionnel. La bibliothèque standard dépend de libc (comme C et C++), mais n’est pas forcément nécessaire, permettant au code de fonctionner sans système d’exploitation préalable.
Deuxième avantage, la granularité dans le contrôle de la mémoire, qui permet au développeur « de choisir quand et combien de mémoire doit être allouée ». Sur ce point, Microsoft considère que Rust est au même niveau que C et C++.
Mais c’est bien sur la protection de cette mémoire que Rust se différencie, faisant dire à l’entreprise que les fameux 70 % de failles n’auraient sans doute jamais existé si le code concerné avait été écrit avec le langage de Mozilla. À noter, d’ailleurs, que Microsoft ne s’exclue pas des erreurs, puisqu’il s’agit dans l’immense majorité des cas de vulnérabilités relevées dans ses propres produits.
La protection accordée n’est cependant pas forcée. Les développeurs peuvent déclarer explicitement des blocs de code comme « unsafe » quand les opérations l’exigent. Mais même ces opérations finissent par être « empaquetées » dans des structures vérifiées statiquement à la compilation.
D’autres points sont appréciés. L’exactitude du langage par exemple, qui a permis en interne de vérifier un vieil adage : « Si ça compile, c’est que ça marche ». La vérification statique des propriétés va également au-delà de la mémoire et permet de se débarrasser d’autres problèmes potentiels, comme les pointeurs null et les accès concurrents.
C’est toutefois la communauté qui remporte l’adhésion de Microsoft. Même si le langage a été créé par Mozilla, qui investit toujours dedans, la majorité des contributions provient de sa communauté. Selon le classement Stack Overflow pour l’année 2018, Rust est en fait le langage le plus populaire, devançant Kotlin, Python et TypeScript. Et plus la communauté grandit, plus le langage devient apte à répondre aux demandes, et plus les tests sont nombreux.
Et pourquoi pas un Windows réécrit en Rust ?
Quelle crédibilité apporter aux réflexions de Microsoft sur ce langage ? Conséquente car l’éditeur en est à publier plusieurs billets de blogs expliquant tout le bien qu’il pense de Rust et la manière dont il pourrait très clairement bénéficier à la programmation système. Et puisque les fameux 70 % concernent des failles dans ses propres produits, il est permis de penser que l’entreprise pense avant tout à sa propre programmation système.
L’image d’un avenir réécrit en Rust chez Microsoft se précise encore quand la firme aborde les quelques points noirs qui l’empêchent pour l’instant de se mettre à la tâche. Parmi eux, un manque d’interopérabilité avec la chaine d’outils maison. L’interopérabilité avec le C++ est également citée comme un problème, de même que la manière de réguler l’utilisation du surensemble « unsafe » du Rust dans les projets de grande taille.
Microsoft va donc continuer à publier des billets sur le langage, notamment pour détailler les problèmes et ce qui manque à son goût pour une utilisation à grande échelle au sein de l’entreprise. La couleur est d’ailleurs annoncée : elle espère impliquer la communauté Rust pour réfléchir aux solutions, signe supplémentaire d’une volonté d’utiliser le langage.
Dans l’hypothèse où toutes les barrières seraient levées, faut-il s’attendre à une réécriture de Windows en Rust ? Pas nécessairement. Au vu de l’ampleur du travail, il est plus probable que la firme travaillerait directement sur de nouvelles briques ou une nouvelle génération de son système d’exploitation.
En attendant, le langage va probablement bénéficier de ce nouvel éclairage, de la même manière que TypeScript (créé par Microsoft) avait été adoubé par Google, qui en avait fait la voie royale pour Angular.