Intel produkuje wadliwe procesory — ale od kiedy? Najwyraźniej od zawsze

Mniej więcej dziesięć lat temu poznałem twórczość geniusza stand-upu, którym był George Carlin. Wśród dziesiątek jego wspaniałych występów, szczególnie dobrze wspominam jeden z ostatnich: „Life worth losing”. Pada tam doskonałe hasło:

„Za każdym razem, gdy ludzkość musi się mierzyć z jakimś problemem, zawsze mam nadzieję, że będzie gorzej. Wy też? Nikt z was nie ma na to ochoty? Czy nie chcecie potajemnie, żeby pożar o którym słyszycie, rozprzestrzenił się i wymknął spod kontroli? Uwielbiam też powodzie!”

Natychmiast przyszło mi ono do głowy, gdy z radością czytałem, zupełnie zresztą niezaskakujące, informacje o nowoodkrytych błędach konstrukcyjnych w procesorach Intela. Jasnym było jednak, że mimo poważnych luk, pozwalających na odczyt pamięci jądra, czy wręcz wyskakiwanie z maszyn wirtualnych, nie będzie mi dane oglądać (z błogim uśmiechem, obejmując swą wybrankę) krajobrazu płonących centrów danych, rozsianych po sparaliżowanym mieście, gdy w tle leci „Where Is My Mind” zespołu The Pixies. 

reklama

Odrzucając owe katastroficzne, choć jakże oczyszczające i niezbędne scenariusze, skierowałem myśli w inną stronę: większość publikacji dotyczących błędów „Meltdown” i „Spectre” utrzymana jest w depresyjnym tonie, ukazującym je jako pierwszy błąd w historii procesorów Intela. Faktem jest jednak, że Intel w zasadzie nigdy nie wydał procesora, który nie byłby pełen błędów. I choć Spectre to pierwsza dziura przekładająca się na problemy z bezpieczeństwem, dawne błędy nie ustępowały jej w swej powadze, a w dodatku były znacznie bardziej żenujące. 

Każdy z „nowożytnych” procesorów Intela jest wraz z upływem czasu opatrywany dokumentami zwanymi Erratą, opisującymi odnalezione błędy, zazwyczaj wraz z metodą mitygowania ich wpływu na kod tworzony przez programistę. Dzisiaj takie informacje są przydatne głównie dla twórców kompilatorów lub bardzo specyficznego kodu HPC, ewentualnie sterowników. Jednakże w mrocznych czasach, w których wysokopoziomowe języki programowania były obliczeniowo bardzo drogie, bezpośrednia rozmowa z procesorem była o wiele częstsza. Zwłaszcza, że zbiór API oferowanego przez MS-DOS był niemal żaden. Znajdowane błędy rzadko były rażącymi katastrofami – w takich sytuacjach procesor prawdopodobnie nie ukazałby się na rynku. Problemy były więc nietypowe, rzadkie i trudne do zaobserwowania. Zatem znajomość erraty nie była wiedzą niezbędną do stworzenia programu działającego na PC, ale od czasu do czasu okazywała się całkiem przydatna. Dzisiaj korzystają z niej twórcy wiernych emulatorów, jak PC.js :)

Oryginalny komputer PC był oparty o przytępiony układ 8088 z 1978 roku. Można się spotkać z poglądem, że był to „prosty” układ, prostszy od 8086 i w porównaniu z takim Coffee Lake, wręcz głupi. Mam wrażenie, że to opinia powtarzana bez zrozumienia przez osoby niekoniecznie zaznajomione z mikroprocesorami. Być może miała ona swoje źródło u doświadczonych programistów, lub legend demosceny, ale 8088 wcale nie jest durną kostką, która prawie nic nie umie. Moje postrzeganie tematu jest zapewne ograniczone przez absolutną niewyuczalność z zakresu mikrokontrolerów i jedynie elementarną, wymęczoną wiedzę z kursu elektroniki, ale naprawdę nie wrzucałbym 8088 do tego samego worka, co „mikrokontrolery”. 

