Rust est un langage de programmation polyvalent multi-paradigme qui met l'accent sur les performances, la sécurité des types et la concurrence. Il assure la sécurité de la mémoire, c'est-à-dire que toutes les références pointent vers une mémoire valide, sans ramasse-miettes. Afin d'assurer simultanément la sécurité de la mémoire et d'éviter les courses aux données, son « vérificateur d'emprunts » suit la durée de vie de toutes les références d'un programme pendant la compilation.
Un billet de blog de la Fondation Rust commence par rappeler aux lecteurs que les programmes Rust « ne peuvent pas être compilés si les règles de gestion de la mémoire sont violées, ce qui élimine essentiellement la possibilité d'un problème de mémoire au moment de l'exécution ». Mais le billet poursuit en explorant « Unsafe Rust in the wild » (utilisé pour un petit ensemble d'actions telles que le déréférencement d'un pointeur brut, la modification d'une variable statique mutable ou l'appel à des fonctions non sûres).
« À première vue, il peut sembler que Unsafe Rust compromette les avantages de sécurité de la mémoire pour lesquels Rust est de plus en plus célébré. En réalité, le mot-clé unsafe est accompagné de garanties spéciales et peut être un moyen puissant de travailler avec moins de restrictions lorsqu'une fonction nécessite de la flexibilité, tant que les précautions standard sont utilisées. »
La Fondation énumère dans son billet les mesures de protection disponibles, qui « rendent les exploits rares, mais pas impossibles ». Mais elle analyse également la quantité de code Rust qui utilise réellement le mot-clé unsafe.
Le contenu du billet de blog de la Fondation Rust est présenté ci-dessous :
Les programmes accèdent à la mémoire - ce concept est fondamental en informatique. Selon le langage de programmation utilisé pour écrire le code, il existe différentes manières de gérer l'allocation et l'utilisation de cette mémoire. Chaque approche requiert prudence et précaution.
Un accès involontaire et hors de portée aux zones de mémoire d'un programme peut exposer des données sensibles ou servir de point d'entrée pour l'exploitation, ce qui représente un risque important et peut contribuer à des attaques de type « zero-day ». En résumé, qu'un programmeur gère et alloue la mémoire manuellement ou qu'il compte sur le langage et le compilateur pour le faire à sa place, des pratiques robustes de gestion de la mémoire sont une nécessité.
Les problèmes de sécurité de la mémoire représentent une part importante des vulnérabilités des logiciels. Les acteurs malveillants en sont bien conscients et utilisent un ensemble évolutif de tactiques pour exploiter le code non sécurisé en mémoire dans certaines des attaques logicielles les plus reconnaissables et les plus dommageables de ces dernières années, telles que Heartbleed.
Compte tenu du nombre d'exploits logiciels nuisibles qui hantent notre industrie et de l'importance des enjeux, les fondations de logiciels, les consortiums technologiques et les gouvernements du monde entier prennent conscience de la situation et plaident en faveur de l'amélioration des pratiques et des outils de programmation.
La puissance et la promesse de Rust
Le langage de programmation Rust est souvent cité par les défenseurs de la sécurité de la mémoire comme l'un des langages de programmation les plus sûrs sur le marché aujourd'hui. Langage à mémoire sécurisée par défaut grâce à un concept appelé ownership, Rust fournit des règles et des garanties pour la gestion de la mémoire et considère la sécurité comme un concept de premier ordre.
Les programmes utilisant Rust ne peuvent pas être compilés si les règles de gestion de la mémoire sont violées, ce qui élimine essentiellement la possibilité d'un problème de mémoire au moment de l'exécution. Les développeurs Rust et les utilisateurs d'applications écrites en Rust ont ainsi la certitude que les vulnérabilités de la mémoire ne doivent pas être un sujet de préoccupation.
Safe Rust et « Unsafe Rust »
Bien que Rust soit un outil puissant pour la sûreté de la mémoire et la sécurité, la puissance de ses contrôles de sécurité peut devenir limitante lorsque le programme ne peut pas réellement se tromper mais que le compilateur est incapable de le garantir lui-même ; le programmeur peut prouver l'impossibilité d'un comportement indéfini par des moyens qui ne sont pas à la disposition du compilateur. Dans ces cas, les programmeurs Rust utiliseront le mot-clé unsafe pour indiquer une fonction ou un segment de code ayant a) des considérations de sécurité supplémentaires ou b) des invariants qu'un programmeur doit suivre manuellement pour garantir la sécurité et qui ne sont pas nécessairement exprimés par Rust ou la fonction elle-même. Le mot-clé unsafe permet aux développeurs de déréférencer un pointeur brut, de modifier une variable statique mutable et, surtout, d'appeler des fonctions unsafe.
Bien que l'utilisation de Unsafe Rust puisse théoriquement produire des vulnérabilités similaires à celles des langages non sûrs pour la mémoire, il existe quatre mesures de protection principales pour réduire ces risques à près de zéro :
- L'utilisation du mot-clé unsafe en Rust est un acte explicite, exigeant du développeur qu'il choisisse de le faire. Cela signifie que vous ne pourrez jamais entrer dans un contexte unsafe au sein de votre code Rust sans faire l'effort conscient de le faire ; d'autres langages peuvent vous permettre d'appeler directement du code unsafe ou non géré.
- Le code unsafe doit être isolé dans ses propres blocs de code. Si un problème survient lors de l'utilisation de Unsafe Rust, le code à l'origine du problème est clairement identifié.
- Il y a un nombre limité de façons d'utiliser unsafe et tout le code safe Rust continue à avoir ses contrôles de sécurité normaux même à l'intérieur d'un bloc unsafe.
- Le système de types de Rust fournit toujours des contraintes de sécurité pour les types sûrs de Rust, même à l'intérieur d'un bloc unsafe.
Ces mesures supplémentaires renforçant Unsafe Rust rendent les exploits rares, mais pas impossibles. Pour déterminer le risque posé par Unsafe Rust, il faut examiner combien de code Rust utilise le mot-clé unsafe.
Unsafe Rust en milieu naturel
La façon canonique de distribuer du code Rust est par le biais d'un paquetage appelé crate. En mai 2024, il existe environ 145 000 crates, dont environ 127 000 contiennent du code significatif. Sur ces 127 000 crates, 24 362 font usage du mot-clé unsafe, soit 19,11 % de tous les crates. Et 34,35 % font un appel direct à une fonction dans une autre crate qui utilise le mot-clé unsafe. Près de 20 % de tous les crates ont au moins une instance du mot-clé unsafe, ce qui n'est pas négligeable.
La plupart de ces utilisations Unsafe Rust sont des appels à du code ou à des bibliothèques de langages tiers non Rust, tels que C ou C++. En fait, la crate qui utilise le plus le mot-clé unsafe est la crate Windows, qui permet aux développeurs Rust de faire appel à diverses API Windows. Cela ne signifie pas que le code de ces blocs Unsafe Rust est exploitable en soi (la majorité ou la totalité de ce code ne l'est probablement pas), mais qu'une attention particulière doit être portée à l'utilisation de Unsafe Rust afin d'éviter les vulnérabilités potentielles.
À première vue, il peut sembler que Unsafe Rust réduit les avantages de sécurité de la mémoire pour lesquels Rust est de plus en plus célébré. En réalité, le mot-clé unsafe est assorti de garanties spéciales et peut être un moyen puissant de travailler avec moins de restrictions lorsqu'une fonction nécessite de la flexibilité, tant que les précautions standard sont utilisées.
Sûreté et sécurité : une responsabilité partagée
Comme cela a été dit, Rust est à la hauteur de sa réputation d'outil excellent et transformateur pour une programmation sûre et sécurisée, même dans un contexte Unsafe. Mais cette réputation nécessite des ressources, une collaboration et un examen constant pour être maintenue correctement. Par exemple, le projet Rust continue de développer des outils comme Miri pour permettre la vérification du code Rust non sécurisé. La Rust Foundation s'est engagée dans ce travail par le biais de son initiative de sécurité : un programme visant à soutenir et à faire progresser l'état de la sécurité au sein de l'écosystème et de la communauté du langage de programmation Rust. Dans le cadre de l'initiative de sécurité, l'équipe technologique de la Fondation Rust a développé de nouveaux outils tels que Painter, TypoMania et Sandpit pour détecter les vulnérabilités dans le code Rust, donnant aux utilisateurs un aperçu des vulnérabilités avant qu'elles ne se produisent et permettant une réponse rapide en cas d'exploitation.
La sûreté est une responsabilité partagée - ce concept est fondamental pour des communautés saines. Entre les développeurs qui utilisent Unsafe Rust, les groupes qui préconisent l'utilisation d'outils d'amélioration de la sécurité comme Rust, et les responsables du langage comme la Fondation Rust, nous avons tous un rôle à jouer dans les pratiques de programmation sécurisée. La collaboration et l'attention constante portée à la sécurité permettront au langage de rester aussi résistant que possible aux vulnérabilités à l'avenir.
Source : "Unsafe Rust in the Wild: Notes on the Current State of Unsafe Rust" (Fondation Rust)
Et vous ?
Quel est votre avis sur le sujet ?
Voir aussi :
Comment Rust améliore la sécurité de son écosystème : la Rust Foundation publie un rapport sur ce que leur initiative de sécurité a accompli au cours des six derniers mois de 2023
Consumer Reports publie un rapport détaillé encourageant l'adoption généralisée de langages sûrs pour la mémoire tels que Rust, et sensibilise sur les risques liés à la sécurité de la mémoire