Google vient de publier le livre blanc « Secure by Design: Googles Perspective on Memory Safety ». Google envisage une transition progressive vers des langages scurit mmoire tels que Java, Go et Rust pour le nouveau code et les composants particulirement risque. Mais Google reconnait aussi qu’il faut complter cette transition par des amliorations de la scurit du code C++ existant, voici son point de vue sur la scurit de la mmoire :
Rsum
L’anne 2022 a marqu le 50e anniversaire des vulnrabilits lies la scurit de la mmoire, signales pour la premire fois par Anderson. Un demi-sicle plus tard, nous sommes toujours confronts des bogues de scurit de la mmoire malgr des investissements substantiels pour amliorer les langages non scuriss.
Comme d’autres, les donnes et les recherches internes de Google sur les vulnrabilits montrent que les bogues de scurit de la mmoire sont trs rpandus et constituent l’une des principales causes de vulnrabilits dans les bases de code non sres pour la mmoire. Ces vulnrabilits mettent en danger les utilisateurs finaux, notre industrie et la socit dans son ensemble.
Chez Google, nous avons des dizaines d’annes d’exprience dans la rsolution, grande chelle, de grandes catgories de vulnrabilits qui taient autrefois aussi rpandues que les problmes de scurit de la mmoire. Sur la base de cette exprience, nous pensons qu’une scurit leve de la mmoire ne peut tre obtenue qu’au moyen d’une approche « Secure-by-Design » centre sur l’adoption globale de langages offrant des garanties rigoureuses en matire de scurit de la mmoire. Par consquent, nous envisageons une transition progressive vers des langages scurit mmoire.
Au cours des dernires dcennies, Google a dvelopp et accumul des centaines de millions de lignes de code C++ qui sont utilises activement et font l’objet d’un dveloppement actif et continu. Cette trs grande base de code existante pose des problmes importants pour la transition vers la scurit de la mmoire :
- D’une part, nous ne voyons pas de voie raliste pour une volution du C++ vers un langage offrant des garanties rigoureuses de scurit de la mmoire, y compris la scurit temporelle.
- D’autre part, une rcriture grande chelle du code C++ existant dans un langage diffrent et sr pour la mmoire semble trs difficile et restera probablement irralisable.
Cela signifie que nous allons probablement exploiter une base de code C++ trs importante pendant un certain temps. Nous considrons donc qu’il est important de complter la transition vers des langages mmoire scurise pour le nouveau code et les composants particulirement risque par des amliorations de la scurit du code C++ existant, dans la mesure du possible. Nous pensons que des amliorations substantielles peuvent tre obtenues par une transition progressive vers un sous-ensemble de langage C++ partiellement sr pour la mmoire, complt par des fonctions de scurit matrielle lorsqu’elles sont disponibles.
Dfinition des bogues de scurit de la mmoire
Les bogues de scurit de la mmoire surviennent lorsqu’un programme permet l’excution d’instructions qui lisent ou crivent dans la mmoire, alors que le programme est dans un tat o l’accs la mmoire constitue un comportement non dfini. Lorsqu’une telle instruction est accessible dans un tat de programme sous contrle adverse (par exemple, traitement d’entres non fiables), le bogue reprsente souvent une vulnrabilit exploitable (dans le pire des cas, permettant l’excution d’un code arbitraire).
Dfinition d’une scurit mmoire rigoureuse
Dans ce contexte, nous considrons qu’un langage est rigoureusement sr en mmoire s’il :
- utilise par dfaut un sous-ensemble sr bien dlimit, et
- garantit qu’un code arbitraire crit dans le sous-ensemble sr est empch de provoquer une violation de la scurit spatiale, temporelle, de type ou d’initialisation.
Ceci peut tre tabli par toute combinaison de restrictions la compilation et de protections l’excution, condition que les mcanismes d’excution garantissent que la violation de la scurit ne peut pas se produire.
quelques exceptions prs, bien dfinies, tout le code devrait pouvoir tre crit dans le sous-ensemble sr bien dlimit.
Dans les nouveaux dveloppements, le code potentiellement dangereux ne devrait se trouver que dans les composants/modules qui optent explicitement pour l’utilisation de constructions non sres en dehors du sous-ensemble de langage sr, et qui exposent une abstraction sre dont la solidit a t examine par des experts. Les constructions non sres ne doivent tre utilises qu’en cas de ncessit, par exemple pour des raisons de performances critiques ou dans le code qui interagit avec des composants de bas niveau.
Lorsque l’on travaille avec du code existant dans un langage non sr pour la mmoire, le code non sr doit tre limit aux utilisations suivantes :
- le code crit dans un langage sr qui fait des appels une bibliothque mise en uvre par une ancienne base de code crite dans un langage non sr.
- l’ajouts/modifications de code des bases de code existantes non sres, o le code est trop profondment entreml pour que le dveloppement dans un langage sr soit pratique.
Impact des vulnrabilits lies la scurit de la mmoire
Les bogues de scurit de la mmoire sont responsables de la majorit (~70%) des vulnrabilits graves dans les grandes bases de code C/C++. Voici le pourcentage de vulnrabilits dues l’inscurit de la mmoire :
- Chrome : 70% des vulnrabilits leves/critiques
- Android : 70% des vulnrabilits leves/critiques
- Serveurs Google : 16 29 % des vulnrabilits
- Projet Zro : 68 % des journes zro dans la nature
- Microsoft : 70 % des vulnrabilits avec CVE
Les erreurs de scurit de la mmoire continuent d’apparatre en tte des listes des « bogues les plus dangereux », telles que le Top 25 et le Top 10 des vulnrabilits exploites connues du CWE. Les recherches internes de Google sur les vulnrabilits dmontrent plusieurs reprises que l’absence de scurit de la mmoire affaiblit d’importantes limites de scurit.
Comprendre les bogues de scurit de la mmoire
Catgories de bogues de scurit de la mmoire
Il peut tre utile de distinguer un certain nombre de sous-classes de bogues de scurit de la mmoire qui diffrent par leurs solutions possibles et leur impact sur les performances et l’exprience des dveloppeurs :
- Les bogues de scurit spatiale (par exemple, « dpassement de tampon », « accs hors limites ») surviennent lorsqu’un accs la mmoire se rfre une mmoire situe en dehors de la rgion alloue l’objet accd.
- Les bogues de scurit temporelle surviennent lorsqu’un accs la mmoire d’un objet se produit en dehors de la dure de vie de l’objet. C’est le cas, par exemple, lorsqu’une fonction renvoie un pointeur sur une valeur de sa pile (« use-after-return »), ou en raison d’un pointeur sur une mmoire alloue au tas qui a depuis t libre, et ventuellement ralloue pour un autre objet (« use-after-free »).
Dans les programmes concurrents, il est courant que ces bogues se produisent en raison d’une mauvaise synchronisation des threads, mais lorsque la violation initiale de la scurit se situe en dehors de la dure de vie de l’objet, nous la classons comme une violation de la scurit temporelle.
- Les bogues de scurit de type surviennent lorsqu’une valeur d’un type donn est lue partir d’une mmoire qui ne contient pas de membre de ce type. C’est le cas, par exemple, lorsque la mmoire est lue aprs un cast de pointeur invalide.
- Les bogues de scurit d’initialisation surviennent lorsque la mmoire est lue avant d’tre initialise. Cela peut conduire des divulgations d’informations et des bogues de scurit de type/temporels.
- Les bogues de scurit lis la course aux donnes rsultent de lectures et d’critures non synchronises par diffrents threads, qui peuvent accder un objet dans un tat incohrent. D’autres formes de bogues de scurit peuvent galement rsulter d’une synchronisation incorrecte ou manquante, mais nous ne les classons pas dans la catgorie des bogues de scurit lis l’espace de donnes et ils sont traits ci-dessus. Ce n’est que lorsque les lectures et les critures sont par ailleurs correctes, l’exception du fait qu’elles ne sont pas synchronises, qu’elles sont considres comme des bogues de scurit lis l’volution des donnes.
Une fois qu’une violation de la scurit de l’espace de donnes s’est produite, l’excution ultrieure peut provoquer d’autres bogues de scurit. Nous les classons dans la catgorie des bogues de scurit lis la course aux donnes, car la violation initiale est strictement un problme li la course aux donnes, sans qu’aucun autre bogue ne soit vident.
La classification utilise ici correspond peu prs la taxonomie de scurit de la mmoire d’Apple.
Dans les langages non scuriss tels que C/C++, il incombe au programmeur de s’assurer que les conditions pralables de scurit sont remplies afin d’viter d’accder une mmoire non valide. Par exemple, pour la scurit spatiale, lors de l’accs aux lments d’un tableau via un index (par exemple, a[i] = x), il incombe au programmeur de s’assurer que l’index se trouve dans les limites de la mmoire alloue de manire valide.
Nous excluons actuellement la scurit de la trace des donnes de la prise en compte de la scurit rigoureuse de la mmoire pour les raisons suivantes :
- La scurit de la course aux donnes est une classe de bogues part entire, qui ne recouvre que partiellement la scurit de la mmoire. Par exemple, Java ne fournit pas de garanties en matire de scurit des courses de donnes, mais les courses de donnes en Java ne peuvent pas entraner la violation des invariants d’intgrit du tas de donnes de bas niveau (corruption de la mmoire).
- l’heure actuelle, nous ne disposons pas du mme niveau de preuve concernant l’inscurit des courses de donnes, qui entrane des problmes systmiques de scurit et de fiabilit pour les logiciels crits dans des langages par ailleurs rigoureusement srs pour la mmoire (par exemple, Go).
Pourquoi les bogues de scurit de la mmoire sont-ils si difficiles rsoudre ?
Les bogues de scurit de la mmoire sont assez courants dans les grandes bases de code C++. L’intuition qui sous-tend la prvalence des bogues de scurit de la mmoire est la suivante :
Premirement, dans les langages non srs, les programmeurs doivent s’assurer que la condition pralable de scurit de la mmoire de chaque instruction est remplie juste avant son excution, dans n’importe quel tat du programme qui pourrait tre atteint, potentiellement sous l’influence d’entres adverses dans le programme.
Deuximement, les instructions non sres qui peuvent entraner des bogues de scurit de la mmoire sont trs courantes dans les programmes C/C++ – il y a beaucoup d’accs aux tableaux, de drfrencements de pointeurs et d’allocations du tas.
Enfin, il est difficile, mme avec l’aide d’un outil, de raisonner sur les conditions pralables de scurit et de dterminer si le programme les garantit dans tous les tats possibles du programme. Par exemple :
- Raisonner sur l’intgrit d’un pointeur/index implique d’envelopper l’arithmtique des entiers, ce qui est tout fait non intuitif pour les humains.
- Le raisonnement sur la dure de vie des objets du tas implique souvent des invariants complexes et subtils pour l’ensemble du programme. Mme le cadrage local et la dure de vie peuvent tre subtils et surprenants.
« De nombreux bogues potentiels » combins un « raisonnement difficile sur les conditions pralables de scurit » et au fait que « les humains font des erreurs » se traduisent par un nombre relativement important de bogues rels.
Les tentatives d’attnuation du risque de vulnrabilit de la mmoire par l’ducation des dveloppeurs et des approches ractives (y compris l’analyse statique/dynamique pour trouver et corriger les bogues, et diverses mesures d’attnuation des exploits) n’ont pas russi rduire l’incidence de ces bogues un niveau tolrable. En consquence, des vulnrabilits graves continuent d’tre causes par cette catgorie de failles, comme nous l’avons vu plus haut.
S’attaquer aux bogues de scurit de la mmoire
S’attaquer la scurit de la mmoire ncessite une approche sur plusieurs fronts :
- Prvenir les bogues de scurit de la mmoire par un codage sr.
- Attnuer les bogues de scurit de la mmoire en rendant leur exploitation plus coteuse.
- Dtecter les bogues de scurit de la mmoire, le plus tt possible dans le cycle de dveloppement.
Nous pensons que ces trois lments sont ncessaires pour rsoudre le problme de la scurit de la mmoire l’chelle de Google. D’aprs notre exprience, il est ncessaire de mettre l’accent sur la prvention par le biais d’un codage sr pour atteindre durablement un niveau d’assurance lev.
Prvention des bogues de scurit de la mmoire par un codage sr
Notre exprience chez Google montre qu’il est possible d’liminer des classes de problmes grande chelle en supprimant l’utilisation de constructions de codage sujettes la vulnrabilit. Dans ce contexte, nous considrons qu’une construction n’est pas sre si elle peut potentiellement manifester un bogue (par exemple, une corruption de la mmoire) moins qu’une condition pralable de scurit ne soit satisfaite au moment de son utilisation. Les constructions non sres mettent la charge du dveloppeur la responsabilit de garantir la condition pralable. Notre approche, que nous appelons « Safe Coding« , traite les constructions de codage non sres elles-mmes comme des dangers (c’est–dire indpendamment et en plus de la vulnrabilit qu’ils peuvent causer), et est centre sur l’assurance que les dveloppeurs ne rencontrent pas de tels dangers lors de la pratique rgulire du codage.
En substance, le codage sr demande que les constructions dangereuses soient interdites par dfaut et que leur utilisation soit remplace par des abstractions sres dans la plupart des codes, avec des exceptions soigneusement examines. Dans le domaine de la scurit de la mmoire, les abstractions sres peuvent tre fournies en utilisant :
- Des invariants de scurit garantis statiquement ou dynamiquement, empchant l’introduction de bogues. Des vrifications au moment de la compilation et des mcanismes mis par le compilateur ou fournis au moment de l’excution garantissent que des classes particulires de bogues ne peuvent pas se produire. Par exemple, au moment de la compilation, l’analyse de la dure de vie empche les bogues de se produire :
- Au moment de la compilation, l’analyse de la dure de vie empche un sous-ensemble de bogues de scurit temporelle.
- Au moment de l’excution, l’initialisation automatise des objets garantit l’absence de lectures non initialises.
- Dtection d’erreurs au moment de l’excution, application des invariants de scurit de la mmoire en levant une erreur lorsqu’une violation de la scurit de la mmoire est dtecte au lieu de poursuivre l’excution avec une mmoire corrompue. Les bogues sous-jacents existent toujours et devront tre corrigs, mais les vulnrabilits sont limines ( l’exception des attaques par dni de service). Par exemple :
- Une recherche dans un tableau peut offrir une dtection d’erreur de scurit spatiale en vrifiant que l’index donn est l’intrieur des limites. Les vrifications peuvent tre supprimes lorsque la scurit est prouve de manire statique.
- Un cast de type peut offrir une dtection d’erreur de scurit de type en vrifiant que l’objet cast est une instance du type rsultant (par exemple, ClassCastException en Java ou CastGuard pour C++).
Dans le domaine de la scurit de la mmoire, l’approche du codage sr est incarne par des langages srs, qui remplacent les constructions non sres par des abstractions sres telles que les vrifications des limites d’excution, les rfrences collectes par le garbage, ou les rfrences ornes d’annotations de dure de vie vrifies de manire statique.
L’exprience montre que les problmes de scurit de la mmoire sont en effet rares dans les langages srs ramasse-miettes tels que Go et Java. Cependant, le ramassage des ordures s’accompagne gnralement d’un surcot d’excution important. Plus rcemment, Rust est apparu comme un langage qui incarne l’approche du codage sr base principalement sur la discipline de type vrifie la compilation, ce qui entrane des surcots d’excution minimes.
Les donnes montrent que le codage scuris fonctionne pour la scurit de la mmoire, mme dans les environnements sensibles aux performances. Par exemple, Android 13 a introduit 1,5 million de lignes de Rust sans aucune vulnrabilit en matire de scurit de la mmoire. Cela a permis d’viter des centaines de vulnrabilits en matire de scurit de la mmoire : « La quantit de nouveau code dangereux pour la mmoire entrant dans Android a diminu, tout comme le nombre de vulnrabilits en matire de scurit de la mmoire. […] 2022 a t la premire anne o les vulnrabilits lies la scurit de la mmoire n’ont pas reprsent la majorit des vulnrabilits d’Android. Bien que la corrlation ne signifie pas ncessairement la causalit, […] le changement est un cart majeur par rapport aux tendances de l’ensemble de l’industrie numres ci-dessus qui ont persist pendant plus d’une dcennie« .
Autre exemple, Cloudflare indique que son proxy HTTP Rust est plus performant que NGINX et qu’il a « servi quelques centaines de milliers de milliards de requtes et [n’a] encore jamais connu de panne due notre code de service« .
En appliquant un sous-ensemble de mcanismes prventifs de scurit de la mmoire un langage non sr tel que le C++, nous pouvons partiellement prvenir des classes de problmes de scurit de la mmoire. Par exemple :
- Un RFC de renforcement des tampons peut liminer un sous-ensemble de problmes de scurit spatiale en C++.
- De mme, un RFC sur la scurit des limites peut liminer un sous-ensemble de problmes de scurit spatiale en C.
- Les annotations de dure de vie en C++ peuvent liminer un sous-ensemble de problmes de scurit temporelle.
Attnuation des risques d’exploitation
Les mesures d’attnuation compliquent l’exploitation des vulnrabilits de la scurit de la mmoire, plutt que de corriger la cause premire de ces vulnrabilits. Par exemple, les mesures d’attnuation comprennent la mise en bac sable des bibliothques non sres, l’intgrit du flux de contrle et la prvention de l’excution des donnes.
Alors que les abstractions sres empchent la corruption de la mmoire, refusant aux attaquants les primitives d’exploitation, les mesures d’attnuation des exploits supposent que la mmoire peut tre corrompue. Les mesures d’attnuation des risques visent empcher les attaquants de passer de certaines primitives d’exploitation l’excution de code sans restriction.
Les attaquants contournent rgulirement ces mesures d’attnuation, ce qui soulve la question de leur valeur en termes de scurit. Pour tre utiles, les mesures d’attnuation devraient obliger les attaquants enchaner des vulnrabilits supplmentaires ou inventer une nouvelle technique de contournement. Au fil du temps, les techniques de contournement deviennent plus prcieuses pour les attaquants que n’importe quelle vulnrabilit isole. L’avantage pour la scurit d’une
d’une attnuation bien conue rside dans le fait que les techniques de contournement devraient tre beaucoup plus rares que les vulnrabilits.
Les mesures d’attnuation des exploits sont rarement gratuites ; elles ont tendance entraner des frais gnraux d’excution qui ne reprsentent gnralement qu’un faible pourcentage un chiffre.
Elles offrent un compromis entre scurit et performance, que nous pouvons ajuster en fonction des besoins de chaque charge de travail. Les frais gnraux d’excution peuvent tre rduits en construisant des mesures d’attnuation directement dans le silicium, comme cela a t fait pour l’authentification des pointeurs, la pile d’appels fictifs, les plateformes d’atterrissage et les cls de protection. En raison des frais gnraux et des cots d’opportunit des caractristiques matrielles, les considrations relatives l’adoption de ces techniques et l’investissement dans celles-ci sont nuances.
D’aprs notre exprience, le sandboxing est un moyen efficace d’attnuer les vulnrabilits lies la scurit de la mmoire et il est couramment utilis chez Google pour isoler les bibliothques fragiles ayant un historique de vulnrabilits. Toutefois, l’adoption du sandboxing se heurte plusieurs obstacles :
- Le sandboxing peut entraner des frais gnraux importants en termes de latence et de bande passante, ainsi que des cots lis au remaniement du code. Cela ncessite parfois la rutilisation des instances de sandbox entre les requtes, ce qui affaiblit les mesures d’attnuation.
- La cration d’une politique de sandbox suffisamment restrictive pour constituer une mesure d’attnuation efficace peut s’avrer difficile pour les dveloppeurs, en particulier lorsque les politiques de sandbox sont exprimes un faible niveau d’abstraction, comme les filtres d’appels systme.
- Le sandboxing peut entraner des risques de fiabilit, lorsque des chemins de code inhabituels (mais bnins) sont exercs en production et dclenchent des violations de la politique de sandboxing.
Dans l’ensemble, l’attnuation des exploits est un outil essentiel pour amliorer la scurit d’une vaste base de code C++ prexistante et profitera galement l’utilisation rsiduelle de constructions non sres dans des langages mmoire sre.
Dtection des bogues lis la scurit de la mmoire
L’analyse statique et le fuzzing sont des outils efficaces pour dtecter les bogues de scurit de la mmoire. Ils rduisent le volume de bogues de scurit de la mmoire dans notre base de code au fur et mesure que les dveloppeurs corrigent les problmes dtects.
Cependant, d’aprs notre exprience, la recherche de bogues ne permet pas elle seule d’atteindre un niveau d’assurance acceptable pour les langages mmoire non scurise. titre d’exemple, le rcent zero-day de haute svrit de webp (CVE-2023-4863) a affect un code largement explor. La vulnrabilit n’a pas t dtecte malgr une couverture leve (97,55 % dans le fichier concern). Dans la pratique, de nombreux bogues lis la scurit de la mmoire ne sont pas dtects, comme le montre le flux constant de vulnrabilits lies la scurit de la mmoire dans un code bien test qui n’est pas sr pour la mmoire.
En outre, le fait de trouver des bogues n’amliore pas en soi la scurit. Les bogues doivent tre corrigs et les correctifs dploys. Certains lments suggrent que les capacits de dtection des bogues dpassent les capacits de correction des bogues. Par exemple, syzkaller, notre fuzzer de noyau, a trouv plus de 5 000 bogues dans le noyau Linux en amont, de sorte qu’ tout moment, il y a des centaines de bogues ouverts (dont une grande partie est probablement lie la scurit), un nombre qui augmente rgulirement depuis 2017.
Nous pensons nanmoins que la recherche de bogues est une partie essentielle de la lutte contre l’inscurit de la mmoire. Les techniques de recherche de bogues qui exercent une pression moindre sur la capacit de correction des bogues sont particulirement prcieuses :
- » Shifting-left « , comme le fuzzing en presubmit, rduit le taux de nouveaux bugs expdis en production. Les bogues dtects plus tt dans le cycle de dveloppement des logiciels (SDLC) sont moins coteux corriger, ce qui augmente notre capacit de correction des bogues.
- Les techniques de recherche de bogues, comme l’analyse statique, peuvent galement suggrer des corrections, qui peuvent tre fournies par l’intermdiaire de l’IDE ou de demandes d’extraction, ou appliques automatiquement pour modifier le code existant de manire proactive.
- Les outils de recherche de bogues tels que les assainisseurs, qui identifient les causes profondes et gnrent des rapports de bogues exploitables, aident les dveloppeurs rsoudre les problmes plus rapidement, ce qui augmente galement notre capacit de correction des bogues.
En outre, les outils de recherche de bogues trouvent des classes de bogues au-del de la scurit de la mmoire, ce qui largit l’impact de l’investissement dans ces outils. Ils peuvent trouver des problmes de fiabilit, de correction et d’autres problmes de scurit, par exemple :
- Le fuzzing bas sur les proprits dtecte les entres qui violent les invariants au niveau de l’application, tels que les proprits de correction encodes par les dveloppeurs. Par exemple, cryptofuzz a trouv plus de 150 bogues dans les bibliothques de cryptographie.
- Le fuzzing dtecte les bogues lis l’utilisation des ressources (par exemple, les rcursions infinies) et les pannes simples qui affectent la disponibilit. En particulier, la dtection des erreurs d’excution (par exemple, la vrification des limites) transforme les vulnrabilits de scurit de la mmoire en erreurs d’excution, qui restent un problme de fiabilit et de dni de service.
- Les progrs dans la dtection des vulnrabilits au-del de la scurit de la mmoire sont prometteurs.
Plonge en profondeur : Safe Coding appliqu la scurit de la mmoire
Google a dvelopp Safe Coding, une approche volutive visant rduire considrablement l’incidence des classes communes de vulnrabilits et obtenir un degr lev d’assurance quant l’absence de vulnrabilits.
Au cours de la dernire dcennie, nous avons appliqu cette approche avec beaucoup de succs l’chelle de Google, principalement pour ce que l’on appelle les vulnrabilits d’injection, y compris l’injection SQL et XSS. Bien qu’ un niveau technique trs diffrent des bogues de scurit de la mmoire, il existe des parallles pertinents :
- Comme les bogues de scurit de la mmoire, les bogues d’injection se produisent lorsqu’un dveloppeur utilise une construction de code potentiellement dangereuse et ne parvient pas garantir sa condition pralable de scurit.
- Le respect de la condition pralable dpend d’un raisonnement complexe sur les invariants de flux de donnes de l’ensemble du programme ou de l’ensemble du systme. Par exemple, la construction potentiellement dangereuse se produit dans le code ct navigateur, mais les donnes peuvent arriver via plusieurs microservices et un magasin de donnes ct serveur. Il est donc difficile de savoir d’o viennent rellement les donnes et si la validation ncessaire a t correctement applique en cours de route.
- Les constructions potentiellement dangereuses sont courantes dans les bases de code typiques.
Comme pour les bogues lis la scurit de la mmoire, « plusieurs milliers de bogues potentiels » ont conduit des centaines de bogues rels. Les approches ractives (examen du code, tests en stylo, fuzzing) ont t largement infructueuses.
Pour rsoudre ce problme grande chelle et avec une grande assurance, Google a appliqu le Safe Coding au domaine des vulnrabilits par injection. Cette dmarche a t couronne de succs et a permis de rduire considrablement, voire d’liminer compltement, les vulnrabilits XSS. Par exemple, avant 2012, les frontaux web comme GMail avaient souvent quelques douzaines de XSS par an ; aprs avoir remani le code pour se conformer aux exigences du Safe Coding, les taux de dfauts sont tombs prs de zro. L’interface web de Google Photos (qui a t dveloppe depuis le dbut sur un cadre d’application web qui applique compltement le Safe Coding) n’a eu aucune vulnrabilit XSS signale dans toute son histoire. Dans les sections suivantes, nous examinons plus en dtail comment l’approche Safe Coding s’applique la scurit de la mmoire, et nous tablissons des parallles avec son utilisation russie pour liminer des classes de vulnrabilits dans le domaine de la scurit du web.
Des abstractions sres
D’aprs notre exprience, la cl de l’limination des classes de bogues consiste identifier les constructions de programmation (API ou constructions natives du langage) qui causent ces bogues, puis liminer l’utilisation de ces constructions dans la pratique courante de la programmation. Cela ncessite l’introduction de constructions sres avec des fonctionnalits quivalentes, qui prennent souvent la forme d’abstractions sres autour des constructions dangereuses sous-jacentes.
Par exemple, les XSS sont causs par l’utilisation d’API de plates-formes Web qui ne sont pas sres appeler avec des chanes de caractres partiellement contrles par l’attaquant. Pour liminer l’utilisation de ces API sujettes aux XSS dans notre code, nous avons introduit un certain nombre d’abstractions sres quivalentes, conues pour garantir collectivement que les conditions pralables de scurit sont remplies lorsque les constructions non sres sous-jacentes (API) sont invoques. Il s’agit notamment d’enveloppes d’API sres, de types de vocabulaire avec des contrats de scurit et de systmes de cration de modles HTML srs.
Les abstractions sres visant garantir les conditions pralables de scurit de la mmoire peuvent prendre la forme d’API enveloppantes dans un langage existant (par exemple, les pointeurs intelligents utiliser la place des pointeurs bruts, y compris MiraclePtr qui protge 50 % des problmes d’utilisation aprs libration contre l’exploitation dans le processus du navigateur de Chrome), ou de constructions troitement lies la smantique du langage (par exemple, le ramassage des miettes dans Go/Java ; les dures de vie vrifies statiquement dans Rust).
La conception de constructions sres doit tenir compte d’un compromis trois voies entre les cots d’excution (CPU, mmoire, taille binaire, etc.), les cots de dveloppement (friction du dveloppeur, charge cognitive, temps de construction) et l’expressivit. Par exemple, le ramassage des miettes fournit une solution gnrale pour la scurit temporelle, mais peut entraner une variabilit problmatique des performances. Les dures de vie de Rust combines avec le vrificateur d’emprunts assurent la scurit entirement la compilation (sans cot d’excution) pour de grandes classes de code ; cependant, le programmeur doit faire plus d’efforts en amont pour dmontrer que le code est en fait sr. Il en va de mme pour le typage statique, qui ncessite un effort initial plus important que le typage dynamique, mais qui permet d’viter un grand nombre d’erreurs de type au moment de la compilation.
Parfois, les dveloppeurs doivent choisir d’autres idiomes pour viter les surcharges d’excution. Par exemple, la surcharge lie la vrification des limites lors de la traverse indexe d’un vecteur peut tre vite en utilisant une boucle « range-for ».
Pour russir rduire l’incidence des bogues, une collection d’abstractions sres doit tre suffisamment expressive pour permettre la plupart des codes d’tre crits sans avoir recours des constructions non sres (ni un code alambiqu et non idiomatique qui est techniquement sr, mais difficile comprendre et maintenir).
Sr par dfaut, peu sr par exception
D’aprs notre exprience, il ne suffit pas de mettre la disposition des dveloppeurs des abstractions sres sur une base facultative (par exemple, suggres par un guide de style), car trop de constructions non sres, et donc trop de risques de bogues, ont tendance subsister.
Au contraire, pour obtenir un degr lev d’assurance qu’une base de code est exempte de vulnrabilits, nous avons jug ncessaire d’adopter un modle dans lequel les constructions non sres ne sont utilises qu’ titre exceptionnel, par l’intermdiaire du
compilateur.
Ce modle se compose des lments cls suivants :
- Il est possible de dcider au moment de la construction si un programme (ou une partie d’un programme, par exemple un module) contient des constructions dangereuses.
- Un programme compos uniquement de code sr est garanti de maintenir les invariants de scurit au moment de l’excution.
- Les constructions non sres ne sont pas autorises moins qu’elles ne soient explicitement autorises/optes, c’est–dire que le code est sr par dfaut.
Dans nos travaux sur les vulnrabilits par injection, nous avons atteint la scurit grande chelle en limitant l’accs aux API non sres grce la visibilit au niveau du langage et au moment de la construction et, dans certains cas, grce des vrifications statiques personnalises.
Dans le contexte de la scurit de la mmoire, la scurit l’chelle exige que le langage interdise par dfaut l’utilisation de constructions non sres (par exemple, l’indexation non vrifie dans les tableaux/tampons). Les constructions non sres devraient provoquer une erreur la compilation, moins qu’une partie du code ne soit explicitement incluse dans le sous-ensemble non sr, comme nous le verrons dans la section suivante. Par exemple, Rust n’autorise les constructions non sres qu’ l’intrieur de blocs non srs clairement dlimits.
Solidit : Code non sr encapsul de manire sre
Comme indiqu ci-dessus, nous supposons que les abstractions sres disponibles sont suffisamment expressives pour permettre la plupart des codes d’tre crits en utilisant uniquement des constructions sres. Dans la pratique, cependant, nous nous attendons ce que la plupart des grands programmes ncessitent l’utilisation de constructions non sres dans certains cas. En outre, les abstractions sres elles-mmes seront souvent des API enveloppantes pour les constructions non sres sous-jacentes. Par exemple, l’implmentation d’abstractions sres autour de l’allocation/dsallocation de la mmoire du tas doit en fin de compte traiter la mmoire brute, par exemple mmap.
Lorsque les dveloppeurs introduisent (mme en petite quantit) du code non sr, il est important de le faire sans annuler les avantages d’avoir crit la majeure partie d’un programme en utilisant uniquement du code sr.
cette fin, les dveloppeurs doivent adhrer au principe suivant : les utilisations de constructions non sres doivent tre encapsules dans des API dont la scurit peut tre dmontre.
En d’autres termes, le code non sr doit tre encapsul derrire une API qui est saine pour tout code arbitraire (mais bien typ) appelant cette API. Il doit tre possible de dmontrer, et d’examiner/vrifier, que le module expose une surface d’API sre sans faire d’hypothse sur le code appelant (autre que son bon typage).
Par exemple, supposons que l’implmentation d’un type utilise une construction potentiellement dangereuse. Il incombe alors l’implmentation du type de s’assurer de manire indpendante que la prcondition de la construction non sre est respecte lorsqu’elle est invoque. L’implmentation ne doit pas faire d’hypothses sur le comportement de ses appelants (en dehors du fait qu’ils sont bien typs), par exemple que ses mthodes sont appeles dans un certain ordre.
Dans notre travail sur les vulnrabilits d’injection, ce principe est incorpor dans des directives pour l’utilisation de ce qu’on appelle les conversions non vrifies (qui reprsentent du code non sr dans notre discipline de type vocabulaire). Dans la communaut Rust, cette proprit est appele Soundness : un module avec des blocs unsafe est sound si un programme compos de ce module, combin avec un Rust arbitraire bien typ et sr, ne peut pas prsenter de comportement indfini.
Ce principe peut tre difficile ou impossible respecter dans certaines situations, comme lorsqu’un programme dans un langage sr (Rust ou Go) fait appel du code C++ non sr. La bibliothque non scurise peut tre enveloppe dans une abstraction « raisonnablement sre », mais il n’existe aucun moyen pratique de dmontrer que l’implmentation est rellement sre et ne prsente pas de bogue de scurit de la mmoire.
Examen du code non scuris par des experts
Le raisonnement sur le code non scuris est difficile et peut tre source d’erreurs, en particulier pour les non-experts :
- Raisonner sur la question de savoir si un module contenant des constructions non sres expose en fait une abstraction sre ncessite une expertise dans le domaine.
- Par exemple, dans le domaine de la scurit web, dcider si une conversion non vrifie dans le type de vocabulaire SafeHtml est sre ncessite une comprhension dtaille de la spcification HTML et des rgles d’chappement et d’assainissement des donnes applicables.
- Dcider si un code Rust avec unsafe est sain ncessite une comprhension profonde de la smantique Rust unsafe et des limites du comportement non dfini (un domaine de recherche actif).
- D’aprs notre exprience, les dveloppeurs qui se concentrent sur la rsolution d’un problme ne semblent pas apprcier l’importance d’encapsuler en toute scurit le code non scuris et n’essaient pas de concevoir une abstraction scurise. Un examen par des experts est ncessaire pour orienter ces dveloppeurs vers une encapsulation sre et pour les aider concevoir une abstraction sre approprie.
Dans le domaine de la scurit du web, nous avons jug ncessaire de rendre obligatoire l’examen par des experts des constructions non sres dans de nombreux cas, comme pour les nouvelles utilisations des conversions non vrifies. Sans examen obligatoire, nous avons observ un grand nombre d’utilisations inutiles/non fondes de constructions non sres, ce qui a dilu notre capacit raisonner sur la scurit l’chelle. Les exigences en matire d’examen obligatoire doivent tenir compte de l’impact sur les dveloppeurs et de la largeur de bande de l’quipe d’examen, et ne sont probablement appropries que si elles sont suffisamment rares.
Scurit de l’ensemble du programme et raisonnement compositionnel
En fin de compte, notre objectif est d’assurer une posture de scurit adquate pour l’ensemble d’un binaire.
Les binaires incluent gnralement un grand nombre de dpendances directes et transitives de bibliothques. Celles-ci sont gnralement maintenues par de nombreuses quipes diffrentes au sein de Google, ou mme l’extrieur dans le cas de codes tiers. Or, un bogue de scurit de la mmoire dans l’une des dpendances peut potentiellement entraner une vulnrabilit de la scurit du binaire dpendant.
Un langage sr, associ une discipline de dveloppement garantissant que le code dangereux est encapsul dans des abstractions saines et sres, peut nous permettre de raisonner de manire volutive sur la scurit de grands programmes :
- Les composants crits uniquement dans le sous-ensemble sr du langage sont par construction srs et exempts de violations de la scurit.
- Les composants qui contiennent des constructions dangereuses exposent des abstractions sres au reste du programme. Pour ces composants, l’examen par des experts fournit une assurance solide de leur solidit et du fait qu’ils ne causeront pas de violations de la scurit lorsqu’ils seront combins avec d’autres composants arbitraires.
Lorsque toutes les dpendances transitives appartiennent l’une de ces deux catgories, nous avons l’assurance que l’ensemble du programme est exempt de violations de la scurit. Il est important de noter que nous n’avons pas besoin de raisonner sur la faon dont chaque composant interagit avec tous les autres composants du programme ; au contraire, nous pouvons arriver cette conclusion en nous basant uniquement sur le raisonnement concernant chaque composant de faon isole.
Pour maintenir et garantir les assertions sur la scurit de l’ensemble du programme dans le temps, en particulier pour les binaires critiques en matire de scurit, nous avons besoin de mcanismes pour garantir les contraintes sur le « niveau de solidit » de toutes les dpendances transitives d’un binaire (c’est–dire pour savoir si elles consistent uniquement en du code sr ou si elles ont fait l’objet d’une rvision par des experts pour ce qui est de la solidit).
Dans la pratique, certaines dpendances transitives auront un niveau d’assurance plus faible quant leur solidit. Par exemple, une dpendance OSS d’un tiers peut utiliser des constructions non sres, mais n’est pas structure de manire exposer des abstractions sres proprement dlimites dont la solidit peut tre effectivement vrifie. Ou encore, une dpendance peut consister en un wrapper FFI dans un code hrit crit entirement dans un langage non sr, ce qui rend impossible une vrification de la solidit avec un degr d’assurance lev.
Les binaires critiques en matire de scurit peuvent vouloir exprimer des contraintes telles que « toutes les dpendances transitives sont soit exemptes de constructions non sres ou sont vrifies par des experts, avec les exceptions spcifiques suivantes« , les exceptions pouvant faire l’objet d’un examen plus approfondi (par exemple, une couverture fuzz tendue). Cela permet aux propritaires d’un binaire critique de maintenir un niveau bien compris et acceptable de risque rsiduel d’inscurit.
Garanties de scurit de la mmoire et compromis
L’application des principes de codage sr la scurit de la mmoire d’un langage de programmation et de son cosystme (bibliothques, outils d’analyse de programmes) implique des compromis, principalement entre les cots encourus au moment du dveloppement (par exemple, la charge cognitive impose aux dveloppeurs) et au moment du dploiement et de l’excution.
La prsente section donne un aperu des approches possibles des sous-classes de scurit de la mmoire et des compromis qui y sont associs.
Scurit spatiale
La scurit spatiale est relativement simple intgrer dans l’cosystme d’un langage et d’une bibliothque. Le compilateur et les types de conteneurs tels que les chanes et les vecteurs doivent s’assurer que tous les accs sont vrifis pour tre dans les limites. Les vrifications peuvent tre supprimes si elles s’avrent inutiles sur la base d’une analyse statique ou d’invariants de type. En rgle gnrale, cela signifie que les implmentations de types ont besoin de mtadonnes (taille/longueur) pour effectuer les vrifications.
Les approches comprennent :
- Les contrles de limites incorpors dans les API (par exemple, std::vector::operator[] avec des assertions de scurit).
- Les contrles de limites insrs par le compilateur, ventuellement aids par des annotations.
- Support matriel tel que les capacits CHERI avec vrification des limites.
Les langages srs tels que Rust, Go, Java, etc., et leurs bibliothques standard, imposent des contrles de limites pour tous les accs indexs. Ils ne sont supprims que s’il est prouv qu’ils sont redondants.
Il semble plausible, mais cela n’a pas t dmontr pour les bases de code grande chelle comme la monorepo de Google ou le noyau Linux, qu’un langage non sr comme le C ou le C++ puisse tre sous-ensemble pour atteindre la scurit spatiale.
Les vrifications de limites entranent un surcot d’excution faible mais invitable. Il appartient au dveloppeur de structurer le code de telle sorte que les vrifications de limites puissent tre vites lorsqu’elles s’accumuleraient autrement pour atteindre un surcot significatif.
Scurit des types et de l’initialisation
Rendre un langage sr du point de vue du type et de l’initialisation peut inclure les lments suivants :
- Interdire les constructions de code non sres du point de vue du type, telles que les unions (non marques) et reinterpret_cast.
- L’instrumentation du compilateur qui initialise les valeurs sur la pile (sauf si le compilateur peut prouver que la valeur ne sera pas lue avant une criture explicite ultrieure).
- Les implmentations de types de conteneurs qui garantissent que les lments (accessibles) sont initialiss.
Dans les langages typage statique, la scurit des types peut tre assure principalement au moment de la compilation, sans surcharge au moment de l’excution. Dans les langages typage statique, la scurit des types peut tre assure principalement la compilation, sans surcharge l’excution. Cependant, il existe un potentiel de surcharge l’excution dans certains scnarios :
- Les unions doivent inclure un discriminateur au moment de l’excution et tre reprsentes comme une construction de niveau suprieur sre (par exemple, les types de somme). Dans certains cas, la surcharge de mmoire qui en rsulte peut tre optimise, par exemple Option<NonZeroUsize> en Rust.
- Il peut y avoir des initialisations superflues de valeurs qui ne sont jamais lues, mais d’une manire que le compilateur ne peut pas prouver. Dans les cas o la surcharge est significative (par exemple, l’initialisation par dfaut de grands vecteurs), il est de la responsabilit du programmeur de structurer le code de telle sorte que les initialisations superflues puissent tre vites, par exemple par l’utilisation de reserve and push ou de types optionnels.
Scurit temporelle
La scurit temporelle est fondamentalement un problme beaucoup plus difficile que la scurit spatiale : Pour la scurit spatiale, il est possible d’instrumenter un programme de manire relativement peu coteuse de sorte que la prcondition de scurit puisse tre vrifie par un contrle d’excution peu coteux (contrle des limites). Dans les cas les plus courants, il est facile de structurer le code de manire ce que les vrifications des limites puissent tre vites (par exemple, en utilisant des itrateurs).
En revanche, il n’existe pas de moyen direct d’tablir la condition pralable de scurit pour la scurit temporelle des objets allous au tas.
Les pointeurs et les allocations vers lesquelles ils pointent, qui leur tour peuvent contenir des pointeurs, induisent un graphe dirig (ventuellement cyclique). Le graphe induit par la squence d’allocations et de dsallocations d’un programme arbitraire peut devenir arbitrairement complexe. Dans le cas gnral, il est impossible de dduire les proprits de ce graphe partir d’une analyse statique du code du programme.
Lorsqu’une allocation est libre, tout ce qui est disponible est le nud du graphe correspondant cette allocation. Il n’existe aucun moyen efficace a priori (en temps constant) de dterminer s’il existe encore une autre arte entrante (c’est–dire un autre pointeur encore accessible dans cette allocation). La dsallocation d’une allocation pour laquelle il existe encore des pointeurs entrants invalide implicitement ces pointeurs (les transforme en pointeurs « pendants »). Un drfrencement futur d’un tel pointeur invalide entranerait un comportement indfini et un bogue de type « use after free ».
Le graphe tant orient, il n’existe pas non plus de moyen efficace ( temps constant, ou mme linaire dans le nombre de pointeurs lis) de trouver tous les pointeurs encore accessibles dans l’allocation sur le point d’tre supprime. S’il tait disponible, ce moyen pourrait tre utilis pour invalider explicitement ces pointeurs ou pour diffrer la dsallocation jusqu’ ce que tous les pointeurs entrants soient supprims du graphe.
Par consquent, chaque fois qu’un pointeur est drfrenc, il n’existe aucun moyen efficace de dterminer si cette opration constitue un comportement indfini parce que la destination du pointeur a dj t libre.
Il existe gnralement trois faons d’obtenir des garanties rigoureuses de scurit temporelle :
- Garantir, par une vrification la compilation, qu’un pointeur/rfrence ne peut pas survivre l’allocation vers laquelle il pointe. Par exemple, Rust met en uvre cette approche par le biais du vrificateur d’emprunt et de la rgle d’exclusivit. Ce mode prend en charge la scurit temporelle des objets du tas et de la pile.
- Avec le support de l’excution, s’assurer que les allocations ne sont dsalloues que lorsqu’il n’y a plus de pointeurs valides vers elles.
- Avec le support de l’excution, s’assurer que les pointeurs deviennent invalides lorsque l’allocation vers laquelle ils pointent est dsalloue, et lever une erreur si un tel pointeur invalide est drfrenc plus tard.
Plusieurs variantes des points 2 et 3 ont t conues et entranent un cot d’excution non ngligeable. Le comptage de rfrences et le ramassage des ordures offrent tous deux la scurit souhaite mais peuvent tre coteux. La mise en quarantaine des dsallocations est une mesure d’attnuation efficace, mais elle ne garantit pas totalement la scurit et entrane nanmoins des frais gnraux. Le marquage de la mmoire repose sur du matriel spcialis et ne fournit qu’une attnuation probabiliste ( moins d’tre combin avec MarkUs).
Dans tous les cas, pour la scurit temporelle, il n’y a pas de repas bon march (et encore moins gratuit). Soit les dveloppeurs structurent et annotent le code de manire ce qu’un vrificateur la compilation (par exemple, le vrificateur d’emprunts de Rust) puisse prouver statiquement la scurit temporelle, soit nous payons le surcot d’excution pour atteindre la scurit ou mme attnuer partiellement ces bogues.
Malheureusement, les problmes de scurit temporelle restent une grande partie des problmes de scurit de la mmoire, comme l’indiquent divers rapports :
- Chrome : 51% des vulnrabilits de scurit de la mmoire leves/critiques
- Android : 20 % des vulnrabilits de scurit de la mmoire leves/critiques en 2022
- Project Zero : 33 % des exploits de scurit de la mmoire dans la nature.
- Microsoft : 32% des CVE de scurit de la mmoire [5]
- GWP-ASan : trouve 4 fois plus d’UAF que d’OOB dans plusieurs cosystmes.
Techniques d’excution et compromis
Un large ventail de techniques d’instrumentation du temps d’excution a t explor pour traiter la scurit temporelle, mais elles s’accompagnent toutes de compromis difficiles. Elles doivent tenir compte de la concurrence lorsqu’elles sont utilises dans des programmes multithreads et, dans de nombreux cas, elles ne font qu’attnuer ces bogues sans garantir la scurit.
- Le comptage de rfrences, soit pour fournir la dure de vie correcte, soit pour dtecter et prvenir les dures de vie incorrectes. Parmi les variantes de cette technique, on peut citer std:shared_ptr, Rc/Arc de Rust, le comptage automatique des rfrences dans Swift ou Objective-C, et l’exprience de Chrome avec DanglingPointerDetector . L’exclusivit force peut tre utilise avec le comptage de rfrences pour rduire son cot, mais pas pour l’liminer.
- Piles de ramasse-miettes. L’exclusivit force peut galement tre combine avec le GC pour rduire l’encombrement.
- La mise en quarantaine des dsallocations, base sur le comptage de rfrences et l’empoisonnement des allocations, comme le propose BackupRefPtr de Chrome, ou combine la traverse et l’invalidation des pointeurs vers les dsallocations mises en quarantaine, comme le propose MarkUs. Ces approches vitent d’interfrer avec la synchronisation du destructeur, mais peuvent ne fournir qu’une attnuation partielle plutt qu’une vritable scurit temporelle dans certains cas. Elles peuvent tre considres comme des variantes du comptage de rfrences et du ramasse-miettes qui n’interfrent pas avec la synchronisation du destructeur tout en empchant la rallocation derrire des pointeurs pendants, mais qui introduisent des valeurs toxiques (et le comportement indfini qui en rsulte) dans le systme d’excution si l’on y accde aprs qu’ils ont t librs.
- Le marquage de la mmoire tiquette les pointeurs et les rgions de mmoire alloues avec l’une des quelques tiquettes (couleurs). Lorsque la mmoire est dsalloue et ralloue, elle est recolore selon une stratgie dfinie. Cela invalide implicitement les pointeurs restants qui auraient encore l' »ancienne » couleur. Dans la pratique, l’ensemble des tiquettes/couleurs est restreint (par exemple, 16 dans le cas de l’ARM MTE). Ainsi, dans la plupart des cas, il fournit une attnuation probabiliste plutt qu’une vritable scurit, car il y a une chance non ngligeable (par exemple, 6,25 %) que les pointeurs pendants ne soient pas marqus comme invalides parce qu’ils ont t recolors de manire alatoire avec la mme couleur. Le MTE entrane galement des frais gnraux d’excution importants. Le marquage de la mmoire acclre galement les approches MarkUs et *Scan, en fournissant une scurit temporelle forte.
Aperu de la scurit du langage de production
Cette section donne un bref aperu des proprits de scurit de la mmoire des langages de production actuels et futurs de Google, ainsi que de certains langages qui pourraient jouer un rle dans un avenir plus lointain.
Langages JVM (Java, Kotlin)
Dans Java et Kotlin, le code non scuris en mmoire est clairement dlimit et limit l’utilisation de l’interface native Java (JNI). Les bibliothques standard du JDK s’appuient sur un grand nombre de mthodes natives pour invoquer des primitives systme de bas niveau et pour utiliser des bibliothques natives, par exemple pour l’analyse d’images. Ces dernires ont t affectes par des vulnrabilits en matire de scurit de la mmoire (par exemple CESA-2006-004 , Sun Alert 1020226.1 ).
Java est un langage scurit de type. JVM garantit la scurit spatiale grce des contrles de limites d’excution et la scurit temporelle grce un tas de donnes collect par le ramasse-miettes.
Java n’tend pas les principes de codage sr la concurrence : un programme bien typ peut avoir des courses de donnes. Cependant, la JVM garantit que les courses de donnes ne peuvent pas violer la scurit de la mmoire. Par exemple, une course aux donnes peut entraner la violation d’invariants de niveau suprieur et le dclenchement d’exceptions, mais ne peut pas entraner de corruption de la mmoire.
Go
En Go, le code non sr pour la mmoire est clairement dlimit et confin au code utilisant le paquetage unsafe ( l’exception du code non sr pour la mmoire rsultant des courses de donnes, voir ci-dessous).
Go est un langage scurit de type. Le compilateur Go s’assure que toutes les valeurs sont initialises par dfaut avec la valeur zro de leur type, assure la scurit spatiale via des vrifications de limites d’excution, et la scurit temporelle via un tas de donnes (garbage-collected heap). l’exception du paquetage unsafe, il n’y a pas de possibilit de crer des pointeurs de manire non scurise.
Go n’tend pas les principes de codage sr la concurrence : Un programme Go bien typ peut avoir des courses aux donnes. De plus, les courses de donnes peuvent conduire la violation des invariants de scurit de la mmoire.
Rust
En Rust, le code non sr pour la mmoire est clairement dlimit et confin dans des blocs non srs. Rust est un langage scurit de type. Safe Rust impose l’initialisation de toutes les valeurs et garantit la scurit spatiale en ajoutant des contrles de limites lorsque cela est ncessaire. Le drfrencement d’un pointeur brut n’est pas autoris en Safe Rust.
Rust est le seul langage mature, prt pour la production, qui assure la scurit temporelle sans mcanismes d’excution tels que le garbage collection ou le refcounting universellement appliqu, pour de grandes classes de code. Rust assure la scurit temporelle grce des contrles compils sur la dure de vie des variables et des rfrences.
Les contraintes imposes par le vrificateur d’emprunts empchent la mise en uvre de certaines structures, en particulier celles qui impliquent des graphes de rfrence cycliques. La bibliothque standard Rust comprend des API qui permettent d’implmenter de telles structures en toute scurit, mais avec un surcot d’excution (bas sur le comptage des rfrences).
En plus de la scurit de la mmoire, le sous-ensemble sr de Rust garantit galement la scurit de la course des donnes ( » Fearless Concurrency « ). Incidemment, la scurit de la course des donnes permet Rust d’viter les surcharges inutiles lors de l’utilisation de mcanismes de scurit temporelle l’excution : Rc et Arc implmentent tous deux des pointeurs compts par rfrence. Cependant, le type de Rc l’empche d’tre partag entre les threads, de sorte que Rc peut utiliser en toute scurit un compteur non atomique moins coteux.
Carbon
Carbon est un langage exprimental qui succde C++ et dont l’objectif explicite est de faciliter la migration grande chelle partir des bases de code C++ existantes. En 2023, les dtails de la stratgie de scurit de Carbon sont encore en suspens. Carbon 0.2 prvoit d’introduire un sous-ensemble sr qui fournit des garanties rigoureuses en matire de scurit de la mmoire. Cependant, il devra conserver une stratgie de migration efficace pour le code C++ non scuris existant. La gestion des mlanges de code Carbon non sr et sr ncessitera des garde-fous similaires ceux utiliss pour les mlanges de C++ et d’un langage sr comme Rust.
Bien que nous nous attendions ce que le code Carbon nouvellement crit soit dans son sous-ensemble memorysafe, le code Carbon issu d’une migration partir du C++ existant s’appuiera probablement sur des constructions Carbon non sres. Nous pensons qu’une migration ultrieure automatise et grande chelle de Carbon non sr vers Carbon sr sera difficile et souvent irralisable. L’attnuation du risque de scurit de la mmoire dans le code non sr restant sera base sur le durcissement via des modes de construction (similaires notre traitement du code C++ hrit). Le mode de construction renforc activera des mcanismes d’excution qui tenteront d’empcher l’exploitation des bogues de scurit de la mmoire.
Un C++ plus sr
Compte tenu du volume important de C++ prexistant, nous reconnaissons qu’une transition vers des langages mmoire scurise pourrait prendre des dcennies, au cours desquelles nous dvelopperons et dploierons du code constitu d’un mlange de langages srs et non srs. Par consquent, nous pensons qu’il est ncessaire d’amliorer la scurit du C++ (ou du langage qui lui succdera, le cas chant).
Bien que la dfinition d’un sous-ensemble de C++ rigoureusement sr pour la mmoire qui soit suffisamment ergonomique et facile maintenir reste une question de recherche ouverte, il pourrait en principe tre possible de dfinir un sous-ensemble de C++ qui offre des garanties raisonnablement fortes en matire de scurit de la mmoire. Les efforts en matire de scurit du C++ devraient adopter une approche itrative et axe sur les donnes pour dfinir un sous-ensemble C++ plus sr : identifier les principaux risques en matire de scurit et de fiabilit, et dployer des garanties et des mesures d’attnuation ayant l’impact et le retour sur investissement les plus levs.
Un tremplin pour une transition progressive
Un sous-ensemble C++ plus sr constituerait un tremplin vers une transition vers des langages mmoire sre. Par exemple, l’application d’une initialisation dfinie ou l’interdiction de l’arithmtique des pointeurs dans un code C++ simplifiera une ventuelle migration vers Rust ou Safe Carbon. De mme, l’ajout de dures de vie au C++ amliorera l’interoprabilit avec Rust. Par consquent, en plus de cibler les principaux risques, les investissements dans la scurit du C++ devraient donner la priorit aux amliorations qui acclreront et simplifieront l’adoption progressive de langages srs pour la mmoire.
En particulier, une interoprabilit sre, performante et ergonomique est un ingrdient cl pour une transition progressive vers la scurit de la mmoire. Android et Apple suivent tous deux une stratgie de transition centre sur l’interoprabilit, avec Rust et Swift respectivement.
Pour ce faire, nous avons besoin d’un meilleur outil d’interoprabilit et d’une meilleure prise en charge des bases de code en langage mixte dans l’outil de construction existant. En particulier, l’outil d’interoprabilit de qualit production existant pour C++/Rust suppose une surface d’API troite. Cela s’est avr suffisant pour certains cosystmes, comme Android, mais d’autres cosystmes ont des exigences supplmentaires. Une interoprabilit plus fidle permet une adoption progressive dans d’autres cosystmes, comme c’est dj le cas pour Swift et comme l’explore Crubit pour Rust. Pour Rust, il reste des questions ouvertes, comme la manire de garantir que le code C++ ne viole pas la rgle d’exclusivit du code Rust, ce qui crerait de nouvelles formes de comportements non dfinis.
En remplaant les composants un par un, les amliorations en matire de scurit sont apportes en continu et non pas en une seule fois la fin d’une longue rcriture. Il est noter qu’une rcriture complte peut ventuellement tre ralise avec cette stratgie incrmentale, mais sans les risques typiquement associs aux rcritures compltes de grands systmes. En effet, pendant cette priode, le systme reste une base de code unique, teste en permanence et livrable.
MTE
Memory Tagging est une fonction du processeur, disponible dans ARM v8.5a, qui permet de marquer les rgions de mmoire et les pointeurs avec l’une des 16 tiquettes. Lorsqu’elle est active, le drfrencement d’un pointeur avec une tiquette mal assortie provoque une erreur.
De multiples fonctions de scurit peuvent tre construites au-dessus de MTE, par exemple :
- Dtection de l’utilisation aprs la libration et du dpassement des limites. Lorsque la mmoire est dsalloue (ou ralloue), elle est alatoirement rtiquete. Cela invalide implicitement les pointeurs restants, qui auraient toujours l' »ancienne » tiquette. Dans la pratique, l’ensemble des tiquettes est petit (16). Il s’agit donc d’une attnuation probabiliste plutt que d’une vritable scurit, car il existe une probabilit non ngligeable (6,25 %) que les pointeurs pendants ne soient pas marqus comme invalides (parce qu’ils ont t rtiquets de manire alatoire avec la mme tiquette).
- De mme, cette mthode permet de dtecter les bogues hors limites de manire probabiliste.
- Il peut dtecter de manire dterministe les dbordements linaires entre allocations, en supposant que l’allocateur garantisse que des allocations conscutives ne partagent jamais la mme tiquette.
- Il peut tre possible de construire une prvention dterministe de l’utilisation sans limite du tas en plus de l’MTE en utilisant une analyse supplmentaire de type GC comme MarkUs.
- Dtection chantillonne de l’utilisation aprs coup et du dpassement des limites. La mme chose que ci-dessus, mais seulement sur une fraction des allocations afin de rduire suffisamment les frais gnraux d’excution pour un dploiement grande chelle.
Avec la MTE chantillonne, les exploits devraient russir aprs quelques tentatives : les attaques ne seront pas arrtes. Cependant, les tentatives rates gnrent du bruit (c’est–dire des pannes de MTE) que nous pouvons inspecter.
En utilisant ces deux techniques, la MTE peut permettre de :
- Les bogues sont trouvs plus tt dans le cycle de dveloppement durable. La MTE non chantillonne devrait tre suffisamment bon march pour tre dploy dans la prsoumission et les canaris.
- Plus de bogues sont dtects en production. La MTE chantillonn permet un taux d’chantillonnage suprieur de 3 ordres de grandeur par rapport au GWP-ASan pour le mme cot.
- Des rapports de crash exploitables. La MTE synchrone signale l’endroit o le bogue s’est produit, au lieu de provoquer un plantage d aux effets secondaires d’un bogue dont l’origine est difficile dterminer. En outre, la MTE chantillonne peut tre combine avec l’instrumentation du tas pour fournir des rapports de bogues avec une fidlit similaire celle de GWP-ASan.
- Amlioration de la fiabilit et de la scurit au fur et mesure que ces bogues sont corrigs.
- Une diminution du retour sur investissement des exploits pour les attaquants. Les attaquants doivent soit trouver des vulnrabilits supplmentaires pour contourner de manire dterministe la MTE, soit risquer d’tre dtects.
- La vitesse de raction des dfenseurs dpendra de leur capacit distinguer les tentatives d’exploitation des autres violations de la MTE. Les tentatives d’exploitation peuvent se dissimuler dans le bruit des violations de la MTE qui se produisent organiquement.
- Mme s’il n’est pas possible de distinguer les tentatives d’exploitation des violations organiques du MTE, la MTE devrait rduire la fentre d’exploitation, c’est–dire la frquence et la dure pendant lesquelles un attaquant peut rutiliser un exploit donn. Plus les violations de l’ETM sont corriges rapidement, plus la fentre d’exploitation est courte, ce qui rduit le retour sur investissement des exploits.
- Cela souligne l’importance de corriger rapidement les violations de l’ETM pour atteindre le potentiel de scurit de l’ETM. Pour y parvenir sans submerger les dveloppeurs, l’ETM doit tre associ un travail proactif visant rduire le volume de bogues.
La MTE non chantillonne peut galement tre dploy pour attnuer les exploits, en protgeant de manire dterministe contre 10 15 % des bogues lis la scurit de la mmoire (en supposant qu’il n’y ait pas d’analyse de type GC). Cependant, en raison de la mmoire non triviale et de la surcharge d’excution, nous nous attendons ce que les dploiements en production se fassent principalement dans des charges de travail faible encombrement, mais critiques pour la scurit.
Malgr ses limites, nous pensons que la MTE est une voie prometteuse pour rduire le volume de bogues de scurit temporelle dans les grandes bases de code C++ existantes. Il n’existe actuellement aucune alternative pour la scurit temporelle du C++ qui puisse tre dploye de manire raliste grande chelle.
CHERI
CHERI est un projet de recherche intriguant qui a le potentiel de fournir des garanties rigoureuses de scurit de la mmoire pour le code C++ existant (et peut-tre Carbon en mode renforc), avec un effort de portage minimal. Les garanties de scurit temporelle de CHERI reposent sur la mise en quarantaine de la mmoire dsalloue et la rvocation par balayage, et la question de savoir si la surcharge d’excution sera acceptable pour les charges de travail de production reste ouverte.
Au-del de la scurit de la mmoire, les capacits de CHERI permettent galement d’autres attnuations de scurit intressantes, telles que le sandboxing grain fin.
Conclusion
Cinquante ans plus tard, les bogues de scurit de la mmoire restent parmi les faiblesses logicielles les plus tenaces et les plus dangereuses. tant l’une des principales causes de vulnrabilit, ils continuent d’entraner des risques importants pour la scurit. Il est de plus en plus vident que la scurit de la mmoire est une proprit ncessaire des logiciels srs. Par consquent, nous nous attendons ce que l’industrie acclre la transition vers la scurit de la mmoire au cours de la prochaine dcennie. Nous sommes encourags par les progrs dj raliss par Google et d’autres grands fabricants de logiciels.
Nous pensons qu’une approche « Secure-by-Design » (Scuriser par la conception) est ncessaire pour une scurit leve de la mmoire, ce qui ncessite l’adoption de langages avec des garanties rigoureuses de scurit de la mmoire. tant donn le long dlai ncessaire la transition vers des langages de scurit de la mmoire, il est galement ncessaire d’amliorer la scurit des bases de code C et C++ existantes dans la mesure du possible, en liminant les classes de vulnrabilit.
Source : « Secure by Design: Googles Perspective on Memory Safety » (Google)
Et vous ?
Quel est votre avis sur le sujet ?
Voir aussi :