Ką „Spectre and Meltdown“ reiškia „WebKit“
Saugumo tyrėjai neseniai atskleidė saugumo problemas, žinomas kaip „Meltdown“ ir „Spectre“. Šios problemos taikomos visiems šiuolaikiniams procesoriams ir suteikia užpuolikams galimybę skaityti prieigą prie atminties dalių, kurios turėjo būti slaptos. Norėdami pradėti „Spectre“ ar „Meltdown“ pagrindu vykdomą ataką, užpuolikas turi sugebėti paleisti kodą aukos procesoriuje. Tai daro įtaką „WebKit“, nes norint pateikti šiuolaikines svetaines, bet kuris „JavaScript“ variklis turi leisti vartotojo procesoriuje paleisti nepatikimą „JavaScript“ kodą. „Spectre“ tiesiogiai veikia „WebKit“. „Meltdown“ veikia „WebKit“, nes „WebKit“ saugos ypatybes pirmiausia reikia apeiti (per „Spectre“), kad būtų galima naudoti „WebKit“ „Meltdown“ atakai sujungti.
- „WebKit“ remiasi filialo instrukcijas priversti įgyvendinti nepatikimą „JavaScript“ ir „WebAssembly“ kodą. „Spectre“ reiškia, kad užpuolikas gali valdyti šakas, todėl vien šakos nebetinka saugumo savybėms įgyvendinti.
-
„Meltdown“ reiškia, kad „userland“ kodas, pvz., „JavaScript“, veikiantis žiniatinklio naršyklėje, gali nuskaityti branduolio atmintį. Ne visi procesoriai yra paveikti „Meltdown“, o „Meltdown“ švelnina operacinės sistemos pakeitimai. Norint įdiegti „Meltdown“ ataką naudojant „JavaScript“, veikiančią „WebKit“, pirmiausia reikia apeiti filialo saugumo patikrinimus, pavyzdžiui, „Spectre“ atakos atveju. Todėl „Spectre“ sušvelninimas, išsprendžiantis šakos problemą, taip pat užkerta kelią užpuolikui naudoti „WebKit“ kaip „Meltdown“ atspirties tašką.
Šiame dokumente paaiškinama, kaip „Spectre“ ir „Meltdown“ veikia esamus „WebKit“ saugos mechanizmus ir kokius trumpalaikius bei ilgalaikius „WebKit“ pataisymus siūlo apsaugoti nuo šios naujos klasės atakų. Pirmasis iš šių padarinių buvo pristatytas 2018 m. Sausio 8 d .:
- „iOS 11.2.2“.
- „High Sierra“ 10.13.2 papildomas atnaujinimas. Tai pakartotinai naudoja 10.13.2 versijos numerį. Galite patikrinti, ar „Safari“ ir „WebKit“ yra pataisyti, patikrinę visos versijos numerį skiltyje „Apie„ Safari ““. Versijos numeris turėtų būti 13604.4.7.1.6 arba 13604.4.7.10.6.
- „Safari 11.0.2“ skirtas „El Capitan“ ir „Sierra“. Tai pakartotinai naudoja 11.0.2 versijos numerį. Pataisytos versijos yra 11604.4.7.1.6 (El Capitan) ir 12604.4.7.1.6 (Sierra).
Spectre ir saugumo patikrinimai
Spectre reiškia, kad šakų nebepakanka, kad būtų užtikrintos skaitymo operacijų saugumo ypatybės „WebKit“. Labiausiai paveiktas posistemis yra „JavaScriptCore“ („WebKit“ „JavaScript“ variklis). Beveik visus ribų patikrinimus galima apeiti, norint savavališkai skaityti už ribų. Tai gali leisti užpuolikui perskaityti savavališką atmintį. Visi tipo patikrinimai taip pat yra pažeidžiami. Pvz., Jei kai kurių tipų 8 poslinkyje yra sveikas skaičius, o kitame – rodyklė 8 poslinkyje, tada užpuolikas galėtų naudoti „Spectre“, kad apeitų tipo patikrinimą, kuris turėtų užtikrinti, kad negalėtumėte naudoti sveiko skaičiaus savavališkai sukurti rodyklė.
„JavaScriptCore“ yra skirta saugiai kalbai virtuali mašina. Turėtų būti įmanoma įkelti nepatikimą „JavaScript“ ar „WebAssembly“ kodą į savo procesą, nerizikuojant, kad proceso atmintis nutekės į „JavaScript“ kodą, išskyrus atvejus, kai jūs aiškiai eksportuojate duomenis į „JavaScript“ per mūsų C arba „Objective-C“ privalomąją API. „Spectre“ sulaužo šią „JavaScriptCore“ ypatybę, nes nepatikimas „JavaScript“ ar „WebAssemble“ dabar turi teorinį kelią nuskaityti visą pagrindinio proceso adresų erdvę.
DOM API ir sistemos API, kurias iškviečia DOM API, taip pat naudoja filialus, kad užtikrintų savo saugumo ypatybes, ir jas galima iškviesti iš „JavaScript“. Taigi „Spectre“ yra ne tik pačios „JavaScriptCore“ ataka, bet ir viskas, ko galima iškviesti iš „JavaScript“.
Samprotavimas apie „Spectre“
Norint suprasti, kaip veikia „Spectre“, naudinga pagalvoti apie tai, kaip saugaus programavimo kalbos operacijos (kaip ir bet kokia nuosavybės prieiga „JavaScript“) vykdomos naudojant „JavaScriptCore“ šiuolaikiniame procesoriuje. Daugelyje diskusijų apie „Spectre“ buvo atliekami ribiniai patikrinimai, todėl šiame skyriuje taip pat nagrinėjamas tas atvejis.
var tmp = intArray[index];
Šiame pavyzdyje laikykime to intArray
mūsų „JavaScript“ varikliui žinoma kaip nuoroda į a Int32Array
bet kad mes to neįrodėme index
yra ribose intArray.length
. Kompiliatorius turės atlikti ribinį patikrinimą, kai jis pavers šią aukšto lygio „JavaScript“ operaciją į žemesnio lygio formą:
if (((unsigned) index) >= ((unsigned) intArray->length))
fail;
int tmp = intArray->vector[index];
Kompiliuojant x86 procesoriuose pateikiamos šios instrukcijos:
mov 0x10(%rsi), %rdx ; %rsi has intArray. This loads
; intArray->vector.
cmp 0x18(%rsi), %ecx ; %ecx has the index. This compares
; the index to intArray->length.
jae Lfail ; Branch to Lfail if
; index >= intArray->length according
; to unsigned comparison.
mov (%rdx,%rcx,4), %ecx ; Load intArray->vector[index].
Šiuolaikiniai procesoriai gali atlikti ribų tikrinimo šaką (jae
) ir paskesnė apkrova (mov (%rdx,%rcx,4), %ecx
) lygiagrečiai. Tai įmanoma, nes:
- Šiuolaikiniai procesoriai profilio šakos. Tokiu atveju jie pastebės, kad šaka visada iškrenta. Tai vadinama šakos numatymas.
- Šiuolaikiniai procesoriai gali sugrąžinti vykdymą. Apkrova po šakos gali būti vykdoma prieš procesoriui patikrinant, ar atšaka iš tikrųjų nukrito. Jei pasirodo, kad filialas yra paimtas, CPU gali anuliuoti viską, kas nutiko tarp filialo susidūrimo ir galutinio patikrinimo. Tai vadinama spekuliacinis vykdymas.
„Spectre“ yra ataka, kuri išnaudoja spekuliacinio vykdymo informacijos nutekėjimą. Apsvarstykite šį kodą:
var tmp = intArray[index];
otherArray[(tmp & 1) * 128];
Centrinis procesorius turi galimybę inicijuoti apkrovas iš pagrindinės atminties į L1 (procesoriaus 1 lygio atminties talpyklą, kuri yra greičiausia ir mažiausia), vykdant spekuliaciškai. Kaip našumo optimizavimas, CPU neatšaukia atkūrimų į L1, kai grįžta spekuliacinis vykdymas. Tai veda prie laiko nutekėjusios informacijos nutekėjimo: šiame kode nurodoma, ar įkeliamas procesorius otherArray[0]
arba otherArray[128]
priklauso nuo tmp & 1
ir vėliau galima nustatyti, kurį procesorių pakrauti spekuliaciškai, nustatant prieigos greitį otherArray[0]
ir otherArray[128]
.
Kol kas pavyzdys susijęs su ribų tikrinimo šakos valdymu. Tai ypač efektyvi „Spectre“ ataka, nes index
elgiasi kaip rodyklė, kuria galima nuskaityti ~ 16 GB atminties aukščiau intArray->vector
. Tačiau „Spectre“ teoriškai gali apimti bet kurią atšaką, užtikrinančią saugumo ypatybes, pavyzdžiui, šakas, naudojamas tipo patikrai „JavaScriptCore“.
Apibendrinti:
- „Spectre“ reikia didelio tikslumo laiko, kad būtų galima pastebėti skirtumą tarp L1 delsos ir pagrindinės atminties delsos.
- „Spectre“ leidžia užpuolikams valdyti šakas. Spekuliacinis vykdymas vykdo šakas pagal praeities istoriją, o užpuolikas gali kontroliuoti šią istoriją. Todėl užpuolikas kontroliuoja, kokias šakas veikia spekuliacinės egzekucijos metu.
- „Spectre“ yra šakos tikrintojo ir informacijos nutekėjimo (tai, ką mes parašėme kaip) inicijavimas
otherArray[(tmp & 1) * 128]
aukščiau). Užpuolikas žino, ar jie laimėjo lenktynes (vienas iš dviejųotherArray
talpyklos eilutės bus L1), todėl ataka veikia tol, kol užpuoliko galimybė laimėti nėra lygi nuliui.
Švelninantis spektrą
„WebKit“ atsakymas į „Spectre“ yra dviejų pakopų gynyba:
- „WebKit“ išjungtas
SharedArrayBuffer
ir sumažintas laikmačio tikslumas. - „WebKit“ pereina prie šakos saugumo tikrinimo be šakos saugumo tikrinimo.
Kai kurie iš šių pakeitimų buvo pristatyti sausio 8 d. Atnaujinimuose, o daugiau tokių pakeitimų toliau rodomi „WebKit“. Likusi šio dokumento dalis išsamiai aprašo mūsų padarinius.
Sumažinti laikmačio tikslumą
Mes sumažiname „WebKit“ laikmačio tikslumą. Šie pakeitimai į bagažinę pateko nuo r226495, ir jie buvo pristatyti sausio 8 d. Naujiniuose.
- Laikmačio tikslumas nuo
performance.now
ir kiti šaltiniai sumažinami iki 1 ms (r226495). - Mes neįgalūs
SharedArrayBuffer
, nes juo galima sukurti didelės skiriamosios gebos laikmatį (r226386).
Mūsų ilgalaikis planas yra padaryti „Spectre“ neįmanomą net ir esant labai ištikimam laikui; reikia toliau dirbti, kad šis kelias vėl būtų įgalintas.
Filialų apsaugos patikrinimai
Nuo tada, kai sužinojome apie „Spectre“, mes tyrėme, kaip atlikti saugumo patikrinimus, nepasikliaujant filialais. Pradėjome pereiti prie šio naujo tipo patikros ir pirmuosius šakos patikrinimus išsiuntėme sausio 8 dienos naujiniuose.
Rodyklės maskavimas
Paprasčiausias šakos saugumo patikrinimo pavyzdys yra masyvo prieigos indekso užmaskavimas:
int tmp = intArray->vector[index & intArray->mask];
Šiuolaikiniai procesoriai nespekuliuoja bitų maskavimu. Jei kaukė pasirenkama taip, kad atitiktų masyvo ilgį, šis švelninimas užtikrina, kad net ir naudodamasis „Spectre“ užpuolikas negali perskaityti masyvo ribų.
Mes įdiegėme indekso maskavimą:
- Įvestos masyvai (r226461),
- „WebAssembly“ atmintinės (r226461, dažniausiai naudojant bendrą kodą su įvestais masyvais),
- Stygos (r226068),
WTF::Vector
(r226068) ir- Paprasti „JavaScript“ masyvai (r225913).
Pakeitimai (1–4) pristatyti sausio 8 d. Naujiniuose. (5) nusileido „WebKit“, bet dar neišsiuntė.
Rodyklės maskavimas dar nėra visiškas išorinės prieigos taisymas. Mūsų dabartiniai indekso maskavimo švelninimai naudoja kaukę, kuri apskaičiuojama apvalinant ilgį iki kitos dviejų galios (ir atimant vieną). Tai vis tiek leidžia skaityti už ribų, tik ne savavališkai atminti.
Dabartiniai mūsų bandymai rodo, kad indekso maskavimas neturi matuojamo poveikio spidometro ir ARES-6 bandymams ir mažiau nei 2,5% „JetStream“ etalonui.
Rodyklės apsinuodijimas
Indekso maskavimą lengva pritaikyti masyvo prieigoms, tačiau daugelis saugumo patikros šakų yra susijusios su objekto tipu, o ne masyvo ribomis. Apsinuodijimas žymekliu yra technika, kurią naudojant galima užtikrinti, kad bet kokio tipo patikrinimas būtų saugus „Spectre“, pakeičiant tikrinamo objekto formą.
Apnuodyti žymeklį reiškia tik atlikti tam tikrą grįžtamąją matematiką, dėl kurios bandymai pasiekti nepavyks, nebent rodyklė yra neapsaugota. Programoje „WebKit“ apsinuodijimas apima vertės, kuri tikrai turi bent vieną bitą, nustatymą aukštose pozicijose, kad prieigos, kurios neatlaisvina, greičiausiai pasieks neporuotą atmintį. „WebKit“ parenka nuodų vertes naudodamas kompiliavimo laiko atsitiktinių skaičių generatorių su daugybe subtilių taisyklių, tačiau norint suprasti požiūrį, tiesiog apsvarstykite 1 << 40
kaip nuodų vertė. Pridėjus vieną terabaitą į galiojantį rodyklę, „MacK“ ir „iOS“ įrenginiuose, tikriausiai ir kitose operacinėse sistemose, „WebKit“ atminties makete bus nepateiktas žymeklis. Yra daug galimų nuodų verčių, kurios turėtų tokį poveikį.
Apsinuodijimas tampa galingiausiu, kai kiekviena statinio žymeklio lauko deklaracija turi unikalią nuodų vertę, o nuodų vertės skiriasi dideliais bitais, todėl apsinuodijus neteisinga verte gaunamas nežymėtas žymeklis.
Apsvarstykite kai kurias klases kaip pavyzdžio apsinuodijimo pavyzdį kaip šakų tipo patikrinimą Foo
priklausanti klasių, dalyvaujančių dinaminėse žemesnėse versijose, remiantis kai kuriais patikrinimais, hierarchijai:
class Foo : public Base {
public:
...
private:
int m_x;
Bar* m_y;
};
Norėdami, kad šios klasės tipo patikros būtų skambančios „Spectre“, mes galime tiesiog perkelti Foo laukus į duomenų struktūrą, kurią nurodo unikaliai užnuodytas rodyklė:
class Foo : public Base {
public:
....
private:
struct Data {
int x;
Bar* y;
};
ConstExprPoisoned<FooDataKey, Data> m_data;
};
Kur FooDataKey
yra unikalus raktas Foo
, kurio pagrindu ConstExprPoisoned<>
apskaičiuos atsitiktinę nuodų vertę kompiliavimo metu. Jei visos šios hierarchijos klasės naudoja laukų apsaugai nukreiptą rodyklę, apsaugančią nuo jų nukreipimo, tai pakanka kaip šakos tipo patikrinimo visų prieigų prie šių tipų. Be to, kad tai puikus „Spectre“ švelninimas, jis taip pat yra naudingas nuotolinio kodo vykdymo sušvelninimas, nes tai apsunkina bet kokio tipo painiavos darymą.
Apsinuodijimas žymekliu kartais nereikalauja jokių papildomų indirektų. „JavaScriptCore“ turi daugybę duomenų struktūrų, kurios maždaug atitinka šį modelį:
struct Thingy {
Type type;
void* data; // The shape of this depends on `type`.
};
Bet kokį tokios duomenų struktūros tipo patikrinimą galima padaryti be šakos nuodijant data
rodyklė pagal nuodų vertę, kuri priklauso nuo type
.
Mes pradėjome konvertuoti „WebKit“ objektų modelius į rodyklių apsinuodijimą (r225363, rr225437, r225632, r225659, r225697, r225857, r226015, r226247, r226344, r226485, r226530), o kai kurie pradiniai rodyklės nuodų atnaujinimo darbai …