Ze względu na swoją złożoność, błędy w pierwszej sztancy z 1978 zostały wykryte i skorygowane dopiero około 1982 roku. Na czym polegają? Cóż, wyjaśnienie jest dość „niskopoziomowe”, przez co strasznie zabawne. Idzie to mniej więcej tak: Powiedzmy, że chcemy zdjąć daną przechowywaną w rejestrze danych (DX, nie EDX!) i przenieść ją na segment stosu (SS), czyli na wskaźnik na stos. Ta operacja ma na celu zestawianie jakiegoś stosu, ale wykonanie jej nie blokuje możliwości wystąpienia przerwania (INT). Jeżeli ono wystąpi, zajmie ono stos dla siebie i zapewne go zniszczy. Dlatego operacja move ss, dx może być ostatnią operacją wykonaną na procesorze. Aby uniknąć tego ryzyka, konieczne jest zablokowanie przerwań (by ustrzec stos przed marnym losem), czyli operacja cli

Nienawidzę asemblera. Nie mieści mi się w głowie, jak można dobrowolnie chcieć się przejmować takim cyrkiem, jak pilnowanie stosu i wydawać polecenia bezpośrednio do procesora. To jakaś niezrozumiała i absurdalnie pracochłonna orka na ugorze. Przegryzienie się przez powyższe opisy było dla mnie niemal bolesnym przeżyciem, ale mam nadzieję, że udało mi się przedstawić „kaliber” problemu: mowa o nieprzewidywalnie lub błędnie działających operacjach atomowych na procesorze. Możliwych z racji swej natury do uniknięcia, ewentualnie obejścia mało wymagającym trikiem. 

Wraz ze wzrostem złożoności układów, rosła złożoność i/lub liczba problemów. Wskazywało to na fakt, że żadna ilość quality assurance nie pozwoli na zmniejszenie bagażu błędów w kolejnych Intelach. Po prostu zawsze konieczne jest odbębnienie rytualnych 5% błędnie działającego układu. Kostka 80286 miała już fajniejsze problemy, równie niemożliwe do wytłumaczenia, nie będę nawet próbował. Są ujęte w dokumencie „Undocumented iAPX 286 Test Instruction” pochodzącym od Intela i pełnią rolę względnie oficjalnego przyznania się do błędu. A im dalej w las, tym ciekawiej.

Procesor i80386, powszechniej znany jako „386 DX” uchodzi do tej pory za rewolucję. Był to pierwszy procesor 32-bitowy dla pecetów, a jego podstawowy zbiór instrukcji jest wyznacznikiem zgodności z platformą. Bardzo często (acz pod koniec epoki zaczęło się to zmieniać) kod pracujący na „architekturze x86” był synonimiczny właśnie z kodem działającym na 386. Była to opinia utrzymująca się nawet wiele lat po popularyzacji układu 486, lepszego pod każdym względem. Jak na rewolucyjny układ, 386 ulegał zaskakująco powolnej popularyzacji. Rok 1985, powszechnie uznawany za rok wprowadzenia 386 na rynek to data budząca słuszne wątpliwości. W owym roku nie dało się bowiem złożyć ani kupić komputera opartego o ten układ. To w ogóle jest fantastyczna historia: IBM nie umiał sprzedać komputera opartego o nowy procesor (wyprzedził ich Compaq w 1986), a jego współpraca z Microsoftem i szaleńcza pogoń za „nowoczesnym systemem operacyjnym” zakończyła się wydaniem OS/2, który był… 16-bitowy.

W momencie wydania „rewolucyjnego procesora”, definiującego rzekomo platformę PC na nowo, nie istniała na rynku żadna oferta sprzętowa. Nawet, gdy wreszcie pojawiły się pierwsze 32-bitowe pecety, były absurdalnie drogie. Co gorsza, żaden system operacyjny nie był gotowy na ich wykorzystanie. MS-DOS był 16-bitowy, pracował w trybie rzeczywistym. Windows dostał obsługę procesora 386 w 1988 roku, ale była to wyjątkowa, niestandardowa i nieznana nigdy później metoda przejścia w tryb chroniony, niezgodna ze wszystkimi „oficjalnymi” menedżerami pamięci. Poza tym, Windows dalej był środowiskiem 16-bitowym. OS/2 tak samo. To niesamowicie denerwujące. Włożono górę pieniędzy w OS/2, a otrzymano system, który za chwilę będzie trzeba przepisać. Wersja 32-bitowa powstała dopiero w 1992. Windows NT – w 1993 (i nikt go nie chciał). Innymi słowy, przez siedem lat od premiery, procesor 386 nie dostał systemu, który umiałby go wykorzystać. Niesamowite.

