Spectre – hardveres sérülékenységek csoportja , a legtöbb modern processzor hibája, amelyek spekulatív utasítás-végrehajtással rendelkeznek.és fejlett ág-előrejelzés , amely lehetővé teszi az adatok harmadik féltől származó csatornán keresztüli olvasását egy közös gyorsítótár - hierarchia formájában . A legtöbb modern mikroprocesszort érinti, különösen az x86/x86_64 architektúrákat (Intel és AMD) és néhány ARM processzormagot [1] .
A sérülékenység potenciálisan lehetővé teszi a helyi alkalmazások (helyi támadó, speciális program futtatása esetén) számára, hogy hozzáférjenek az aktuális alkalmazás vagy más programok virtuális memóriájának tartalmához [2] [3] [4] . A fenyegetés két CVE - azonosítót kapott: CVE-2017-5753 és CVE-2017-5715 .
A Spectret az észak-amerikai Google vállalat ( Project Zero ) kutatói és egy Paul Kocherrel együttműködő csoport fedezték fel egymástól függetlenül, a Grazi Műszaki Egyetem munkatársainak részvételével . A sérülékenységet 2017 közepén találták meg, és több hónapig zárt vita és javítás alatt állt. A részletek és a javítások közzétételét 2018. január 9-re tervezték, de a sebezhetőség részleteit 2018. január 4-én, a Meltdown támadással egy időben hozták nyilvánosságra, a The Register [5] újságíróinak publikációi miatt, akik tudomást szereztek a a KAISER/KPTI javítások a Linux kernel levelezőlistájáról származó Meltdown leküzdésére [6] .
A Spectre bug lehetővé teszi, hogy az adott számítógépen futó rosszindulatú felhasználói alkalmazások olvasási hozzáférést kapjanak a számítógép memóriájában az áldozati folyamat által használt tetszőleges helyekhez, például más alkalmazásokhoz (azaz megszakítsák a programok közötti memórialeválasztást). A Spectre támadás a legtöbb nagy teljesítményű mikroprocesszort használó számítógépes rendszert érinti, beleértve a személyi számítógépeket, szervereket, laptopokat és számos mobileszközt [7] . A Spectre támadást különösen az Intel és az AMD vállalatok által gyártott processzorok és ARM processzormagokat használó chipek ellen mutatták be .
A Spectre támadásnak létezik egy olyan változata, amely JavaScript programokat használ a böngészők memóriájához való hozzáféréshez (más oldalakról származó adatok vagy a böngészőben mentett adatok beolvasása) [8] .
Tegyük fel, hogy az áldozati folyamat kódrészlete
if ( x < tömb1_méret ) y = tömb2 [ tömb1 [ x ] * 256 ];egy olyan függvény része, amely egy előjel nélküli x egész számot kap egy nem megbízható forrásból, és a kódot végrehajtó folyamat hozzáfér egy előjel nélküli 8 bites egész számokból álló tömbhöz , amelynek mérete tömb1_méret mérete 64 kb.
Ez a részlet azzal kezdődik, hogy ellenőrzi, hogy x érvényes érték. Ez az ellenőrzés pedig elengedhetetlen biztonsági szempontból. Különösen megakadályozza az információ beolvasását a tömb1 határain túl . Ennek hiányában az érvénytelen x értékek kivételt jelenthetnek, amikor a folyamat rendelkezésre álló memóriáján kívüli adatokat próbálnak beolvasni, vagy a folyamat által elérhető bizalmas információkat olvashatják az x = <titkos_byte_cím> - <tömb1_címtömb1> megadásával .
Sajnos egy feltételes ág téves előrejelzése az utasítások spekulatív végrehajtása során a programkód olyan ágának a végrehajtásához vezethet, amely normál körülmények között soha nem kerül végrehajtásra [9] .
Például a fenti kódrészlet a következő feltételek mellett hajtható végre:
Ilyen feltételek spontán módon is felmerülhetnek, de céltudatosan is kialakíthatók, például nagy mennyiségű idegen adat beolvasásával, hogy ezekkel az adatokkal feltöltsék a processzor gyorsítótárát, és ennek megfelelően a tömb1_mérete és tömb2 kiütődjenek a gyorsítótárból, ill. majd hívja meg a k titkos bájtot használó kernelfüggvényt annak gyorsítótárazásához. Ha azonban a gyorsítótár-struktúra ismert, vagy a processzor önként ad egy gyorsítótár-visszaállítási utasítást (például az x86 család processzorainak cflush utasítását ), akkor a kódrészlet végrehajtásához szükséges feltételek megteremtése jelentősen leegyszerűsödik.
A kódrészlet úgy kezdődik, hogy összehasonlítja x értékét a tömb1_méret értékével . A tömb1_méret értékének beolvasása a fent leírt feltételek mellett gyorsítótár kihagyást eredményez, ami viszont azt eredményezi, hogy várni kell, amíg a tömb1_méret értéke lekérésre kerül a RAM-ból. A processzorban egy spekulatív utasítás-végrehajtási mechanizmus jelenléte miatt a várakozási idő alatt a processzor nem tétlen, hanem az elágazási utasítást követően megpróbálja végrehajtani a programkód valamelyik ágát.
Mivel a töredékhez való korábbi hozzáférések érvényes x értékekkel történtek , az ág-előrejelző azt feltételezi, hogy ezúttal az predikátum (x < tömb1_méret) igaz lesz, és a processzor megpróbálja végrehajtani a megfelelő utasítássorozatot. Ugyanis a <tömb1_cím> + x -en lévő bájtot fogja beolvasni , vagyis a titkos k bájtot , amely a speciálisan kialakított feltételeknek köszönhetően már a gyorsítótárban van. Ezután a processzor a kapott értéket felhasználva kiértékeli a k * 256 kifejezést , és beolvassa a tömb2[k * 256] elemét , ami egy második gyorsítótár kihagyást eredményez, és megvárja, amíg a tömb2[k * 256] értéke megjelenik. RAM-ból lekérve. Ekkor az array1_size értéke a RAM-ból lesz leolvasva , a processzor felismeri az elágazás-előrejelző hibáját, és visszaállítja a programkód hibás ágának végrehajtása előtti pillanatra az architekturális állapotot.
Valós processzorokon azonban a tömb2[k * 256] spekulatív olvasása hatással lesz a processzor gyorsítótárának állapotára, és ez az állapot k függvénye . A támadás befejezéséhez csak egy oldalcsatornás támadással kell észlelni ezt a változást (a támadónak hozzá kell férnie a megosztott processzor gyorsítótárához és a pontos időforráshoz), és ennek alapján ki kell számítani a titkos k bájtot . Ezt könnyű megtenni, mivel a tömb2[n * 256] elemeinek olvasása n = k esetén gyors , más értékek esetén lassú lesz.
Egy közvetett elágazás kettőnél több címet is használhat az elágazáshoz. Például az x86 -család processzor utasításai ugrhatnak egy címérték használatával egy regiszterben ( jmp eax ), a memóriában ( jmp [ eax ] vagy jmp dword ptr [ 0xdeadc0de ] ), vagy a veremben ( ret ). A közvetett ugrási utasítások megtalálhatók az ARM -ben ( mov pc, r14 ), MIPS -ben ( jr $ra ), SPARC -ban ( jmpl %o7 ), RISC-V- ben ( jarl x0,x1,0 ) és sok másban is.
Ha a közvetett elágazás címének meghatározása a gyorsítótár hiánya miatt késik, és a közvetett elágazás- előrejelzőt speciálisan kiválasztott címekre "oktatják", akkor a támadó által megadott címen az utasítások spekulatív végrehajtása fordulhat elő. Parancsok, amelyeket egyébként soha nem hajtottak volna végre. Ha egy ilyen teljesítmény mérhető mellékhatásokat hagy maga után, akkor a használata erőteljes eszközzé válik a támadó kezében.
Jelenleg nem állnak rendelkezésre kész szoftvertechnológiák a Spectre támadás elleni védelemre, bár némi munka folyik [10] . A támadást népszerűsítő webhely szerint "Nem olyan könnyű kijavítani, és ez (a hiba) sokáig kísérteni fog minket."
A szoftverjavítás magában foglalhatja a szoftver újrafordítását új fordítók segítségével a sérülékeny gépi kódszekvenciák helyettesítésére (az úgynevezett "retpoline" mechanizmus, amelyet a GCC és a Clang / LLVM implementál ) [11] .
A processzorgyártók több javítást is javasoltak, némelyikhez a processzor mikrokódjának frissítése szükséges, másokhoz pedig új utasításokat kell hozzáadni a jövőbeli processzorokhoz. A javításokat szoftver-újrafordítással kell kombinálni [11] .
A Spectre CVE közleményének korai verzióiban a CERT a processzorok cseréjét javasolta válaszként a sérülékenységre: „A sérülékenységet a mikroprocesszor-tervezési döntések okozzák. A sérülékenység teljes eltávolításához ki kell cserélni az érintett mikroprocesszorokat.” A későbbi szövegekben azonban a javításnak ezt a változatát már nem említették [11] .