FIT SZZ Materiály
← Zpět na specializaci

NSEC, okruh č. 61

Nearchitekturní útoky - Spectre, Meltdown a jim podobné útoky.

Materiály

Meltdown

NOTE
Mikroarchitekturní útoky typu Meltdown ukázaly zásadní nesoulad mezi tím, co procesor garantuje na úrovni architektury, a tím, co reálně probíhá uvnitř mikroarchitektury. Z architekturního hlediska platí, že neprivilegovaný proces nesmí číst paměť jádra operačního systému. Pokud se o to pokusí, přístup je zamítnut a je vyvolána výjimka. Problém však spočívá v tom, že moderní procesory kvůli výkonu provádějí některé operace dříve, než je definitivně jasné, zda budou moci být architekturně potvrzeny. Výsledky těchto operací se sice následně zahodí, ale jejich mikroarchitekturní vedlejší efekty, zejména změny v cache, mohou přetrvat a být pozorovatelné. Meltdown využívá právě tuto vlastnost. Útočník v neprivilegovaném režimu vyvolá přístup na adresu, která patří do privilegované části adresního prostoru, typicky do paměti jádra. Takový přístup nemá být povolen. Než je však výjimka architekturně zpracována, může procesor krátce pracovat s načtenou hodnotou v rámci transientního provádění. Tato hodnota se neobjeví v registrech způsobem, který by byl pro program legálně dostupný, ale může být použita jako operand následujících instrukcí. Typickým trikem je použít tajný bajt jako index do pomocného pole v uživatelské paměti. Podle hodnoty tajného bajtu se načte jiná část tohoto pole, a tím se do cache dostane konkrétní cache line. Samotné tajemství tedy není útočníkovi předáno přímo. Přenese se nepřímo přes stav cache. Útočník následně změří dobu přístupu k jednotlivým částem pomocného pole. Ta část, která byla při transientním provádění načtena, bude dostupná rychleji, protože je v cache. Z rychlého přístupu lze odvodit, jaká hodnota byla použita jako index, a tedy jaký bajt se nacházel na chráněné adrese. Tento mechanismus odpovídá postrannímu kanálu, konkrétně cache timing side channelu. Často se používá technika Flush+Reload, při níž se sledovaná data nejprve odstraní z cache a poté se měří, která položka byla znovu načtena. Podstatné je, že Meltdown nevyžaduje klasickou softwarovou chybu v jádře operačního systému. Nejde o buffer overflow, chybné oprávnění souboru ani chybu v systémovém volání. Útok zneužívá fakt, že privilegovaná paměť byla v mnoha systémech namapována v adresním prostoru každého procesu, byť označena jako nepřístupná pro uživatelský režim. Toto řešení bylo historicky výhodné z hlediska výkonu, protože zrychlovalo přechody mezi uživatelským a kernelovým režimem. Bezpečnostní model předpokládal, že samotný bit oprávnění ve stránkovací tabulce postačí. Meltdown ukázal, že nestačí, pokud mikroarchitektura dovolí, aby se data z nepovolené adresy transientně dostala do výpočtu před dokončením kontroly oprávnění. Z hlediska dopadu je útok závažný proto, že narušuje základní princip izolace paměti. Pokud může běžný proces číst paměť jádra, může potenciálně získat hesla, kryptografické klíče, obsah souborů v paměti, data jiných procesů nebo informace z prostředí sdíleného hostitele. V kontejnerových technologiích je problém ještě citlivější, protože kontejnery sdílejí stejné jádro. Únik z jednoho kontejneru tedy může znamenat ohrožení ostatních kontejnerů na stejném fyzickém systému. Podobné riziko se týká i cloudových prostředí, kde je izolace mezi zákazníky základním bezpečnostním požadavkem. Hlavní softwarovou obranou se stalo oddělení stránkovacích tabulek uživatelského a kernelového režimu, známé jako KAISER nebo později KPTI. Princip spočívá v tom, že kernelová paměť již není běžně namapována v adresním prostoru uživatelského procesu. Pokud není privilegovaná adresa vůbec platně namapována, procesor z ní nemůže transientně načíst data, a útok ztrácí základní předpoklad. Tato obrana však přináší výkonové náklady, protože přechody mezi user mode a kernel mode vyžadují častější přepínání stránkovacích struktur. Meltdown je důležitý nejen jako konkrétní zranitelnost, ale i jako bezpečnostní poučení. Ukazuje, že formální správnost architektury procesoru nestačí, pokud mikroarchitekturní implementace zanechává měřitelné stopy po operacích, které měly být z hlediska programu nepozorovatelné. Bezpečnost moderních systémů proto musí počítat nejen s tím, jaké výsledky instrukce oficiálně vracejí, ale také s tím, jaké vedlejší efekty zanechávají v cache, prediktorech, bufferech a dalších vnitřních strukturách procesoru.

Spectre

