Nowy wariant Spectre v2. Czym jest Branch Target Reuse
Spectre wraca w kolejnej odsłonie. Szczegóły techniki nazwanej Branch Target Reuse, w skrócie BTR, przedstawili w publikacji badacze z VUSec oraz Scuola Superiore Sant’Anna. Działanie BTR opiera się na tym, że procesor może pamiętać, jak zachowywał się nieistniejący już kod. W określonych warunkach taka „pamięć” może zostać wykorzystana do odczytywania danych, do których program normalnie nie powinien mieć dostępu.
Nowy wariant potwierdzono na testowanych procesorach Intel, AMD i Arm. Badacze przygotowali również demonstracje dla Linuksa, które pokazują możliwości wycieku danych z pamięci jądra systemu.
Procesor nie lubi czekać
Współczesne procesory są tak szybkie między innymi dlatego, że próbują przewidzieć, co program zrobi za chwilę. Jeśli w danym miejscu program zwykle przechodzi do tego samego fragmentu kodu, procesor może wcześniej przygotować kolejne instrukcje i dzięki temu zaoszczędzić czas.
Czasami jednak przewidywanie okazuje się błędne. Procesor wycofuje wtedy pracę wykonaną „na zapas” i wraca na właściwą ścieżkę. Spectre udowadnia, że nie wszystko znika bez śladu. Błędnie wykonane operacje mogą pozostawić drobne zmiany wewnątrz procesora, a odpowiednio przygotowany atak potrafi wykorzystać je do odtworzenia chronionych informacji.
O podobnym problemie pisaliśmy już wcześniej przy okazji exploita, który obchodził zabezpieczenia Spectre v2 w procesorach Intel i AMD. Więcej na ten temat można przeczytać tutaj.
Co nowego robi Branch Target Reuse?
BTR nie zmienia podstawowej zasady działania Spectre, ale wykorzystuje inny sposób wprowadzenia procesora w błąd. Wcześniejsze warianty często opierały się na takim „uczeniu” procesora, aby zaczął przewidywać niewłaściwy cel skoku.
Branch Target Reuse korzysta natomiast ze starego przewidywania, które procesor już zapamiętał. Program może utworzyć fragment kodu, wykonać go wiele razy, a następnie usunąć. Procesor może jednak nadal przechowywać informacje o tym, dokąd wcześniej prowadził jeden ze skoków.
Jeśli w tym samym miejscu pojawi się nowy kod, CPU może przez bardzo krótką chwilę wykorzystać starą informację. W efekcie zaczyna wykonywać nowy fragment programu w sposób, jakiego aplikacja wcale nie planowała. Taki moment może wystarczyć do użycia mechanizmu znanego ze Spectre.
Dlaczego JIT ma znaczenie?
BTR jest szczególnie interesujący w środowiskach korzystających z JIT, czyli Just-In-Time compilation. To mechanizm używany między innymi przez przeglądarki, maszyny wirtualne i niektóre elementy systemów operacyjnych. Pozwala on tworzyć kod maszynowy już podczas działania programu.
Taki kod może zostać wygenerowany, być używany przez pewien czas, a później usunięty. Zwolniona pamięć może następnie posłużyć do przechowania czegoś innego.
Właśnie tutaj pojawia się warunek potrzebny do BTR. Program widzi już nowy kod, ale procesor może nadal pamiętać informacje związane z tym, co wcześniej znajdowało się w tym miejscu. Powstaje więc różnica między aktualnym stanem programu a tym, co CPU zapamiętał z wcześniejszego wykonania.
Linux, Firefox i GraalVM
Badacze sprawdzili BTR w kilku środowiskach wykorzystujących dynamicznie generowany kod. Wśród nich znalazły się Linux cBPF, Oracle GraalVM oraz SpiderMonkey, czyli silnik JavaScript i WebAssembly używany przez Firefoksa.
Najbardziej kompletne testy przeprowadzono na Linuksie. Specjaliści przygotowali dwa exploity pozwalające na wyciek danych z pamięci jądra na współczesnych procesorach Intela. W jednej z demonstracji udało się odnaleźć hash hasła konta root. Prędkość wycieku wynosiła około 8 bajtów na sekundę.
To niewiele, jeśli myślimy o kopiowaniu dużych plików, ale w takim ataku czasem wystarczy niewielka ilość danych. Klucz, token, hash lub inny sekret może mieć tylko kilkanaście czy kilkadziesiąt bajtów.
W przypadku Firefoksa pokazano działający proof of concept, ale nie przygotowano kompletnego ataku uruchamianego bezpośrednio przez złośliwą stronę internetową.
VUSec opublikował również nagranie prezentujące działanie exploita:
Problem nie dotyczy tylko jednego producenta
Zachowanie potrzebne do przeprowadzenia BTR potwierdzono na testowanych procesorach Intel, AMD i Arm. Nie oznacza to, że wszystkie układy są podatne w identyczny sposób. Skuteczność ataku zależy między innymi od konkretnego procesora, systemu operacyjnego i używanego oprogramowania.
Badania pokazują, że BTR nie jest problemem ograniczonym do jednej firmy czy jednej serii CPU. Wynika raczej z mechanizmów, jakie nowoczesne procesory wykorzystują do przyspieszania pracy.
Poprawki trafiają głównie do oprogramowania
W przypadku BTR część zabezpieczeń można wprowadzić po stronie oprogramowania. Producenci procesorów wskazują na istnienie mechanizmów pozwalających czyścić lub ograniczać stan wykorzystywany do przewidywania skoków.
Linux otrzymał zmiany związane z ponownym używaniem pamięci przez BPF JIT, natomiast Oracle ograniczyło podobne zachowanie w GraalVM. Chodzi przede wszystkim o zminimalizowanie ryzyka zaistnienia sytuacji, w której nowy kod trafia w miejsce nadal powiązane ze starymi przewidywaniami procesora.
Podsumowanie
Branch Target Reuse pokazuje, że mimo wielu lat pracy nad zabezpieczeniami Spectre wciąż pojawiają się nowe sposoby wykorzystania mechanizmów przyspieszających działanie procesorów. Tym razem szczególnie istotne okazało się połączenie predykcji skoków z dynamicznie tworzonym i ponownie używanym kodem. Najważniejsze są dwa wnioski: problem nie ogranicza się do jednego producenta procesorów, a walka z nim w dużej mierze zależy od zmian po stronie oprogramowania. BTR jest kolejnym przykładem na to, że bezpieczeństwo współczesnych systemów opiera się nie tylko na samym kodzie aplikacji, ale również na tym, co dzieje się głębiej – wewnątrz procesora.




