Pitfalls in VM Implementation on CHERI: Lessons from Porting CRuby

Cet article présente les pièges spécifiques à l'implémentation de machines virtuelles sur l'architecture CHERI, identifiés lors du portage de CRuby, qui découlent de comportements non définis en C supposés valides sur les architectures traditionnelles mais incompatibles avec le modèle de sécurité mémoire de CHERI, tout en proposant des solutions de contournement validées.

Hanhaotian Liu (University of Tokyo, Japan), Tetsuro Yamazaki (University of Tokyo, Japan), Tomoharu Ugawa (University of Tokyo, Japan)

Publié Mon, 09 Ma
📖 7 min de lecture🧠 Analyse approfondie

Each language version is independently generated for its own context, not a direct translation.

🛡️ Le Grand Remodelage : Quand le langage Ruby rencontre le "Super-Héros" CHERI

Imaginez que vous avez un vieux château (le langage de programmation Ruby et son moteur, la Machine Virtuelle ou VM). Ce château fonctionne depuis des décennies, mais il a des portes faibles, des murs fissurés et des passages secrets que n'importe qui peut emprunter pour voler ou détruire des choses. C'est ce qu'on appelle les failles de sécurité mémoire.

Pour réparer ce château, les chercheurs ont conçu un nouveau système de sécurité ultra-puissant appelé CHERI. Au lieu d'avoir de simples clés (les pointeurs classiques), CHERI donne à chaque objet une carte d'identité magique (une "capacité"). Cette carte ne dit pas seulement "où" se trouve l'objet, elle précise aussi "jusqu'où" vous pouvez aller et "ce que vous avez le droit de faire" (lire, écrire, exécuter). Si vous essayez d'ouvrir une porte avec une carte qui ne correspond pas exactement à la zone, le système vous arrête immédiatement.

Le problème ? Le château Ruby a été construit par des architectes qui pensaient que les clés étaient simples. Ils ont fait des suppositions sur la façon dont les choses fonctionnent, des suppositions qui sont fausses avec les nouvelles cartes d'identité de CHERI.

Ce papier raconte l'histoire de l'équipe qui a dû rénover le château Ruby pour qu'il fonctionne avec ce nouveau système de sécurité, et les pièges bizarres qu'ils ont rencontrés.


🕵️‍♂️ Les 6 Pièges (et les analogies pour les comprendre)

Les chercheurs ont découvert six types de problèmes majeurs. Voici comment ils les expliquent avec des métaphores :

