« Nous venons de commencer à travailler sur Nova, un pilote GSP basé sur Rust pour les GPU Nvidia. Nova, à long terme, est destiné à servir de successeur à Nouveau pour les GPU basés sur le firmware GSP », annonce Red Hat.
L’initiative ravive le débat des comparaisons entre Rust et les langages C et C++
Les comparatifs des langages Rust et C++ ont un dénominateur commun : la mise en avant de la supériorité de Rust à C++ en matière de sécurisation de la mémoire.
« Les langages de programmation tels que C et C++ sont des exemples de langages de programmation qui peuvent conduire à un code non sûr pour la mémoire et qui sont encore parmi les langages les plus utilisés aujourd'hui. Pour tenter d'atténuer les dangers du code à mémoire non sécurisée obtenu en C et C++, de nombreux fabricants de logiciels investissent dans des programmes de formation à l'intention de leurs développeurs.
Nombre de ces programmes de formation comprennent des tactiques conçues pour réduire la prévalence des vulnérabilités de sécurité de la mémoire produites par ces langages. En outre, il existe de nombreux programmes de formation organisés par des associations commerciales et industrielles. En outre, diverses organisations et universités proposent des formations et un certificat professionnel pour démontrer la connaissance des pratiques de codage sécurisé en C et en C++.
Bien que la formation puisse réduire le nombre de vulnérabilités qu'un codeur peut introduire, étant donné l'omniprésence des défauts de sécurité de la mémoire, il est presque inévitable que des vulnérabilités de sécurité de la mémoire se produisent encore. Même les développeurs les plus expérimentés introduisent des bogues desquels peuvent résulter des vulnérabilités importantes. La formation doit servir de transition pendant qu'une organisation met en œuvre des contrôles techniques plus robustes, tels que des langages à sécurité mémoire », soulignent les Five Eyes dans un appel à abandonner C ou C++ et à passer à Rust.
« Rust garantit la sécurisation de la mémoire et des threads au moment de la compilation en introduisant des règles de propriété. Il va au-delà du RAII, un mécanisme de gestion de la mémoire couramment utilisé en C++. Il présente deux avantages. Le premier est évident : une fois que le compilateur Rust a validé notre programme, nous n'aurons pas de défauts de segmentation ou de conditions de concurrence lors de l'exécution, ce qui nécessiterait des dizaines d'heures de débogage, en particulier dans une base de code hautement concurrente et principalement asynchrone. La seconde est plus subtile : le compilateur Rust restreint simplement les types de fautes, ce qui réduit les fragments de code étroitement imbriqués qui peuvent causer un tel comportement bogué. La réplication des bogues est considérablement améliorée avec l'aide de l'exécution déterministe », indique l'éditeur RisingWave à propos de la réécriture de son SGBD Cloud natif depuis zéro en Rust après abandon du projet en C++.
« Choisir Rust c’est opter pour une meilleure sécurisation des logiciels qu’avec le C, mais une efficacité énergétique et une performance d’exécution que seul le C offre », déclare Amazon. En effet, certains benchmarks suggèrent que les applications Rust sont plus rapides que leurs équivalents en langage C. Et c’est justement pour ces atouts que sont la parité en termes de vitesse d’exécution en comparaison avec le C, mais surtout pour la sécurisation et la fiabilité que Mark Russinovich recommande le Rust plutôt que le C ou le C++.
« En 2021, nous avons annoncé que Google rejoignait la Rust Foundation. À l'époque, Rust était déjà largement utilisé dans Android et d'autres produits Google. Notre annonce soulignait notre engagement à améliorer les examens de sécurité du code Rust et son interopérabilité avec le code C++. Rust est l'un des outils les plus puissants dont nous disposons pour résoudre les problèmes de sécurité de la mémoire. Depuis cette annonce, les leaders de l'industrie et les agences gouvernementales se sont fait l'écho de notre sentiment.
Nous sommes ravis d'annoncer que Google a accordé une subvention d'un million de dollars à la Fondation Rust pour soutenir les efforts visant à améliorer la capacité du code Rust à interopérer avec les bases de code C++ existantes. Nous poursuivons également notre engagement envers la communauté open-source Rust en regroupant et en publiant des audits pour les crates Rust que nous utilisons dans les projets open-source de Google. Ces contributions, ainsi que nos précédentes contributions en matière d'interopérabilité, nous rendent enthousiastes quant à l'avenir de Rust », écrit Google dans le cadre de l’annonce de l’accord d’une subvention d’un million de dollars de la Fondation Rust pour soutenir les efforts d’interopérabilité avec C++.
« Nous sommes ravis de soutenir ce travail par le biais de l'initiative Interop de la Fondation Rust et en collaboration avec le projet Rust afin de s'assurer que tous les ajouts effectués sont appropriés et répondent aux défis de l'adoption de Rust auxquels les projets utilisant C++ sont confrontés. L'amélioration de la sécurité de la mémoire dans l'industrie du logiciel est l'un des principaux défis technologiques de notre époque, et nous invitons la communauté et l'industrie à se joindre à nous pour travailler ensemble à la sécurisation de l'écosystème open source pour tous », ajoute le géant technologique.
Rust de Mozilla Research est le type de langage de programmation auquel ceux qui écrivent du code pour des systèmes d’entrée/sortie de base (BIOS), des chargeurs d’amorce, des systèmes d’exploitation, etc. portent un intérêt. De façon graduelle, Microsoft migre vers ce dernier au détriment d’autres langages que l’entreprise juge moins outillés pour la mise sur pied d’applications dites système. Motif : Rust offre de meilleures garanties en matière de sécurisation des accès mémoire des logiciels.
« Les problèmes de gestion de la mémoire sont exploités depuis des décennies et sont encore trop courants aujourd'hui. Nous devons utiliser de façon systématique des langages sécurisés pour la mémoire et d'autres protections lors du développement de logiciels afin d'éliminer ces faiblesses des cyberacteurs malveillants », déclare Neal Ziring, directeur technique de la cybersécurité de la NSA.
En effet, il y a une liste de griefs qui reviennent à l’encontre de langages de programmation comme le C et le C++ : les problèmes liés à la gestion de la mémoire – dépassements de mémoire tampon, allocations non libérées, accès à des zones mémoire invalides ou libérées, etc. D’après les chiffres du dictionnaire Common Vulnerabilities and Exposure (CVE), 15,9 % des 2288 vulnérabilités qui ont affecté le noyau Linux en 20 ans sont liées à des dépassements de mémoire tampon.
Le créateur du C++ est d’avis que « La sécurisation des logiciels via le langage Rust n'est pas supérieure à celle offerte par le C++ »
Mark Russinovich de Microsoft a déclaré que « c’est le moment d’arrêter d’initier de nouveaux projets en langages C ou C++ et de passer à Rust. » Motif : le Rust offre de meilleures garanties de sécurisation des logiciels que les langages C ou C++. La position reprise quelques mois plus tard par la NSA trouve contradicteur et pas des moindres. Sans détour, le créateur du langage C++ déclare : « la sécurisation des logiciels par le langage Rust n’est pas supérieure à celle offerte par le C++. »
En effet, Bjarne Stroustrup s’inscrit en faux avec le fait que la publication de la NSA limite la notion de sécurisation des logiciels à celle de sécurisation de la mémoire. En réalité, cet aspect est un dénominateur commun de toutes les publications qui conseillent de mettre le C ou le C++ au rebut au profit du langage Rust en raison des garanties de sécurisation des logiciels que plusieurs grandes entreprises (Microsoft, Amazon, etc.) lui reconnaissent.
« Il n'y a pas qu'une seule définition de la notion de "sécurité" et nous pouvons réaliser une variété de types de sécurité par une combinaison de styles de programmation, de bibliothèques de support et grâce à la mise à profit de l'analyse statique », indique-t-il. Bjarne Stroustrup suggère ainsi que ce qu’il est possible d’obtenir du C++ en matière de sécurisation des logiciels dépend entre autres du développeur et notamment de la connaissance des outils que lui offre le langage, de sa maîtrise du compilateur, etc.
Des ingénieurs de Google au fait de ce que le C++ leur offre comme possibilités se sont donc lancés dans la mise sur pied dans ce langage d’un borrow-checker. C’est une fonctionnalité du compilateur Rust qui garantit la sécurisation de la mémoire grâce à une gestion des allocations en mémoire des pointeurs.
L’équipe de Google dont la publication est parvenue à la conclusion que le système de types du C++ ne se prête pas à un tel exercice. Et donc que la sécurisation de la mémoire en C++ est réalisable avec des vérifications lors de l’exécution du programme. En d’autres termes, c’est avec du code C++ lent qu’il est possible d’atteindre un niveau de sécurisation équivalent à celui du Rust.
Code Rust : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | #include <type_traits> #include <utility> #include <assert.h> #include <stddef.h> enum NoRefs {}; enum HasMutRef {}; enum HasRefs {}; template <class T, typename Mode> class Own; template <class T> class MutRef; template <class T> class Ref; template <class T, typename... Args> inline Own<T, NoRefs> make(Args... args) { return Own<T, NoRefs>(std::forward<Args>(args)...); } template <class T> inline Own<T, NoRefs> consume(Own<T, HasMutRef> own, MutRef<T> ref) { return Own<T, NoRefs>(std::move(own)); } template <class T> inline Own<T, NoRefs> consume(Own<T, HasRefs> own) { return Own<T, NoRefs>(std::move(own)); } template <class T> std::pair<Own<T, HasMutRef>, MutRef<T>> mut(Own<T, NoRefs> own) { T* t = own.t_; own.t_ = nullptr; return std::make_pair(Own<T, HasMutRef>(t), MutRef<T>(t)); } template <class T> std::pair<Own<T, HasRefs>, MutRef<T>> ref(Own<T, NoRefs> own) { T* t = own.t_; own.t_ = nullptr; return std::make_pair(Own<T, HasRefs>(t), Ref<T>(t)); } // No refs exist. template <class T> class [[clang::trivial_abi]] Own<T, NoRefs> { public: template <typename... Args> Own(Args... args) : t_(new T(std::forward<Args>(args)...)) {} ~Own() { delete t_; } Own(Own<T, NoRefs>&& other) : t_(other.t_) { other.t_ = nullptr; } T& operator*() const noexcept { return *t_; } T* operator->() const noexcept { return t_; } private: friend Own<T, NoRefs> consume<T>(Own<T, HasMutRef> own, MutRef<T> ref); friend Own<T, NoRefs> consume<T>(Own<T, HasRefs> own); friend std::pair<Own<T, HasMutRef>, MutRef<T>> mut(Own<T, NoRefs> own); friend std::pair<Own<T, HasRefs>, Ref<T>> ref(Own<T, NoRefs> own); Own(Own<T, HasMutRef>&& own) : t_(own.t_) {} Own(Own<T, HasRefs>&& own) : t_(own.t_) {} T* t_; }; // A mut ref exists. template <class T> class [[clang::trivial_abi]] Own<T, HasMutRef> { public: T& operator*() const noexcept { return *t_; } T* operator->() const noexcept { return t_; } private: friend class Own<T, NoRefs>; Own(T* t) : t_(t) {} ~Own() {} T* t_; }; // Non-mut refs exist. template <class T> class [[clang::trivial_abi]] Own<T, HasRefs> { public: T& operator*() const noexcept { return *t_; } T* operator->() const noexcept { return t_; } Ref<T> ref() { return Ref<T>(t_, &count_); } private: friend std::pair<Own<T, HasRefs>, Ref<T>> ref(Own<T, NoRefs> own); explicit Own(T* t) : t_(t) {} ~Own() { assert(count_ == 0u); } T* t_; uint32_t count_; }; template <class T> class MutRef { public: T& operator*() const noexcept { return *t_; } T* operator->() const noexcept { return t_; } ~MutRef() = default; MutRef(MutRef&& other) : t_(other.t_) {} private: friend std::pair<Own<T, HasMutRef>, MutRef<T>> mut(Own<T, NoRefs> own); MutRef(T* t) : t_(t) {} T* t_; }; template <class T> class Ref { public: T& operator*() const noexcept { return *t_; } T* operator->() const noexcept { return t_; } ~Ref() { --(*count_); } Ref(const Ref& other) : t_(other.t_), count_(other.count_) { ++(*count_); } Ref(Ref&& other) : t_(other.t_), count_(other.count_) {} private: friend std::pair<Own<T, HasRefs>, Ref<T>> ref(Own<T, NoRefs> own); Ref(T* t, uint32_t* count) : t_(t), count_(count) { ++(*count); } T* t_; uint32_t* count_; }; MutRef<int> Borrows(MutRef<int> i) { (*i)++; return i; } TEST(Borrow, HelloWorld) { // Can't do this. The HasMutRefs type is not destructible outside of // consume()in order to have compiler check it is re-owned, but it won't // compile. To pass the HasMutRefs to consume() it has to be destroyed both // inside and outside of consume(). This is true even if trivial_abi is // used and only one destructor would actually run. Own<int, NoRefs> i = make<int>(5); auto& hasmut = mut(std::move(i)); MutRef<int> ref = Borrows(std::move(hasmut.second)); Own<int, NoRefs> i2 = consume(std::move(hasmut.first), std::move(ref)); } |
Source : liste de diffusion du noyau Linux
Et vous ?
Êtes-vous en accord avec les griefs portés à l'endroit de C/C++ en matière de sécurité ? Le problème n'est-il pas plutôt celui de la qualité des développeurs ?
Le C et le C++ ont-ils vraiment besoin de remplaçants surtout en matière de programmation système ?
Votre entreprise a-t-elle adopté le langage Rust ? Si oui, pour quelles raisons ?
Voir aussi :
L'équipe Microsoft Security Response Center recommande l'utilisation de Rust comme approche proactive pour un code plus sécurisé
Quel langage pourrait remplacer C ? Après avoir comparé Go, Rust et D, le choix d'Andrei Alexandrescu se porte sur D
C2Rust : un outil qui permet de faire la traduction et la refactorisation de votre code écrit en langage C vers le langage Rust