Pitfalls in VM Implementation on CHERI: Lessons from Porting CRuby

Dit artikel analyseert de valkuilen bij het porten van virtuele machines zoals CRuby naar CHERI, waarbij het specifiek ingaat op de conflicten tussen C-idioms en het strengere CHERI-beveiligingsmodel, en biedt werkoplossingen om veiligere VM-implementaties te realiseren.

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

Gepubliceerd Mon, 09 Ma
📖 6 min leestijd🧠 Diepgaand

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

Hier is een uitleg van het paper "Pitfalls in VM Implementation on CHERI: Lessons from Porting CRuby", vertaald naar begrijpelijk Nederlands met behulp van alledaagse analogieën.

De Kern: Een Veiligheidswet die te streng is voor oude gewoonten

Stel je voor dat CHERI een nieuw, superveilig type sleutelbord is voor computers. In de oude wereld (de traditionele architectuur) zijn sleutels (pointers) gewoon nummers die aangeven waar iets in het huis (het geheugen) staat. Je kunt met die nummers doen wat je wilt: ze optellen, aftrekken, en ze gebruiken om naar elke deur te lopen, zelfs als je daar geen toestemming voor hebt.

CHERI vervangt deze simpele nummers door slimme sleutels (capabilities). Deze sleutels zijn niet alleen een adres, maar dragen ook een paspoort mee met regels:

  1. Grens: Je mag alleen naar deuren in een specifieke kamer lopen (geen toegang tot de zolder of de kelder).
  2. Rechten: Je mag alleen binnenkomen, maar niet meubels verplaatsen (lezen, maar niet schrijven).
  3. Geldigheid: De sleutel heeft een hologram (een 'tag'). Als het hologram verdwenen is, werkt de sleutel niet meer.

Het probleem? De programmeurs van CRuby (de motor achter de programmeertaal Ruby) zijn gewend aan de oude, losse wereld. Ze hebben code geschreven die doet alsof alle sleutels simpele nummers zijn. Toen ze deze code probeerden te laten werken op het nieuwe, strenge CHERI-systeem, botste het. De code probeerde dingen te doen die op de oude manier "gewoon werkten", maar op de nieuwe manier direct werden gestopt omdat ze de regels van de slimme sleutels schonden.

De 6 Valkuilen (De "Pitfalls")

De auteurs hebben de CRuby-code onderzocht en zes soorten fouten gevonden. Hier zijn ze, vertaald naar alledaagse situaties:

1. De "Verkeerde Kaart" (Invalid Derived Pointer)

  • Het probleem: Stel je voor dat je een sleutel hebt die alleen toegang geeft tot je eigen slaapkamer. Je probeert nu een nieuwe sleutel te maken die toegang geeft tot het hele huis door gewoon een stukje van je oude sleutel te kopiëren en er een getal bij te tellen. Op de oude manier werkt dit; op CHERI niet, want de nieuwe sleutel heeft nog steeds de beperkingen van de oude.
  • In de praktijk: De Ruby-VM probeerde een adres op te halen van een lokale variabele (een klein stukje geheugen) en dacht dat dit het begin van de hele stapel was. Omdat de originele sleutel maar een klein stukje dekte, viel de nieuwe "sleutel" buiten de grenzen.
  • De oplossing: Gebruik een "meestersleutel" (super capability) die het hele huis dekt, en maak daar nieuwe sleutels van.

2. De "Valse Vriend" (Dereferencing Ambiguous Pointers)

  • Het probleem: De Ruby-VM kijkt naar een hoop getallen en zegt: "Dit getal lijkt op een adres, dus ik ga erheen en kijk wat er staat." Op de oude manier was dat veilig genoeg. Op CHERI is een getal dat op een adres lijkt, geen echte sleutel. Het mist het hologram (de geldigheid). Als je probeert erin te kijken, gaat het alarm af.
  • In de praktijk: De "Garbage Collector" (de schoonmaker die dode objecten opruimt) dacht dat een willekeurig getal een verwijzing naar een object was. Omdat het getal geen geldige sleutel was, crashte het systeem.
  • De oplossing: Kijk eerst naar het hologram. Is het hologram aanwezig? Ja? Dan is het een echte sleutel. Nee? Laat het dan links liggen, ook al lijkt het op een adres.