1. Le Piège de la "Carte Trop Petite" (Pointeurs dérivés invalides)

  • Le problème : Imaginez que vous avez une carte d'accès à tout l'étage du château (la pile d'exécution). Vous en faites une copie pour aller dans une seule pièce (une variable locale). La copie est valide, mais elle ne vous autorise qu'à entrer dans cette pièce.
  • L'erreur : Le vieux Ruby prenait cette copie restreinte et disait : "Tiens, je vais l'utiliser pour parcourir tout l'étage !"
  • La conséquence : Le système de sécurité CHERI crie : "Arrête ! Ta carte ne couvre que cette pièce, tu ne peux pas aller ailleurs !" et bloque tout.
  • La solution : Garder toujours la "Super-Carte" (celle qui couvre tout l'étage) en réserve et ne jamais l'oublier, même quand on en a besoin pour des petites tâches.

2. Le Piège du "Faux Visage" (Déréférencement de pointeurs ambigus)

  • Le problème : Le système de sécurité (Garbage Collector) doit trier les objets. Il regarde les chiffres sur la table et se dit : "Celui-ci ressemble à une clé, je vais l'essayer."
  • L'erreur : Parfois, un simple nombre (un entier) a exactement la même apparence qu'une clé. Sur les vieux systèmes, on l'essayait et ça marchait (ou ça plantait gentiment). Sur CHERI, si ce nombre n'a pas la "carte d'identité" valide (le tag), le système le rejette violemment.
  • La solution : Au lieu de regarder juste la forme du nombre, on vérifie sa carte d'identité. Si le tag est manquant, on sait tout de suite que ce n'est pas une vraie clé. C'est même plus rapide !

3. Le Piège du "Tapis Rouge qui Change" (Réallocation sur place)

  • Le problème : Imaginez que vous avez un tapis (un bloc de mémoire) et que vous voulez le rallonger pour mettre plus de meubles.
  • L'erreur : Le vieux Ruby disait : "Je rallonge le tapis, mais je garde la même étiquette sur le coin du tapis."
  • La conséquence : Sur CHERI, quand on rallonge le tapis, l'étiquette (la capacité) change pour refléter la nouvelle taille. Si le vieux Ruby continue d'utiliser l'ancienne étiquette (qui dit "taille courte") pour écrire sur la partie rallongée, le système bloque : "Hé ! Tu écris en dehors de tes limites !"
  • La solution : Ne jamais supposer que l'adresse reste la même après un agrandissement. Il faut toujours mettre à jour l'étiquette avec la nouvelle version.

4. Le Piège des "Bits Fantômes" (Utilisation des bits de remplissage)

  • Le problème : Les nouvelles cartes d'identité (les capacités) sont plus grosses que les anciennes clés. Pour les faire entrer dans les vieux tiroirs, on a ajouté des espaces vides (des bits de remplissage) qui contiennent des informations secrètes (les métadonnées).
  • L'erreur : Le vieux Ruby prenait une carte, la transformait en nombre, et jouait avec tous les bits, y compris ceux qui contiennent les secrets de sécurité.
  • La conséquence : En modifiant ces bits secrets, on corrompt la carte d'identité. CHERI ne comprend plus rien et plante.
  • La solution : Utiliser des boîtes (types entiers) qui n'ont pas de secrets cachés à l'intérieur, pour ne toucher qu'aux données utiles.

5. Le Piège de la "Clé Scellée" (Modification de capacités temporaires)

  • Le problème : Certaines clés sont "scellées" (comme un cachet de cire sur une lettre). On ne peut pas les modifier, sinon le cachet casse. C'est le cas des adresses de retour des fonctions.
  • L'erreur : Le compilateur CHERI est très intelligent. Parfois, il crée une "copie temporaire" d'une clé pour faire un calcul mathématique. Si la clé originale était scellée, cette copie temporaire essaie de modifier le cachet, ce qui est interdit.
  • La conséquence : Explosion de sécurité (faute de capacité scellée).
  • La solution : Dire au compilateur : "Ne fais pas de copie temporaire, traite ça comme un simple nombre brut."

6. Le Piège du "Changement de Costume" (Arithmétique sur des types non-capables)

  • Le problème : En programmation, on fait souvent des calculs sur des adresses en les transformant en nombres, puis on les retransforme en adresses.
  • L'erreur : Le vieux Ruby utilisait des "nombres génériques" (comme size_t) pour faire ces calculs. Mais sur CHERI, seul un "nombre spécial" (uintptr_t) sait comment garder la carte d'identité intacte pendant le calcul.
  • La conséquence : Quand on retransforme le nombre en adresse, la carte d'identité est perdue ou corrompue. La nouvelle clé ne fonctionne plus.
  • La solution : Utiliser uniquement le "nombre spécial" (uintptr_t) pour tous les calculs d'adresses.

📉 Est-ce que ça ralentit tout ?

C'est la grande question : si on ajoute toutes ces règles de sécurité, est-ce que le château Ruby va devenir une tortue ?

Les chercheurs ont fait des tests. Résultat : Non, pas vraiment !

  • La plupart des tâches vont à la même vitesse (98% de la vitesse originale).
  • Il y a quelques exceptions (comme la gestion des "fibres", un type de multitâche), où c'est un peu plus lent, mais c'est acceptable.
  • Le plus important : en corrigeant ces bugs, le système devient beaucoup plus sûr, et parfois même plus précis dans sa gestion de la mémoire.

🏁 Conclusion

Ce papier nous apprend une leçon précieuse : On ne peut pas simplement copier-coller du vieux code sur une nouvelle architecture de sécurité.

Les développeurs de machines virtuelles (comme celle de Ruby) ont l'habitude de tricher un peu avec les règles du langage C pour aller plus vite. CHERI, lui, ne tolère aucune triche. Pour construire un château sûr avec CHERI, il faut :

  1. Arrêter de faire des suppositions sur la façon dont la mémoire fonctionne.
  2. Respecter strictement les règles des cartes d'identité (capacités).
  3. Utiliser les bons outils (types de données) pour chaque tâche.

C'est un travail de rénovation difficile, mais c'est la seule façon de construire des logiciels qui résistent vraiment aux pirates de demain.