Klęska na polu środowisk 32-bitowych doprowadziła do zabawnych efektów. Istotna partia procesorów 386 miała wadę konstrukcyjną. Mowa o innej wadzie, niż ta, która wymusiła sprzedaż układów z zaniżonymi zegarami – tamta dotyczyła bowiem wszystkich procesorów z serii. Wada, którą mam na myśli, rozpoznawano po tajemniczym symbolu na pokrywie procesora: podwójnej dużej sigmie. To niewiele mówiące oznaczenie zastosowano dla odróżnienia procesorów działających poprawnie („sprawdzone, działa”) od pozostałych. Niesprawdzone układy pozostawały nagie, a przetestowane otrzymywały albo podwójną sigmę albo o wiele więcej mówiący opis „16 BIT S/W ONLY". 

Układy Sigma-Sigma potrafiły wykonywać poprawnie operację 32-bitowego mnożenia. Tak jest. Nie chodzi tu o żadne skakanie po stosie, operacje związane z przerwaniami, gubienie flag ani nic z tych rzeczy. Przełomowy 32-bitowy procesor nie potrafił poprawnie wykonywać 32-bitowego mnożenia. Przecież to jest jakiś dowcip. Ale to nie wszystko. Być może oznaczanie poprawnych procesorów sigmą ma teraz sens, ale po co oznaczać wadliwe procesory? Przecież są uszkodzone, wywalą się na pierwszym strzępku 32-bitowego kodu (no, może nie na pierwszym...). Otóż, jak się okazuje, ten kompromitujący błąd procesorów 386 nie był przeszkodą we wprowadzeniu ich na rynek! Dlaczego? No przecież przed chwilą ustaliliśmy, że na rynku nie było żadnego 32-bitowego kodu! Jeżeli więc ten rażący problem nigdy nie wyjdzie na jaw, to przecież można dalej sprzedawać wadliwy układ. Natłukliśmy sporo tych kostek, co się mają zmarnować, prawda? 

Zwłaszcza, że 386 „schodziły” z magazynu dość powoli. I chociaż następca w postaci 486 powstał już w 1989, twórcy oprogramowania musieli brać pod uwagę numery, jakie potrafi wykręcić „rewolucyjny” poprzednik. Dlatego też Windows 95, system operacyjny którego powstanie (z powodu takich właśnie kwiatków) zakrawa na cud, musiał brać poprawkę na takie coś i zamiast po prostu uruchamiać swoje chronione VMM, najpierw wykonywał serię testów-łamańców. Najpierw po to, by odrzucić układy starsze od 386, a potem odsiać te 386’ki, które sprawiały problemy z nowoczesnym kodem. Czyli wywalić blokujące ostrzeżenie dla pierwszych… pięciu generacji. Wszak długie mnożenie nie było jedynym problemem z owym procesorem. Errata dla 386 to już solidna lektura. Wszystkie problemy naturalnie naprawiano w kolejnych „krokach” (stepping) procesora, ale w międzyczasie wprowadzano następne. Problemy wizerunkowe, związane z wadliwością 386 doprowadziły do tego, że chwilowo wstrzymano publikację erraty dla nowych układów. Intel wyszedł z założenia, że wysokopoziomowe oprogramowanie jest już na tyle popularne, że użytkownik końcowy nie potrzebuje wiedzy o błędach w procesorze. Takiej wiedzy może potrzebować na przykład Microsoft albo IBM, ale im można je dostarczyć osobno, za odpowiednim parawanem klauzuli tajności. 

A przecież 486 również nie uchodziły za wzór stabilności. Zwłaszcza w tandemie z efemerycznym złączem VLB potrafiły wykoleić nawet porządny, poprawny elektrycznie sprzęt, kosztujący ciężkie pieniądze. Na szczęście wszystkie te problemy miał wyeliminować „połączony” chipset Intel PCISet (kładący fundament pod nadchodzący standard ATX) o wysokiej skali integracji, współpracujący z procesorem 80586. Od piątki w numerze pochodzi nazwa, pod którą tenże układ jest znany o wiele lepiej: Pentium. Superskalarny, wspomagany arytmetycznie i wysokowydajny procesor Intel Pentium nie miał żadnych znanych z 386 problemów z mnożeniem - to była już melodia przeszłości. Pentium dla odmiany nie umiał dzielić

