Door Wouter Tinus

De HyperThreading-'bug' uitgelegd

Geheime communicatie

HyperThreading aankondiging De onafhankelijk werkende BSD-programmeur Colin Percival waarschuwde afgelopen vrijdag dat het gebruik van HyperThreading-technologie op servers met meerdere gebruikers een beveiligingsrisico kon vormen. Er zou namelijk een methode bestaan om deze techniek - die al lange tijd standaard in een groot deel van de desktop- en serverchips van Intel zit - te misbruiken voor het achterhalen van encryptiesleutels van anderen. Nu de complete technische details met betrekking tot deze ontdekking bekend zijn gemaakt is het tijd om te bekijken wat er precies aan de hand is. Van te voren kunnen we al melden dat het allemaal niet zo spectaculair is als het in eerste instantie werd gebracht: Het is niet nodig voor Intel om al zijn HyperThreading Xeons terug te roepen, en waarschijnlijk zullen alleen de écht paranoïde systeembeheerders het de moeite waard vinden om er een oplossing voor te zoeken. Toch is het een interessante en vooral slimme truc, dus vandaar dat we er graag nog even aandacht aan willen besteden.

* Geheime kanalen

Om een beter idee te krijgen van wat er mogelijk kan gebeuren is het handig om eerst het concept van een 'secret channel' uit te leggen. Dit is een manier voor twee threads om met elkaar te communiceren zonder dat het operating systeem dat kan voorkomen of zelfs maar in de gaten heeft. Beide processen moeten hier bewust aan meewerken, maar een hacker kan op deze manier dus wel alle restricties omzeilen die het operating systeem heeft om gebruikers van elkaar gescheiden te houden. De eerste methode die we zullen bekijken gaat er wel vanuit dat er een bestand is waar beide processen van kunnen lezen, maar verderop zullen we zien dat zelfs dat niet nodig is.

De communicatie werkt op de volgende manier: Het 'verzendende' proces leest een paar delen van het bestand uit. Door het lezen van deze gegevens komen ze automatisch in het geheugen te staan. Het 'ontvangende' proces leest vervolgens het complete bestand uit. Het (virtuele) geheugen van een computer werkt altijd met brokken data van vaste grootte, de zogenaamde pagina's. Door te meten hoe lang het duurt voor iedere pagina van het bestand is opgehaald kan herkend worden welke delen ervan al een keer eerder zijn gelezen. Als een bepaald deel al in het RAM staat zal het immers veel eerder toegankelijk zijn dan wanneer het nog van de harde schijf gehaald moet worden. Door een simpele afspraak te maken (pagina lezen: 1, pagina niet lezen: 0) kunnen op deze manier gegevens in binaire vorm worden overgestuurd.

Wie nu denkt dat dit een gigantisch onhandige methode is met meer nadelen dat wat anders heeft helemaal gelijk. Toch is er een variant die wel degelijk (redelijk) goed werkt. Deze is gebaseerd op het cache van de processor en doet eigenlijk precies het tegenovergestelde van de eerste methode: In plaats van dingen te lezen zodat voor de ander merkbaar is dat ze sneller zijn, duwt deze juist data uit het cache om het voor de ander trager te maken. Het voordeel daarvan ten opzichte van de andere methode is dat de twee threads op deze manier geen toegang hoeven hebben tot een of ander gedeeld bestand, maar behalve het draaien op dezelfde processor geen enkele andere connectie nodig hebben.

Cacheing
Van traag en groot naar klein en snel: harde schijf, systeemgeheugen, L2-cache, L1-cache.

Het equivalent van een geheugenpagina in termen van processorcache is een lijn. Hoewel het operating systeem zelf kan bepalen hoe groot pagina's zijn, liggen cachelijnen vastgelegd in de hardware. Het L1-cache van de Pentium 4-architectuur is bijvoorbeeld opgebouwd uit 128 lijnen van 64 bytes groot. Voor iedere bit die de 'verzender' wil versturen moet het een stuk geheugen reserveren ter grootte van één cachelijn. Om een 32-bits woord te versturen is dus een array van 2048 bytes nodig. De ontvanger reserveert ondertussen een array dat precies even groot is als de capaciteit van het cache (voor het L1 van de Pentium 4 is dat 8KB) en leest dat direct helemaal in. Op dat moment staan er dus alleen nog maar gegevens van de ontvanger in het cache.