3. De "Verhuizing die niet werkt" (In-Place Reallocation)

  • Het probleem: Stel je voor dat je een koffer hebt (geheugen) en je wilt hem groter maken zonder hem te verplaatsen. Op de oude manier zei je: "Oké, ik gebruik nog steeds dezelfde sleutel voor de koffer, alleen is hij nu groter." Op CHERI is de sleutel echter gekoppeld aan de oude grootte. Als je de koffer vergroot, past de oude sleutel niet meer bij de nieuwe randen.
  • In de praktijk: De VM probeerde een blok geheugen uit te breiden en dacht dat de oude sleutel nog steeds werkte voor het nieuwe, grotere deel. CHERI blokkeerde dit omdat de grenzen van de sleutel niet overeenkwamen met de nieuwe grootte.
  • De oplossing: Gebruik altijd de nieuwe sleutel die je krijgt na het uitbreiden, en gooi de oude weg.

4. De "Lege Ruimte" (Using Padding Bits)

  • Het probleem: In de oude wereld zijn alle bits in een getal nuttig. In de CHERI-wereld zijn de bovenste bits van een "sleutel-getal" (uintptr_t) echter gereserveerd voor paspoortgegevens (metadata). Ze zijn als "lege ruimte" in een koffer die je niet mag gebruiken voor je kleding.
  • In de praktijk: Ruby probeerde kleine stukjes informatie (zoals vlaggetjes) in de bovenste bits van een getal te verstoppen. Omdat deze bits op CHERI gereserveerd zijn voor metadata, werden de data overschreven of genegeerd.
  • De oplossing: Gebruik voor het opslaan van data puur "lege" getallen (zoals uint64_t) die geen paspoortinhoud hebben, zodat je alle bits kunt gebruiken.

5. De "Gegoten Sleutel" (Modifying Temporary Capabilities)

  • Het probleem: Sommige sleutels zijn "afgegoten" (sealed). Ze zijn zo gemaakt dat je ze nooit meer kunt aanpassen. Als je probeert ze te veranderen, breekt de sleutel.
  • In de praktijk: De computer zelf maakt soms tijdelijke versies van deze afgegoten sleutels om berekeningen te doen. De programmeur dacht: "Ik tel gewoon twee getallen op." Maar omdat de computer een afgegoten sleutel gebruikte, probeerde hij die te veranderen, wat verboden is.
  • De oplossing: Zet de afgegoten sleutel eerst om in een gewoon getal (zonder paspoort), doe de berekening, en gebruik het resultaat als een getal.

6. De "Verkeerde Rekenmachine" (Pointer Arithmetic on Non-Capability Type)

  • Het probleem: Soms gebruiken programmeurs de verkeerde "rekenmachine" om met adressen te rekenen. Ze gebruiken een rekenmachine voor gewone maten (size_t) in plaats van de speciale rekenmachine voor sleutels (uintptr_t).
  • In de praktijk: Ruby rekende afstanden uit met een type dat niet geschikt was voor slimme sleutels. Het resultaat was een "sleutel" die eruitzag als een sleutel, maar geen geldig hologram had.
  • De oplossing: Gebruik altijd de juiste, speciale rekenmachine (uintptr_t) die weet hoe het om moet gaan met de regels van de slimme sleutels.

Wat betekent dit voor de toekomst?

De auteurs hebben CRuby succesvol aangepast. Ze hebben de code "opgepoetst" zodat het werkt op het nieuwe, veilige systeem.

  • Snelheid: Het nieuwe systeem is bijna even snel als het oude (ongeveer 98% van de snelheid).
  • Veiligheid: Het grootste voordeel is dat het systeem nu veel veiliger is. Veel hacks die mogelijk waren op de oude manier, zijn nu onmogelijk omdat de "slimme sleutels" de regels streng bewaken.

Conclusie:
Het porten van complexe software (zoals een VM) naar een veiliger systeem is als het verhuizen van een oud huis naar een nieuw, streng beveiligd complex. Je kunt niet zomaar je oude sleutels gebruiken; je moet je gewoonten aanpassen en nieuwe regels leren. Dit paper is een handleiding voor die verhuizing, zodat anderen niet dezelfde fouten maken.