Ze względu na rozpędzającą się popularyzację pecetów ich powolny proces eksterminowania dedykowanych stacji roboczych np. w środowiskach naukowych, błąd dzielenia w procesorze Pentium stał się hitem branżowych wiadomości. Intel zareagował tak samo, jak na niedawne informacje o Spectre: nic się nie stało, problem występuje tylko przy określonych warunkach i tak dalej. Rozpoczęto jednak akcję wymiany partii wadliwych procesorów. Podobno spotkała się ze skromnym odbiorem, ale kosztowała firmę Intel niezłą górę pieniędzy. Krążą też pogłoski, że wymienione wadliwe kostki były przerabiane na oficjalne breloczki do kluczy. To raczej nieprawda, ale istotnie Intel rozdawał breloczki z „wafelkiem” Pentium obarczonym błędem dzielenia (floating point number division, FDIV). Windows musiał znowu dostosować się do tego, że procesor niekoniecznie działa w pełni tak, jak piszą w instrukcji: Windows NT do wersji 2003 zawierał narzędzie „pentnt”, które informuje użytkownika, czy posiadany procesor zawiera błąd w dzieleniu. O problemie z FDIV informowało nawet CNN, więc była z tego niezła afera, acz nie dowiedziono, żeby za wybieraniem konkurencyjnych układów AMD przemawiało wtedy cokolwiek poza względami finansowymi (jakże to znajomo brzmi…).

Problemy nie skończyły się na FDIV. W 1997 roku okazało się, że da się wysłać do procesora sekwencję, która zablokuje procesor, oczekujący na odebranie wyjątku, który nie może nadejść. Blokujący kod można wykonać w przestrzeni użytkownika trybu chronionego, co oznacza, że blokująca sekwencja F0 0F C7 C8 to w praktyce „suicide button” – mimo, że instrukcja logicznie nie ma sensu, procesor robi, co może, żeby ją wykonać, zamiast wyrzucić bezwarunkowy błąd (invalid opcode) nieobsługiwanej instrukcji. Oczywiście trzeba się trochę natrudzić, żeby złożyć program wykonujący taką instrukcję, kompilator niesprowokowany sam z siebie nie złoży programu w taki sposób. Ale nie zmienia to faktu, że da się doprowadzić do sytuacji, w której komputer po prostu przestaje działać i z takiego stanu może go wybudzić tylko zimny restart. 

Tym razem jednak obyło się bez takiego szału medialnego, głównie dlatego, że ludzie masowo wymieniali komputery na nowoczesne systemy ATX z kasetkowym Pentium II, USB, ACPI i AGP. Pamiętajmy wszak, że w owych czasach trzyletni komputer uchodził za przestarzały złom. Dziś… Cóż, właśnie piszę z komputera z 2010 roku. To staroć bez SATA III i Thunderbolta 3, ale ośmiowątkowy procesor i7, 16GB pamięci i macierz RAID z dysków półprzewodnikowych jakoś sprawiają, że nie odczuwam woli aktualizacji.

Skala problemów z 80386 oraz oryginalnym Pentium była na tyle duża, że można z powodzeniem uznać te procesory za wadliwe produkty, wykazujące błędy na tyle poważne, że nie powinny się ukazać na rynku. Ale nie dość, że sprzedawano jest w powodzeniem i bez wyrzutów sumienia, to jeszcze w globalnej perspektywie „nic się nie stało”. To pokazuje, że o wiele więcej rzeczy musi pójść źle, żeby doprowadzić do globalnych problemów.

Te jednak nadchodzą. Nie mam tutaj najmniejszych wątpliwości. Kluczem do katastrofy nie będą błędy, jak Spectre. Te są bowiem całkiem skomplikowane i nieoczywiste. Nie chodzi w nich np. o to, że można specjalnie spreparowaną instrukcją otrzymać informacje o pamięci. Nic z tych rzeczy – tryb chroniony dalej jest chroniony. Spectre wykorzystuje nieprzewidziane i zignorowane podczas projektowania skutki uboczne procesu zwanego „warunkowym wykonaniem spekulatywnym”, czyli zbiorem czynności wykonywanym przez procesor „na wszelki wypadek”. Jeżeli okażą się przydatne, to super – mamy gotowy wynik, policzony w międzyczasie na boku. Jeżeli okażą się zbędne, to idą do kosza. This is some high level shit. Trzeba się naprawdę nieźle napracować, żeby zdefiniować tak specyficzną klasę ataków na integralność danych. Skomplikowane problemy mają jednak zazwyczaj proste (acz bolesne) rozwiązania. O wiele gorzej sprawa ma się z prostymi problemami, które zazwyczaj mają niewyobrażalnie skomplikowane rozwiązania, o ile da się je w ogóle znaleźć. Takim „prostym problemem” jest Intel Management Engine. 