Vervolgens is de verzender aan de beurt om bepaalde delen van zijn 2KB-array lezen. Omdat het L1-cache al helemaal volstaat zal iedere keer dat de verzender iets leest een stuk data van de ontvanger weggegooid moeten worden. Als de ontvanger vervolgens weer aan de beurt is kan deze zijn eigen 8KB-array weer een keer nalopen, en meten of (en zo ja ook welke) lijnen door de verzender terug naar het L2-cache zijn geschopt. Er kunnen natuurlijk altijd andere threads tussendoor komen die roet in het eten gooien, maar gegeven dat er gunstige omstandigheden zijn en er een goed foutcorrectie-algoritme in het protocol zit kan op een 2,8GHz Pentium 4 toch een kanaal van 400KB/s worden gerealiseerd.

Ook het L2-cache kan gebruikt worden om een geheim kanaal aan te leggen, maar dat is om verschillende redenen al een stuk lastiger. Ten eerste bevat het L2-cache in tegenstelling tot het L1-cache een mix van instructies en data, waardoor de reden waarom een lijn uit het cache is geschopt minder zeker is. Ook is de extra latency bij ontbrekende gegevens minder consequent, omdat dankzij de TLB (translation lookaside buffer) de helft van de lijnen sneller in het geheugen kan worden gevonden dan de andere helft. Ook kan het hardwarematige prefetch-mechanisme roet in het eten gooien als er in een (te) voorspelbaar patroon uit het cache wordt gelezen. Toch is het mogelijk om deze problemen te omzeilen en een kanaal met een bandbreedte van ongeveer 100KB/s aan te leggen.

Wat vind je van dit artikel?

Geef je mening in het Geachte Redactie-forum.

Nintendo Switch (OLED model) Apple iPhone SE (2022) LG G1 Google Pixel 6 Call of Duty: Vanguard Samsung Galaxy S22 Garmin fēnix 7 Nintendo Switch Lite

Tweakers vormt samen met Hardware Info, AutoTrack, Gaspedaal.nl, Nationale Vacaturebank, Intermediair en Independer DPG Online Services B.V.
Alle rechten voorbehouden © 1998 - 2022 Hosting door True

Tweakers maakt gebruik van cookies

Tweakers plaatst functionele en analytische cookies voor het functioneren van de website en het verbeteren van de website-ervaring. Deze cookies zijn noodzakelijk. Om op Tweakers relevantere advertenties te tonen en om ingesloten content van derden te tonen (bijvoorbeeld video's), vragen we je toestemming. Via ingesloten content kunnen derde partijen diensten leveren en verbeteren, bezoekersstatistieken bijhouden, gepersonaliseerde content tonen, gerichte advertenties tonen en gebruikersprofielen opbouwen. Hiervoor worden apparaatgegevens, IP-adres, geolocatie en surfgedrag vastgelegd.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Toestemming beheren

Hieronder kun je per doeleinde of partij toestemming geven of intrekken. Meer informatie vind je in ons cookiebeleid.

Functioneel en analytisch

Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. Klik op het informatie-icoon voor meer informatie. Meer details

janee

    Relevantere advertenties

    Dit beperkt het aantal keer dat dezelfde advertentie getoond wordt (frequency capping) en maakt het mogelijk om binnen Tweakers contextuele advertenties te tonen op basis van pagina's die je hebt bezocht. Meer details

    Tweakers genereert een willekeurige unieke code als identifier. Deze data wordt niet gedeeld met adverteerders of andere derde partijen en je kunt niet buiten Tweakers gevolgd worden. Indien je bent ingelogd, wordt deze identifier gekoppeld aan je account. Indien je niet bent ingelogd, wordt deze identifier gekoppeld aan je sessie die maximaal 4 maanden actief blijft. Je kunt deze toestemming te allen tijde intrekken.

    Ingesloten content van derden

    Deze cookies kunnen door derde partijen geplaatst worden via ingesloten content. Klik op het informatie-icoon voor meer informatie over de verwerkingsdoeleinden. Meer details

    janee