Spectre of the KAISER Meltdown
Napisał: Patryk Krawaczyński
05/01/2018 w Bezpieczeństwo 1 komentarz. (artykuł nr 651, ilość słów: 1281)
W
“2015 roku zaobserwowaliśmy kilka naprawdę poważnych błędów w procesorach Intela i w przyszłości powinniśmy spodziewać się ich więcej” – cytując klasyka. W ciagu ostatnich dni pojawiło się trochę domysłów, histerii i analizy na temat luki, która wpływa na co najmniej kilka generacji procesorów. Wspomniana podatność jest aktywna nie tylko na systemie Linux, ale także na Windows i macOS, a w raz z pojawieniem się poprawek będzie powodowała duże zamieszanie w centrach danych i u dostawców chmur obliczeniowych ze względu na konieczność restartu serwerów i obserwowania wpływu zmian na dotychczasową wydajność środowiska.
W czym jest problem?
Sam problem sprowadza się do wycieku danych o pamięci jądra do przestrzeni użytkownika. Wewnątrz większości nowoczesnych systemów operacyjnych znajdziemy uprzywilejowany jego rdzeń znany jako jądro. Zarządza ono w systemie wszystkim innym tj.: uruchamia i zatrzymuje programy użytkownika; wymusza przestrzeganie ustawień bezpieczeństwa; zarządza pamięcią, aby jeden program nie mógł zabrać jej innemu; kontroluje dostęp do podstawowego sprzętu, takiego jak dyski i karty sieciowe; jednym słowem dzieli i rządzi. Cała reszta – to, co nazywamy “programami użytkowników” działa w tzw. przestrzeni użytkownika, gdzie programy mogą wchodzić ze sobą w interakcje, ale tylko za wspólnym porozumieniem.
Jeśli jeden program mógłby przez przypadek przeczytać (lub, co gorsza zmodyfikować) jakiekolwiek inne dane programu lub zakłócić jego działanie, byłby to poważny problem z zabezpieczeniami; byłoby jeszcze gorzej, gdyby program użytkownika mógł uzyskać dostęp do danych jądra, ponieważ zakłócałoby to bezpieczeństwo i integralność całego systemu. Dlatego jednym z zadań jądra jest ostrożne rozdzielanie przestrzeni użytkownika i jądra, aby programy tego pierwszego nie mogły przejąć kontroli nad systemem i podważyć jego zabezpieczenia przez uruchomienie złośliwego oprogramowania, wykradanie danych, szpiegowanie ruchu sieciowego, czy papranie w ustawieniach sprzętu.
Sam procesor komputera zapewnia wsparcie sprzętowe dla tego rodzaju separacji. W architekturze x86 oraz x64 nazywa się je poziomami uprawnień, które są zaimplementowane i wymuszone przez sam układ. Można je również wykorzystać do oddzielenia jądra od uruchomionych programów użytkownika. Intel nazywa te poziomy pierścieniami, których są cztery; większość systemów operacyjnych używa dwóch z nich: pierścień 0
(najbardziej uprzywilejowany) dla jądra i pierścień 3
(najmniej uprzywilejowany) dla przestrzeni użytkownika. Mówiąc w uproszczeniu – procesy w pierścieniu 0
mogą przejąć kontrolę nad procesami i zasobami znajdującymi się w pierścieniach o wyższym numerze, ale nie na odwrót.
W teorii procesor sam blokuje programy z wyższych pierścieni, które chcą odczytać pamięć z środkowych rubieży zapobiegając w ten sposób problemu podglądania przez programy użytkownika przestrzeni adresowej jądra, co mogłoby spowodować wyciek krytycznych informacji o samym systemie, jego programach i danych. Pod względem technicznym, sekwencja instrukcji maszynowych takich jak ta poniżej, działająca w przestrzeni użytkownika, powinna być zablokowana w kroku 1:
mov rax, [pamięć jądra] ; to zostanie zablokowane - ta pamięć jej chroniona mov rbx, [pamięć użytkownika] ; to zostanie dopuszczone - ta pamięć jej "Twoja"
Analogicznie – zamieniając instrukcje miejscami sekwencja ta zostanie zablokowana w kroku 2:
mov rbx, [pamięć użytkownika] ; to zostanie dopuszczone - ta pamięć jej "Twoja" mov rax, [pamięć jądra] ; to zostanie zablokowane - ta pamięć jej chroniona
Współczesne procesory Intela i AMD obsługują tzw. wykonywanie spekulatywne (ang. speculative execution), dzięki czemu procesor orientuje się, co ma zrobić kilka następnych instrukcji; dzieli je na mniejsze pod-instrukcje i przetwarza je w możliwie innej kolejności od tej w jakiej pojawiły się w programie. Zabieg ten jest stosowany w celu zwiększenia przepustowości. Powolna operacja, które nie ma wpływu na jakiekolwiek wyniki pośrednie może zostać rozpoczęta wcześniej w potoku razem z innymi instrukcjami do wykonania. W innym przypadku inna praca byłaby zablokowana i bezproduktywna, gdyby ta powolna operacja została pozostawiona na końcu listy rzeczy do zrobienia. Powyższy przykład pokazał dwie instrukcje, które są niezależne obliczeniowo, więc nie ma znaczenia, w jakiej kolejności działają. Nawet jeśli ich zamiana miejscami nastąpi w momencie, w którym procesor zainterweniuje, aby zablokować niepoprawną instrukcję (próbującą załadować pamięć z jądra).
Czy kolejność ma znaczenie?
W lipcu 2017 r. niemiecki badacz ds. bezpieczeństwa Anders Fogh przeprowadził testy, aby sprawdzić, czy kolejność rzeczywiście ma znaczenie. Zastanawiało go, co by się stało, gdyby procesor obliczył jakieś wewnętrzne wyniki jako część nielegalnej instrukcji X, użył tych wewnętrznych wyników w obsłudze dopuszczalnej instrukcji Y, a dopiero później oznaczył X jako niedozwoloną. Nawet jeśli obie instrukcje X i Y w rezultacie zostałby zablokowane, czy zostałby ślad po spekulatywnym wykonaniu wewnętrznego wyniku niedozwolonej instrukcji X? Jeśli tak, to czy można coś z tego śladu wykombinować? Zacznijmy od przykładu:
mov rax, [K] ; K jest chronionym adresem jądra and rax, 1 ; mov rbx, [U+rax] ; U jest dopuszczalnym adresem użytkownika
Kod robi następujące rzeczy:
- Załaduj rejestr A z pamięci jądra,
- Zmień A na 0 jeśli jest równe lub na 1 jeśli jest nie równe (dzięki temu zamysł eksperymentu jest prosty),
- Załaduj rejestr B z lokalizacji pamięci U+0 lub U+1, w zależności od A.
W teorii wykonywanie spekulatywne oznacza, że procesor może zakończyć pracę na trzeciej instrukcji przed ukończeniem pierwszej, mimo że cała sekwencja instrukcji zostanie ostatecznie unieważniona i zablokowana z powodu naruszenia uprawień w pierwszej. A, co jeśli skutki uboczne trzeciego kroku mogą zostać odczytane z innych źródeł procesora? W końcu jego zachowanie byłoby nieco inne w zależności od tego, czy wykonanie spekulatywne trzeciego kroku odwoła się do lokalizacji pamięci U lub U+1. Na przykład ta różnica może po prostu pojawić się w pamięci podręcznej procesora – lista ostatnio przywoływanych adresów pamięci oraz ich wartości, które są utrzymywane wewnątrz samego procesora ze względu na wydajność. Innymi słowy, pamięć podręczna może zadziałać jako “wskaźnik” zwany kanałem bocznym (ang. side channel), przez który mogą wyciec tajne informacje z procesora – w tym przypadku odpowiedź na pytanie, czy uprzywilejowana wartość położenia pamięci K była równa lub nie.
Koniec końców w tym przypadku Anders nie mógł odpowiedzieć na pytanie, czy procesor przyglądał się U, czy U+1. Na (nie)szczęście inne, podobne konstrukcje kodu pozwoliły mu wydobyć informacje o pamięci jądra. Innymi słowy, procesory Intela (testy były przeprowadzane na i3-5005u Broadwell) są podatne na atak kanału bocznego na poziomie sprzętowym, który powoduje wyciek uprzywilejowanej pamięci do nieuprzywilejowanych programów.
Jak nastąpiło stopienie widma?
Skoro w powyższej publikacji pojawiły się słowa kluczowe (wyciek, tabele stron, intel) w środowisku bardzo szybko skojarzono to z ruchami wdrażania poprawek dla systemu Linux. Z rosnącym napięciem i coraz większą liczbą plotek Google opublikowało wytłumaczenie całego zjawiska. Otóż ataki o nazwie Meltdown oraz Spectre zgłosiło kilka niezależnych zespołów oraz badaczy już w zeszłym roku. O ich szczegółach technicznych możemy przeczytać na dedykowanych stronach informacyjnych oraz wpisie zespołu Google Project Zero opisującym obydwa ataki. Zarówno Intel, jak i AMD wydały już stosowane oświadczenia. Dla różnych ataków typu Kernel Side-Channel przypisano trzy numery CVE: CVE-2017-5753, CVE-2017-5715 i CVE-2017-5754. Poprawki (FUCKWIT – Forcefully Unmap Complete Kernel With Interrupt Trampolines, aka KAISER – Kernel Address Isolation to have Side-channels Efficiently Removed, aka KPTI – Kernel Page Table Isolation ) dla systemu Linux są już dopracowywane.
Więcej informacji: Further Analyzing The Intel CPU “x86 PTI Issue” On More Systems, More Linux Kernel & GCC Patches Come Out In The Wake Of Spectre+Meltdown, Mitigations landing for new class of timing attack, Meltdown demo – Spying on passwords, Meltdown in Action: Dumping memory
Skrypt do sprawdzenia, czy nas system jest podatny znajdziemy tutaj.