Wspomniałem już, że nienawidzę asemblera i najchętniej zawsze używałbym wysokopoziomowych języków programowania. Owa postawa nie oznacza jednak braku szacunku dla reguły KISS, która moim zdaniem nie jest regułą, a oczywistością, wnioskiem z rzeczywistości. Dlatego byłem zdumiony, gdy ludzie których uznawałem za rozsądnych twierdzili, że strach przez UEFI to podeście rodem z teorii spiskowych. Co więcej, debata na temat złożoności UEFI nigdy nie nastąpiła, ponieważ show został ukradziony przez kontrowersje związane z Secure Boot. W zasadzie każda dyskusja o UEFI była dyskusją o Secure Boot… aż tu nagle się okazało, że istnieją na wolności takie implementacje „pancernego następcy BIOSu”, które pozwalają na nadpisanie firmware przez użytkownika, z poziomu systemu operacyjnego. Problem z UEFI jest prosty – mechanizm jest zbyt skomplikowany i nie powinien był nigdy w takiej postaci powstać. Rozwiązanie jest straszne: ustawiczne polowanie na problemy i doraźne łatanie skromnego podzbioru obsługiwanych urządzeń.

Właśnie takie problemy sprowadzą na nas katastrofę. Nie pogrążą nas ani skomplikowane słabości złożonych algorytmów, jak Spectre. Przetrwamy też bez większej szkody kłopoty wywołane przez bolesne błędy w implementacji projektu referencyjnego (jak błąd FDIV). Oberwiemy od elementów, których samo istnienie jest problemem. Błędem. Obecnie czymś takim jest Intel ME. O ile sam pomysł jest zaskakująco wiekowy, to jego najnowsza implementacja zakrawa na żart. Samodzielny, odrębny 32-bitowy procesor, pracujący pod kontrolą systemu MINIX 3. Z dostępem do wszystkiego i bez możliwości wyłączenia, nawet na komputerach konsumenckich, gdzie w ogóle nie jest nawet potrzebny! Zakładając niewinnie, że jego wprowadzenie nie było operacją wdrożenia tylnej furtki do wszystkich komputerów na świecie, jego przydatność jest znikoma w porównaniu ze skalą kłopotów, jakie może wprowadzić. Przedsmak tego, co może nas czekać mieliśmy już w 2017 roku: podatność SA-00075 umożliwiała pominięcie uwierzytelniania w AMT. Kto by pomyślał, że stos sieciowy bezpośrednio w procesorze to zły pomysł. Albo podatność ogłoszona pod koniec listopada (SA-00086): arsenał podatności CVE, z których większość wymaga fizycznego dostępu, ale niektóre działają przez sieć. I po co? Żeby laptop Cioci Gieni, zaopatrzony w talerzowy dysk i próbną wersję Office, mógł w przezroczysty sposób aktualizować firmware modemów i udostępniać Wake-On-LAN? To naprawdę takie potrzebne?

Myślę, że wnioski są tutaj dość oczywiste: biorąc pod uwagę dotychczasową historię Intela z jakością swoich układów (innymi słowy: Intel nigdy jeszcze nie wydał nie-wadliwego procesora PC) i zestawiając z powagą funkcjonalną Intel ME, trudno nie mieć wrażenia, że zabezpieczenia będzie się dało obejść. Jedenaście podatności CVE, wymagających nierzadko wymiany całego sprzętu, dowodzi słuszności tych domysłów. Zatem jeżeli w ciągu najbliższych kilku lat nie wybuchnie plaga szkodliwego oprogramowania na nieznaną dotychczas skalę, to nie dlatego, że czarne scenariusze były zbyt paranoidalne. Oznaczać to będzie, że mieliśmy dziwnie dużo szczęścia. Ewentualnie, luki będą wykorzystywane po cichu i przez kilkanaście lat niemal nikt nie będzie o tym wiedział. I na pewno nie ogłoszą tego w CNN.

Był kiedyś taki dowcip:

What does the ”Intel Inside” sticker mean? That you’ve been warned!

Cóż, na pewno architektura Cannonlake okaże się bezproblemowym i superbezpiecznym strzałem w dziesiątkę! Do dwudziestu dwóch razy sztuka! Bo cóż innego pozostaje, może kupić AMD? ;) 

  

sprzęt bezpieczeństwo
reklama

Komentarze