NOTE
Spectre je příbuzná třída mikroarchitekturních útoků, ale princip je od Meltdownu podstatně odlišný. Zatímco Meltdown obchází hardwarovou kontrolu oprávnění a umožňuje neprivilegovanému procesu transientně pracovat s daty z privilegované paměti, Spectre se zaměřuje na zneužití spekulativního provádění v rámci kódu, který má k daným datům legitimní přístup. Útočník tedy typicky nedonutí procesor přímo přečíst kernelovou paměť, ale zmanipuluje predikční mechanismy tak, aby oběť spekulativně provedla instrukce, které by při správném běhu programu provedeny nebyly. Tyto instrukce mohou pracovat s citlivými daty oběti a zanechat po sobě měřitelnou stopu v cache. Základní myšlenkou Spectre je narušení předpokladu, že kontroly v programu, například kontrola mezí pole, jednoznačně brání přístupu k nepovoleným datům. Uvažujme funkci, která před přístupem do pole ověřuje, zda je index menší než délka pole. Architekturně je vše v pořádku: pokud index platný není, přístup se neprovede. Procesor však kvůli výkonu nechce čekat na definitivní vyhodnocení podmínky a použije branch predictor. Pokud byl prediktor předtím natrénován na to, že podmínka bývá splněna, procesor začne spekulativně vykonávat větev s přístupem do pole i pro neplatný index. Jakmile se později ukáže, že predikce byla chybná, architekturní výsledky se zahodí. Mikroarchitekturní efekty, zejména načtení určité cache line, však mohou zůstat. Typický Spectre útok má proto dvě fáze. Nejprve útočník natrénuje prediktor větvení tak, aby očekával určité chování programu. Potom vyvolá vstup, při kterém je predikce chybná a program spekulativně sáhne mimo logicky povolenou oblast. Takto získaná tajná hodnota se použije jako index do pomocného pole, čímž se zakóduje do cache. Následným měřením časů přístupu, například metodou Flush+Reload nebo Prime+Probe, lze určit, která část pomocného pole byla načtena, a z toho odvodit tajnou hodnotu. Důležité je, že z architekturního pohledu se žádné pravidlo neporušilo: nepovolený přístup byl zrušen. Informace však unikla přes vedlejší kanál. Spectre je obecnější než Meltdown a právě proto je obtížnější jej plně odstranit. Nezávisí pouze na tom, zda je kernelová paměť mapována do uživatelského adresního prostoru. Využívá běžné konstrukce programů, jako jsou podmínky, nepřímé skoky, volání přes ukazatele na funkce, virtuální metody nebo návraty z funkcí. Jde tedy spíše o útok na hranici mezi tím, co program smí udělat architekturně, a tím, co může procesor dočasně vykonat spekulativně. Oběť přitom může být jiný proces, sandboxovaný skript v prohlížeči, knihovna sdílená mezi procesy nebo kód běžící ve stejném adresním prostoru. Nejznámější varianty Spectre se označují jako variant 1 a variant 2. Varianta 1, bounds check bypass, zneužívá špatně predikovanou podmínku, typicky kontrolu mezí pole. Procesor spekulativně pokračuje, jako kdyby index byl platný, a tím může použít data mimo očekávaný rozsah. Varianta 2, branch target injection, zneužívá predikci cíle nepřímého skoku. Útočník se snaží ovlivnit prediktor tak, aby oběť spekulativně skočila na vhodný úsek instrukcí, často označovaný jako gadget, který dokáže citlivou hodnotu zakódovat do mikroarchitekturního stavu. Později byly popsány i další příbuzné varianty využívající návratový prediktor, store-to-load forwarding nebo jiné spekulační mechanismy. Rozdíl oproti Meltdownu je zásadní i z hlediska obrany. Proti Meltdownu velmi dobře funguje odstranění kernelových mapování z uživatelského prostoru pomocí KPTI, protože útok potřebuje, aby privilegovaná paměť byla v adresním prostoru procesu platně namapována. Spectre tímto jednoduchým opatřením vyřešit nelze. Útok totiž často probíhá uvnitř legitimního adresního prostoru oběti a zneužívá instrukce, které jsou samy o sobě běžné a správné. Obrana proto musí kombinovat více technik: vkládání spekulačních bariér, úpravu kompilátorů, omezení přesných časovačů, izolaci procesů, retpoline pro nepřímé větvení, čištění nebo oddělování predikčních struktur a úpravy hardwaru. Spectre je z bezpečnostního hlediska významný tím, že rozšiřuje problém mikroarchitekturních útoků z konkrétní chyby jedné optimalizace na obecnější vlastnost moderního návrhu procesorů. Spekulativní provádění je všudypřítomné a zásadní pro výkon, ale zároveň vytváří dočasné výpočetní stavy, které původní bezpečnostní modely často nepovažovaly za pozorovatelné. Spectre ukazuje, že i správný program s kontrolami mezí a bez klasické paměťové chyby může při spekulativním běhu vytvářet informační únik. Z pohledu návrhu bezpečných systémů proto nestačí ověřovat pouze architekturní chování programu; je nutné uvažovat i to, zda spekulativní cesty nemohou citlivá data přenést do cache nebo jiného měřitelného mikroarchitekturního stavu.

Použito také ve specializacích