Zastosowanie symulacji bŇĎdów do oceny i
Transkrypt
Zastosowanie symulacji bŇĎdów do oceny i
POLITECHNIKA WARSZAWSKA Wydział Elektroniki i Technik Informacyjnych ROZPRAWA DOKTORSKA mgr inż. Sławomir Chyłek Zastosowanie symulacji bł˛edów do oceny i optymalizacji niezawodności systemów operacyjnych Promotor prof. dr hab. inż. Janusz Sosnowski Warszawa 2014 Podzi˛ekowania Dzi˛ekuj˛e profesorowi Januszowi Sosnowskiemu za opiek˛e przez cały okres studiów doktoranckich oraz nieoceniona˛ pomoc podczas tworzenia niniejszej rozprawy. Dzi˛ekuj˛e Żonie Emilii, za wspieranie mnie oraz wyrzeczenia, które umożliwiły mi napisanie niniejszej pracy. Dzi˛ekuj˛e Koleżankom i Kolegom z Wydziału za wsparcie i pomoc podczas pracy nad doktoratem. Streszczenie Symulacja bł˛edów jest jedna˛ z głównych technik ewaluacji niezawodności oprogramowania. Niniejsza rozprawa poświ˛econa jest adaptacji symulacji bł˛edów w emulatorach systemów komputerowych, co umożliwiło badanie niezawodności oprogramowania systemów operacyjnych oraz tworzenie nowych mechanizmów wykrywania i obsługi bł˛edów. W rozprawie zaprezentowana została metodyka testowania oprogramowania z zastosowaniem emulatora systemu komputerowego. Przedstawione zostały cechy emulacji szczególnie użyteczne przy badaniu niezawodności oraz opisano oryginalne rozszerzenia procesu emulacji o funkcje symulacji bł˛edów i nieinwazyjnego śledzenia wykonania. Omówiony został aspekt masowego wykonania eksperymentów oraz analizowania dzienników wykonania b˛edacych ˛ ich artefaktami. Implementacja opisanej metodyki posłużyła do opracowania oryginalnych metod przeprowadzania eksperymentów porównujacych ˛ różne architektury procesorów, systemy operacyjne, a także pozwoliła przeprowadzić badania ukierunkowane na ewaluacj˛e wrażliwości systemu operacyjnego na bł˛edy wyst˛epujace ˛ w urzadzeniach ˛ systemu komputerowego oraz poszczególnych typach danych systemu operacyjnego: kod, stos, dane alokowane, dane statyczne oraz dane tylko do odczytu. W rozprawie opisano przeprowadzone eksperymenty wraz z wynikami i płynacymi ˛ z nich wnioskami. Przeprowadzone badania pozwoliły na określenie krytycznych komponentów systemu operacyjnego. Uwzgl˛edniajac ˛ ograniczenia oprogramowania wykonywanego w przestrzeni jadra, ˛ zaproponowano oryginalny algorytm obsługi przerwań umożliwiajacy ˛ detekcj˛e i obsług˛e lokalnych bł˛edów, a jego skuteczność została zweryfikowana opracowana˛ metodyka˛ testowania. Zdefiniowano problem odtwarzalności wraz z algorytmem brudnych zasobów stanowiacym ˛ jedno z jego rozwiazań. ˛ Dodatkowo zaprezentowano mechanizm ochrony wskaźników powrotu z funkcji przechowywanych na stosie. Słowa kluczowe: wstrzykiwanie bł˛edów, emulacja, niezawodność oprogramowania, testowanie oprogramowania, systemy operacyjne, problem odtwarzalności, detekcja bł˛edów, wrażliwość na bł˛edy, lokalizacja bł˛edów, tolerowanie bł˛edów. 5 Abstract Adaptation of fault injection technique in assessment and reliability optimization of operating systems Fault injection is one of the most commonly used techniques for software reliability evaluation. This thesis is focused on the subject of integration of fault injection technique into computer system emulation software. The approach enabled research on reliability of operating system’s software and development of novel fault detection and error handling mechanisms. The thesis proposes methodology for testing software with utilization of computer software emulation. Emulation features especially advantageous in reliability evaluation are presented in detail followed by description of original extensions to emulation process: fault injection and nonintrusive execution tracing. The aspects of parallel experiment execution and analysis of experiments’ execution logs was discussed. Implementation of the proposed methodology was utilized to develop original experimental methods for processors’ architectures and operating systems comparison. Dedicated research was focused on evaluation of operating system’s susceptibility to faults in case of faults occurring in computer system’s devices or different types of operating system’s data: code, stack space, dynamically allocated data, static data and read-only data. The thesis includes descriptions of conducted experiments followed by results and conclusions. Performed research enabled identification of most critical components of operating system. While taking into account limitations of code executed in kernel mode a novel algorithm for detecting and handling faults in interrupt procedures was proposed. Its effectiveness was verified with presented testing methodology. The recovery problem was defined along with the dirty resources algorithm as one of its solution. In addition, a method for protecting functions’ return address stored on stack was proposed. Keywords: fault injection, emulation, software reliability, software testing, operating systems, recovery problem, software fault detection, fault sensitivity, software debugging, error tolerance. Spis treści 1. Wprowadzenie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.1. Motywacja do powstania pracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.2. Kierunek badań . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.3. Teza i cel rozprawy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.4. Układ pracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2. Analiza wpływu bł˛edów na działanie systemu komputerowego . . . . . . . . . . . . . . . 17 2.1. Model systemu komputerowego . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.1.1. Model zasobów sprz˛etowych . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 2.1.2. Model oprogramowania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Modele bł˛edów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.2.1. Źródła bł˛edów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.2.2. Charakterystyka modeli bł˛edów . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.2.3. Bł˛edy jednostek przetwarzajacych ˛ . . . . . . . . . . . . . . . . . . . . . . . . 28 2.2.4. Bł˛edy pami˛eci operacyjnej . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 2.2.5. Bł˛edy urzadzeń ˛ zewn˛etrznych . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.3. Mechanizmy zwi˛ekszania niezawodności . . . . . . . . . . . . . . . . . . . . . . . . . 31 2.4. Symulacja bł˛edów w badaniu niezawodności systemów komputerowych . . . . . . . . . 33 2.5. Analiza efektów bł˛edów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.5.1. Scenariusz wystapienia ˛ bł˛edu . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.5.2. Symulowanie bł˛edów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 3. Metodyka symulacji bł˛edów w emulowanym środowisku . . . . . . . . . . . . . . . . . . 43 2.2. 2.6. 3.1. Motywacja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 3.2. Emulacja systemów komputerowych . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 3.3. Zastosowanie emulacji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 3.4. Środowisko zautomatyzowanych testów . . . . . . . . . . . . . . . . . . . . . . . . . . 51 3.4.1. Wybór emulatora systemu komputerowego . . . . . . . . . . . . . . . . . . . . 52 3.4.2. Dokładność emulacji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 3.4.3. Nieinwazyjne śledzenie wykonania . . . . . . . . . . . . . . . . . . . . . . . . 54 3.4.4. Wydajność emulacji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 3.4.5. Metodyka badań . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 3.4.6. Architektura QEFI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 7 3.4.7. Charakterystyka bł˛edów symulowanych w QEFI . . . . . . . . . . . . . . . . . 67 3.4.8. Zastosowanie metodyki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 4. Badania eksperymentalne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 3.5. 4.1. Plan przeprowadzonych eksperymentów . . . . . . . . . . . . . . . . . . . . . . . . . . 71 4.2. Profilowanie wrażliwości na bł˛edy badanej architektury sprz˛etowej . . . . . . . . . . . 74 4.3. Porównanie wrażliwości na bł˛edy różnych architektur sprz˛etowych . . . . . . . . . . . 85 4.4. Porównanie wrażliwości różnych systemów operacyjnych . . . . . . . . . . . . . . . . 90 4.5. Eksperymenty ukierunkowane na jadro ˛ systemu operacyjnego . . . . . . . . . . . . . . 95 4.5.1. Bł˛edy urzadzeń ˛ wejścia/wyjścia . . . . . . . . . . . . . . . . . . . . . . . . . . 96 4.5.2. Zaburzanie kodu, danych statycznych i danych tylko do odczytu systemu operacyjnego . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 4.5.3. Zastosowanie profilowania do zaburzania kodu, stosu oraz danych alokowanych systemu operacyjnego . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 4.6. Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 5. Mechanizmy wykrywania i obsługi bł˛edów . . . . . . . . . . . . . . . . . . . . . . . . . . 117 5.1. Mechanizmy zwi˛ekszajace ˛ niezawodność w systemie operacyjnym . . . . . . . . . . . 117 5.2. Ogólne założenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 5.3. Identyfikacja krytycznych komponentów . . . . . . . . . . . . . . . . . . . . . . . . . 120 5.4. Założenia dotyczace ˛ projektowanych mechanizmów zwi˛ekszania niezawodności . . . . 121 5.5. Zapewnienie spójności kodu wykonywalnego . . . . . . . . . . . . . . . . . . . . . . . 122 5.6. Procedury naprawcze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 5.6.1. Metoda obsługi przerwań procesora dla kodu systemu operacyjnego . . . . . . 125 5.6.2. Algorytm brudnych zasobów . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 5.6.3. Ochrona stosu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 5.6.4. Mechanizmy ochrony danych . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 5.7. Zastosowanie QEFI do optymalizacji niezawodności . . . . . . . . . . . . . . . . . . . 143 5.8. Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 6. Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 6.1. Spostrzeżenia i wnioski . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 6.2. Zastosowania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 6.3. Kierunki dalszych badań . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 Bibliografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 A. Dodatek – specyfikacja opracowanego oprogramowania . . . . . . . . . . . . . . . . . . . 161 A.1. QEFI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 A.1.1. QEMU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 A.1.2. Nadzorca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 8 A.1.3. Ekstraktor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 A.1.4. Eksperyment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 A.1.5. Analizator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 A.2. Zmiany w jadrze ˛ systemu GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 9 1. Wprowadzenie Wraz z upowszechnieniem si˛e komputerów rośnie znaczenie niezawodnego funkcjonowania urzadzeń ˛ cyfrowych. Oczekiwania te zwiazane ˛ sa˛ z coraz wyższymi wymaganiami użytkowników w stosunku do dost˛epności i jakości usług, a także z krytyczna˛ natura˛ zadań powierzonych systemom komputerowym – np. sterowanie układami pojazdów, czy urzadzeń ˛ medycznych. O wadze tego problemu świadczy wiele faktów jak awaria chmury obliczeniowej Amazon EC2 w 2012 roku1 powodujaca ˛ straty finansowe wielu portali internetowych, czy opracowany w 2013 roku raport Amerykańskiej Agencji ds. Żywności i Leków (FDA), ujawniajacy ˛ w Stanach Zjednoczonych w latach 2006-2011 wzrost liczby incydentów zagrażajacych ˛ bezpieczeństwu pacjentów w zwiazku ˛ z usterkami medycznego sprz˛etu komputerowego z 153 do 319 (patrz [6]). Awarie te wystapiły ˛ pomimo nakładów pracy poświ˛econych na zwi˛ekszanie niezawodności tych produktów, natomiast wiele awarii komputerów pozostaje nieodnotowanych lub raporty sa˛ niewystarczajace ˛ do prawidłowego określenia przyczyny problemu (patrz [113]). Dotyczy to w szczególności awarii konsumenckich stacji roboczych, telefonów komórkowych, czy terminali POS2 . Ostatnie badania (patrz [84, 94]) potwierdzaja˛ wag˛e problemu wyst˛epowania awarii zarówno w systemach serwerowych jak i konsumenckich stacjach roboczych. Rodzi to potrzeb˛e opracowywania nowych mechanizmów zwi˛ekszania niezawodności, które moga˛ być stosowane w systemach typu COTS3 . 1.1. Motywacja do powstania pracy Mechanizmy podnoszace ˛ niezawodność sa˛ wykorzystywane w specjalistycznych rozwiazaniach, ˛ majacych ˛ na celu zwi˛ekszenie bezpieczeństwa ludzkiego życia lub minimalizacj˛e finansowych. W krytycznych zastosowaniach systemów komputerowych wi˛eksza niezawodność osiagana ˛ jest poprzez ugruntowane metody realizowane sprz˛etowo lub programowo – np. redundancja, punkty kontrolne (checkpoint), czy n-version programming (patrz 2.3). Jednak wiele z tych technik nie jest wykorzystywanych w komponentach COTS ze wzgl˛edu na wi˛eksze koszty projektowania lub produkcji – przykładowo w komputerach przeznaczonych na rynek konsumencki standardowo nie sa˛ montowane dyski twarde 1 2 3 http://money.cnn.com/2011/04/21/technology/amazon_server_outage/index.htm Ang. Point of Service. Ang. Customer Of The Shelf. 11 wykorzystujace ˛ technologi˛e RAID4 , znaczaco ˛ zmniejszajace ˛ prawdopodobieństwo utraty danych, a przygotowywanie kilku wersji oprogramowania, ocenianych później pod wzgl˛edem wrażliwości na bł˛edy, jest wykorzystywane tylko w specjalistycznych dziedzinach. Wiele systemów komputerowych oferowanych konsumentom pozbawionych jest ochrony przed efektami awarii, a sa˛ także zbudowane z tańszych komponentów bardziej podatnych na usterki (patrz [84]). Sprz˛etowe metody zwi˛ekszania niezawodności sa˛ rozwiazaniami ˛ drogimi w produkcji ze wzgl˛edu na koszt dodatkowych układów montowanych w każdym z produkowanych urzadzeń. ˛ Z tego wzgl˛edu szczególnie interesujace ˛ sa˛ programowe metody zwi˛ekszania niezawodności, które moga˛ być dodane do oprogramowania urzadzenia ˛ bez dodatkowych kosztów i to nie tylko w fazie produkcji, ale również podczas eksploatacji urzadzenia. ˛ Technika˛ wykorzystywana˛ w obszarze badań nad niezawodnościa˛ oprogramowania jest SWIFI5 (patrz [8]). Polega ona na wprowadzaniu bł˛edów do systemu komputerowego metoda˛ programowa˛ w celu ewaluacji jego działania w obliczu zaburzeń. Instytut Informatyki Politechniki Warszawskiej posiada bogate doświadczenie z wykorzystaniem techniki SWIFI (m.in. [37, 38, 42, 96, 97] ). Badania prowadzone w Instytucie pozwoliły na opracowanie wielu narz˛edzi wstrzykiwania bł˛edów, ocen˛e podatności na bł˛edy różnych typów oprogramowania, zaproponowanie rozwiazań ˛ programowych zwi˛ekszajacych ˛ niezawodność, a także zaawansowana˛ analiz˛e dzienników działania systemów komputerowych. Według autora, na podstawie analizy prac prowadzonych w Instytucie Informatyki oraz literatury, istotna˛ dziedzina˛ wymagajac ˛ a˛ badań jest niezawodność oprogramowania systemów operacyjnych. Twierdzenie to jest uzasadnione nast˛epujaco: ˛ — Obserwowana jest ekspansja systemów operacyjnych znanych z zastosowań biurowych/serwerowych do nowych dziedzin [10, 114]. Przykładami takich scenariuszy jest wykorzystanie jadra ˛ systemu operacyjnego GNU/Linux w robotyce, platformie Android, czy systemów z rodziny Windows NT w platformie Windows Phone. Oznacza to, że od tych systemów oczekiwane jest niezawodne funkcjonowanie zarówno w kontrolowanych warunkach farm serwerów jak i urzadzeniach ˛ przenośnych. — Potwierdzone sa˛ przypadki wyst˛epowania przekłamań powodujacych ˛ awari˛e systemów operacyjnych (patrz [84]) w konsumenckich stacjach roboczych. — Wiele przedstawionych w literaturze mechanizmów zwi˛ekszania niezawodności aplikacji wykorzystuje usługi dostarczane przez systemy operacyjne, jednak niewiele jest opisanych mechanizmów zwi˛ekszania niezawodności samego oprogramowania systemów operacyjnych. 4 5 Ang. Redundant Array of Independent Disks. Ang. Software Implemented Fault Injection 12 Zainteresowanie autora zagadnieniem niezawodności systemów operacyjnych dodatkowo zostało wzmocnione udziałem w projekcie realizowanym dla Centrum Badawczo-Rozwojowego Samsung Electronics Polska w Warszawie przez Instytut Informatyki Politechniki Warszawskiej6 . W literaturze można znaleźć niewiele publikacji skupiajacych ˛ si˛e na badaniu niezawodności systemu operacyjnego. Według autora fakt ten wynika z nast˛epujacych ˛ problemów technicznych: — opracowywane narz˛edzia SWIFI dla oprogramowania aplikacji najcz˛eściej polegaja˛ na usługach systemu operacyjnego, co uniemożliwia ich zastosowanie w jadrze ˛ systemu operacyjnego, — opracowywane narz˛edzia symulacji bł˛edów w systemie operacyjnym wymagaja˛ modyfikacji źródeł jadra ˛ systemu operacyjnego – powoduje to de facto badanie niezawodności innego oprogramowania, niż oprogramowanie docelowe (pozbawionego kodu symulujacego ˛ bł˛edy), — ograniczona skalowalność przedstawionych rozwiazań ˛ – do przeprowadzania eksperymentów cz˛esto dedykowany jest osobny system komputerowy; ch˛eć zwi˛ekszenia liczby przeprowadzanych testów wia˛że si˛e z kosztem instalacji i konfiguracji dodatkowych dedykowanych systemów komputerowych. Niemniej badanie niezawodności jadra ˛ systemu operacyjnego i projektowanie mechanizmów zwi˛ekszajacych ˛ niezawodność działajacych ˛ po stronie jadra ˛ systemu operacyjnego wia˛że si˛e z potencjalnymi korzyściami: — systemy operacyjne sa˛ stosowane w wi˛ekszości współczesnych urzadzeń, ˛ co pozwala zwi˛ekszyć ich niezawodność niezależnie od ich specyficznych zastosowań, — możliwość informowania aplikacji o potencjalnych problemach wykrytych przez system operacyjny, — zwi˛ekszenie dost˛epności oraz możliwości diagnostyki systemu komputerowego, — opracowanie mechanizmów zwi˛ekszania niezawodności, wykorzystujacych ˛ kooperacj˛e aplikacji i systemu operacyjnego; podejście takie jest alternatywa˛ dla mechanizmów, gdzie zarówno program o zwi˛ekszonej niezawodności, jak i program realizujacy ˛ usługi zwi˛ekszania niezawodności (np. program dokonujacy ˛ operacji wznowienia działania po awarii na podstawie wcześniej zapisanych wyników cz˛eściowych) sa˛ aplikacjami użytkownika działajacymi ˛ w systemie operacyjnym. Motywacja˛ do powstania rozprawy jest ulepszenie realizacji metod SWIFI do badania niezawodności systemów operacyjnych, w zwiazku ˛ z wymienionymi problemami 6 Projekt Adapting fault injection techniques to improve Samsung mobile products współfinansowany przez Polska˛ Agencj˛e Rozwoju Przedsi˛ebiorczości w ramach działania 1.4 Wsparcie projektów celowych osi priorytetowej 1 Badania i rozwój nowoczesnych technologii oraz działania 4.1 Wsparcie wdrożeń wyników prac B+R osi priorytetowej 4 Inwestycje w innowacyjne przedsi˛ewzi˛ecia. 13 technicznymi, wyst˛epujacymi ˛ w obecnych rozwiazaniach ˛ oraz opracowywanie na tej podstawie nowych mechanizmów zwi˛ekszajacych ˛ niezawodność. W ten sposób autor pragnie wnieść wkład w proces integracji mechanizmów niezawodności w opracowywanie produktów wysokiej jakości. 1.2. Kierunek badań Rozważania opisane w rozprawie bazuja˛ na koncepcji zastosowania emulatora systemu komputerowego do przeprowadzania eksperymentów badania niezawodności. Zastosowanie takiego podejścia pozwala rozwiazać ˛ wymienione powyżej problemy techniczne oraz posiada dodatkowe atuty: możliwe jest zwi˛ekszenie spektrum modeli symulowanych bł˛edów wzgl˛edem rozwiazań ˛ znanych z literatury (np. o modele bł˛edów konkretnych urzadzeń), ˛ a także porównywanie mi˛edzy soba˛ różnych architektur systemów komputerowych i różnych implementacji systemów operacyjnych. Dzi˛eki temu możliwe jest uzupełnienie stanu wiedzy o nowe fakty nieopisane w literaturze. Opracowanie środowiska symulacji bł˛edów, wykorzystujacego ˛ emulator, wymagało dogł˛ebnego poznania szczegółów implementacji zarówno różnych technik emulacji, jak i systemów operacyjnych. Badania przeprowadzone w przygotowanym przez autora środowisku pozwoliły na szczegółowa˛ analiz˛e scenariuszy wystapienia ˛ bł˛edów w systemie operacyjnym. Na tej podstawie autor opracował metody zwi˛ekszania niezawodności implementowane po stronie jadra ˛ systemu operacyjnego, przy czym przyj˛ete zostało założenie integracji opracowywanych mechanizmów z istniejacym ˛ oprogramowaniem. Opracowane mechanizmy bazuja˛ na wzbogaceniu procedur obsługi przerwań zaimplementowanych w systemie operacyjnym o dodatkowe kroki umożliwiajace ˛ kontynuowanie pracy systemu. 1.3. Teza i cel rozprawy Teza˛ pracy jest stwierdzenie: Integracja technik symulacji bł˛edów z emulacja˛ systemu komputerowego umożliwia dokładniejsza˛ ocen˛e wrażliwości na bł˛edy oprogramowania systemu operacyjnego oraz weryfikacj˛e skuteczności mechanizmów zwi˛ekszania niezawodności. Celem rozprawy jest: Opracowanie metodyki, algorytmów oraz narz˛edzi służacych ˛ ocenie niezawodności systemów komputerowych typu COTS oraz zaproponowanie nowych typów mechanizmów 14 zwi˛ekszania niezawodności implementowanych po stronie jadra ˛ systemu operacyjnego, wraz z ocena˛ ich efektywności. Cel rozprawy osiagni˛ ˛ eto poprzez: — opracowanie autorskich rozszerzeń oprogramowania emulatora o funkcje: — symulacji bł˛edów, — nieinwazyjnego śledzenia wykonania, — zaproponowanie oryginalnej metodyki i scenariuszy przeprowadzania eksperymentów z wykorzystaniem emulatora oraz miar służacych ˛ ocenie wrażliwości systemu na bł˛edy, — opracowanie algorytmów i oprogramowania QEFI realizujacego ˛ zaproponowana˛ metodyk˛e, — przeprowadzenie serii eksperymentów z wykorzystaniem opracowanych narz˛edzi: — porównanie wrażliwości na bł˛edy różnych architektur sprz˛etowych, — porównanie wrażliwości na bł˛edy różnych systemów operacyjnych, — zbadanie efektów bł˛edów wyst˛epujacych ˛ w różnych urzadzeniach, ˛ — zbadanie wrażliwości na bł˛edy kodu, danych statycznych, danych tylko do odczytu, danych alokowanych oraz stosu systemu operacyjnego, — zaproponowanie metody zwi˛ekszania niezawodności w przypadku przekłamań w kodzie systemu operacyjnego i jej weryfikacja z zastosowaniem opracowanej metodyki, — opracowanie eksperymentalnej metody ochrony stosu, wykorzystujacej ˛ współprac˛e aplikacji oraz jadra ˛ systemu operacyjnego. Dodatkowo na podstawie obserwacji efektów bł˛edów w kodzie systemu operacyjnego zdefiniowany został problem odtwarzalności oraz opracowano algorytm brudnych zasobów. 1.4. Układ pracy Praca składa si˛e z sześciu rozdziałów, bibliografii oraz dodatku zawierajacego ˛ informacje o opracowanym oprogramowaniu. Rozdział pierwszy stanowi wprowadzenie do tematyki rozprawy oraz zdefiniowanie tezy i celu rozprawy. Rozdział drugi przedstawia tło badań nad niezawodnościa˛ z wykorzystaniem SWIFI oraz znane z literatury mechanizmy zwi˛ekszania niezawodności. Opisane sa˛ modele badanych bł˛edów oraz zdefiniowane sa˛ miary opisujace ˛ wpływ symulowanych bł˛edów na system komputerowy, wykorzystane w dalszej cz˛eści rozprawy. Rozdział trzeci zawiera opis opracowanej metodyki przeprowadzania eksperymentów symulacji bł˛edów z wykorzystaniem emulacji systemu komputerowego. W rozdziale opisane jest opracowane przez autora narz˛edzie QEFI, służace ˛ symulacji bł˛edów w emulowanym systemie komputerowym, profilowaniu działania systemu oraz analizie efektów 15 wprowadzanych bł˛edów. Przedstawiona jest architektura QEFI, uzasadnione sa˛ decyzje projektowe oraz opisane sa˛ algorytmy, służace ˛ realizacji opracowanej metodyki. Rozdział czwarty przedstawia praktyczne wykorzystanie metodyki w serii eksperymentów opartych o opracowane przez autora scenariusze testów. Przedstawiono porównanie wrażliwości na bł˛edy różnych architektur ISA procesorów (patrz 4.3) oraz porównanie różnych systemów operacyjnych (patrz 4.4). Opracowana została seria badań nad wrażliwościa˛ na bł˛edy systemu operacyjnego GNU/Linux – zbadano efekty bł˛edów wyst˛epujacych ˛ w urzadzeniach ˛ systemu komputerowego (patrz 4.5.1) oraz różnych typach danych: kod, stos, dane alokowane, dane statyczne oraz dane tylko do odczytu (patrz 4.5.2, 4.5.3). W opisie eksperymentów wprowadzania bł˛edów w przestrzeń kodu, stosu oraz danych alokowanych, przedstawiono wykorzystanie mechanizmów profilowania zintegrowanych z QEFI. W rozdziale piatym ˛ opisano opracowane mechanizmy zwi˛ekszania niezawodności – metod˛e obsługi przerwań, algorytm brudnych zasobów oraz metod˛e ochrony stosu. Mechanizmy te pozwalaja˛ uniknać ˛ wystapienia ˛ sytuacji wyjatkowej ˛ podczas wykonania oprogramowania i moga˛ być łatwo zintegrowane z systemem operacyjnym GNU/Linux z użyciem mechanizmu kprobes. Skuteczność metody obsługi przerwań została zweryfikowana z użyciem QEFI. Przy opracowaniu algorytmu brudnych zasobów zdefiniowany został problem odtwarzalności – tzn. przywrócenia prawidłowego stanu wykonania programu po wykonaniu serii zaburzonych instrukcji. Skuteczność algorytmu brudnych zasobów została oszacowana poprzez symulacj˛e. Natomiast metoda ochrony stosu prezentuje technik˛e kooperacji aplikacji oraz systemu operacyjnego przy zwi˛ekszaniu niezawodności. Dodatkowo przeprowadzona została dyskusja nad mechanizmami ochrony danych w systemie operacyjnym Rozdział szósty stanowi podsumowanie przeprowadzonych badań. wnioski i spostrzeżenia z przeprowadzonych badań. Rozdział zawiera Przedstawione sa˛ zastosowania zaproponowanych rozwiazań ˛ oraz dalsze kierunki badań. Dodatek zawiera wykaz funkcji opracowanego oprogramowania QEFI wraz z informacja˛ o zmianach w oprogramowaniu QEMU oraz jadrze ˛ systemu GNU/Linux. 16 2. Analiza wpływu bł˛edów na działanie systemu komputerowego Projektowanie mechanizmów zwi˛ekszania niezawodności systemów komputerowych wymaga analizy problemów wyst˛epujacych ˛ podczas eksploatacji. Na podstawie tych danych tworzone sa˛ modele bł˛edów, które wykorzystywane sa˛ przy ewaluacji skuteczności technik obsługi sytuacji wyjatkowych. ˛ W rozdziale przedstawiony jest model systemu komputerowego, stanowiacy ˛ podstaw˛e dalszych rozważań. Nast˛epnie scharakteryzowane sa˛ źródła bł˛edów eksploatacyjnych w systemach cyfrowych, podstawowe techniki badania i zwi˛ekszania niezawodności oraz modele bł˛edów opisujace ˛ efekty zaburzeń w warstwie logicznej. Ostatnia cz˛eść rozdziału poświ˛econa jest miarom niezawodności – wprowadzone miary wykorzystane sa˛ do oceny kondycji systemu komputerowego w rozdziałach 4 oraz 5. 2.1. Model systemu komputerowego Celem systemów komputerowych jest udost˛epnianie określonych funkcji. Sposób ich realizacji zapisany jest w postaci oprogramowania. Oprogramowanie operuje na danych wejściowych i w wyniku wykonania zaimplementowanych algorytmów wytwarza dane wyjściowe. Za wykonanie oprogramowania oraz dostarczenie danych do i z systemu komputerowego odpowiedzialne sa˛ zasoby sprz˛etowe. Powyższa charakterystyka pozwala na zdefiniowanie systemu komputerowego: Definicja 2.1.1. System komputerowy jest to SK ≡ H × S × D, gdzie H – zasoby sprz˛etowe, S – oprogramowanie, D – dane. Zasoby sprz˛etowe składaja˛ si˛e z wielu urzadzeń ˛ o skomplikowanej wewn˛etrznej strukturze. Dzi˛eki sieci połaczeń ˛ oraz opracowanym interfejsom komunikacji możliwe jest współdziałanie urzadzeń ˛ w celu realizacji określonych zadań. W sekcji 2.1.1 przedstawiony jest model tych urzadzeń, ˛ opracowany na potrzeby niniejszej rozprawy. Oprogramowanie systemu komputerowego jest niezmienne podczas eksploatacji systemu (z wyłaczeniem ˛ czynności konfiguracyjnych), natomiast dane sa˛ zmienne i wykorzystywane na bieżaco ˛ przy realizacji określonych funkcji. Oprogramowanie można podzielić według 17 miejsca wykonania (np. procesory ogólnego przeznaczenia1 , procesory specjalistyczne2 , układy wbudowane3 ) oraz poziomu abstrakcji – stos oprogramowania rozciaga ˛ si˛e od oprogramowania bezpośrednio obsługujacego ˛ urzadzenia ˛ elektroniczne do aplikacji użytkownika realizujacych ˛ określone funkcje. W sekcji 2.1.2 szczegółowo przestawiono opracowany model oprogramowania. 2.1.1. Model zasobów sprz˛etowych W systemach komputerowych podstawowymi komponentami sa˛ procesory, pami˛eć oraz urzadzenia ˛ wejścia/wyjścia. Urzadzenia ˛ te współpracuja˛ ze soba˛ za pośrednictwem interfejsów umożliwiajacych ˛ wymian˛e danych. Procesor Procesor jest to układ cyfrowy realizujacy ˛ sekwencyjne wykonanie instrukcji pobieranych z pami˛eci. Zbiór instrukcji procesora określany jest jako ISA4 . Operacje zakodowane przez instrukcje można podzielić według nast˛epujacych ˛ kategorii: ładowanie danych do pami˛eci, manipulowanie danymi (wykonywanie obliczeń), zapisywanie danych w pami˛eci, instrukcje sterujace ˛ (instrukcje skoku i warunkowe) oraz instrukcje specjalne (np. instrukcje opróżnienia pami˛eci podr˛ecznej). Procesor dysponuje rejestrami – sa˛ to komórki pami˛eci wykorzystywane do przechowywania pośrednich wyników obliczeń oraz stanu procesora. Można wyróżnić rejestry danych, adresowe, ogólnego przeznaczenia, zmiennoprzecinkowe, wektorowe oraz specjalne (patrz [56]). Procesor wyposażony jest również w mechanizm obsługi przerwań, pozwalajacy ˛ na wstrzymanie aktualnie wykonywanego kodu i wykonanie przez procesor kodu procedury obsługi przerwania. Przerwania moga˛ być zgłaszane przez: urzadzenia ˛ zewn˛etrzne (np. sygnalizowane jest w ten sposób nadejście nowych danych), zegary (wykorzystywane przy implementacji systemów z podziałem czasu), procesor (sa˛ to wyjatki ˛ procesora wywołane wykonaniem przez program niedozwolonej operacji) lub wykonanie specjalnej instrukcji przerwania programowego. Przedstawiony model procesora jest modelem logicznym. Współczesne procesory w celu przyśpieszenia wykonania dysponuja˛ dodatkowymi układami realizujacymi ˛ specjalizowane zadania: potok wykonania, układ przewidywania skoków, superskalarne jednostki wykonawcze oraz zwielokrotnienie rejestrów. Elementy mikroarchitektur˛e procesora (patrz [51]) i służa˛ przyśpieszeniu jego pracy. te stanowia˛ Integralna˛ cz˛eść procesora stanowi również pami˛eć podr˛eczna. Jest to mechanizm buforowania danych i instrukcji przechowywanych w pami˛eci operacyjnej w pami˛eci o krótszym czasie dost˛epu. 1 Współcześnie konstruowane sa˛ systemy wieloprocesorowe, gdzie system komputerowy wyposażony jest kilka fizycznych procesorów, a każdy z nich pełni funkcj˛e jednego lub wi˛ecej procesorów logicznych. 2 Np. Układy graficzne GPU (Ang. Graphics Processing Unit). 3 Np. kontrolery RAID. 4 Ang. Instruction Set Architecture. 18 Rozwiazanie ˛ to zostało wprowadzone z uwagi na duży koszt wytworzenia pojemnej pami˛eci o krótkim czasie dost˛epu. lokalności odwołań. Wykorzystane zostało tu zjawisko czasowej i przestrzennej Pami˛eci podr˛eczne organizowane sa˛ w hierarchiczne struktury – najcz˛eściej wykorzystywane sa˛ dwa lub trzy poziomy pami˛eci podr˛ecznej, gdzie każdy kolejny poziom charakteryzuje si˛e wi˛eksza˛ pojemnościa˛ oraz dłuższym czasem dost˛epu. Dost˛ep do wymienionych układów procesora jest niemożliwy z poziomu wykonywanych programów (wyjatkiem ˛ jest specjalna instrukcja procesora wymuszajaca ˛ unieważnienie zawartości danych w pami˛eci podr˛ecznej). Warto zaznaczyć, że we współczesnych procesorach stosuje si˛e wi˛ecej, niż jeden rdzeń wykonania, co pozwala na zwi˛ekszenie wydajności systemu. Rdzenie te posiadaja˛ wspólna˛ pami˛eć podr˛eczna˛ i połaczone ˛ sa˛ jedna˛ szyna˛ danych do reszty systemu. Dodatkowo każdy z rdzeni może być wyposażony w technologi˛e hyper threading, która powoduje, że pojedynczy rdzeń jest widoczny dla systemu operacyjnego jako dwie wirtualne jednostki wykonawcze. Technologia ta polega na zwielokrotnieniu niektórych zasobów procesora w taki sposób, że możliwe jest przechowywanie dwóch kontekstów wykonania. W przypadku, gdy jedna jednostka wykonania zostaje wstrzymana (np. podczas oczekiwania na dane pobierane z pami˛eci) rdzeń przełacza ˛ si˛e na kontekst drugiej jednostki wykonania, umożliwiajac ˛ w ten sposób realizacj˛e równolegle dwóch zadań. Pami˛eć Pami˛eć realizuje funkcj˛e przechowywania danych. Można wyróżnić pami˛eć ROM5 oraz RAM6 . Pami˛eci ROM służa˛ przechowywaniu danych tylko do odczytu – sa˛ to np. procedury startowe systemu komputerowego. Natomiast pami˛eć RAM jest pami˛ecia˛ ogólnego przeznaczenia umożliwiajac ˛ a˛ zapis oraz odczyt danych. Pami˛eć RAM sa˛ nazywane również pami˛ecia˛ operacyjna˛ w odróżnieniu od innych, specjalizowanych typów pami˛eci (np. pami˛eć podr˛eczna procesora). Istotnym układem wykorzystywanym w obsłudze pami˛eci jest MMU7 – jest to urzadzenie ˛ odpowiedzialne za mechanizm pami˛eci wirtualnej, tworzacy ˛ dla każdego z programów wykonywanych przez procesor osobna˛ przestrzeń adresowa.˛ Obecnie układ MMU stanowi integralna˛ cz˛eść procesora. Urzadzenie ˛ to w ścisłej współpracy z systemem operacyjnym dzieli pami˛eć na strony i zarzadza ˛ ich stanem (m.in. wolna, załadowana, w pliku wymiany) oraz prawami dost˛epu (strona zawiera wykonywalny kod, dane, dane tylko do odczytu). Urzadzenia ˛ wejścia/wyjścia Systemy komputerowe wyposażane sa˛ w dodatkowe urzadzenia ˛ realizujace ˛ funkcje komunikacyjne, multimedialne, wskazujace ˛ oraz pami˛eci masowej. Poszczególne urzadzenia ˛ 5 6 7 Ang. Read Only Memory. Ang. Random Access Memory. Ang. Memory Management Unit. 19 systemu komputerowego wymieniaja˛ dane z procesorem oraz pami˛ecia˛ z zastosowaniem magistral. Współpraca procesora oraz urzadzeń ˛ wejścia/wyjścia realizowana jest przez przerwania oraz mechanizm Memory mapped I/O, czyli przypisanie cz˛eści przestrzeni adresowej dost˛epnej dla procesora bezpośrednio do rejestrów urzadzeń ˛ zamiast do pami˛eci operacyjnej. 2.1.2. Model oprogramowania Oprogramowanie systemu komputerowego określonych przez twórców algorytmów. służy przetwarzaniu danych według Jest ono zapisane w postaci zestawu instrukcji wykonywanych przez procesor – zbiór instrukcji nazywany jest również kodem programu. W celu realizacji swoich zadań oprogramowanie wykorzystuje pami˛eć. Można wyróżnić kilka typów pami˛eci ze wzgl˛edu na przechowywane dane: stos programowy, pami˛eć statyczna,˛ pami˛eć tylko do odczytu oraz pami˛eć alokowana.˛ Stos programowy służy jako pami˛eć przechowujaca ˛ dane tymczasowe obliczeń, gdy jest ich zbyt wiele, aby zostały zapisane w rejestrach procesora. Dodatkowo wykorzystywany jest on w programowaniu wysokopoziomowym, pozwalajac ˛ na hierarchiczne wywołania procedur. Pami˛eć statyczna sa˛ to obszary pami˛eci stałego rozmiaru dost˛epne na każdym etapie obliczeń pod tym samym adresem. W pami˛eci tego typu przechowywane sa˛ dane globalne – sa˛ to dane dost˛epne na każdym etapie wykonania programu. Pami˛eć tylko do odczytu zawiera niezmienne podczas obliczeń dane. Mi˛edzy innymi jest to kod programu, zakodowane obrazy wyświetlane użytkownikowi na ekranie, czy stałe napisowe, b˛edace ˛ szablonami komunikatów wypisywanych podczas interakcji z programem. Pami˛eć alokowana jest przydzielana w trakcie obliczeń według potrzeb wykonywanego algorytmu. Charakteryzuje si˛e zmiennym rozmiarem oraz tym, że jest przyznawana przez mechanizmy alokacji pami˛eci systemu operacyjnego spośród dost˛epnej w danej chwili puli wolnej pami˛eci. Istnieje wiele algorytmów alokacji pami˛eci, które różnia˛ si˛e czasami alokacji oraz stopniem fragmentacji pami˛eci8 . Opracowane sa˛ również zaawansowane techniki zarzadzania ˛ pami˛ecia,˛ pozwalajace ˛ na automatyczne zwalnianie niewykorzystywanej pami˛eci (garbage collection), jednak nie sa˛ one wykorzystywane w każdym rodzaju oprogramowania ze wzgl˛edu na niedeterministyczny charakter działania. Dynamika alokacji oraz lokalność odwołań jest ściśle zwiazana ˛ z realizowanymi algorytmami oraz wykorzystywanymi strukturami danych. Przykładowo alokacja danych na potrzeby 9 listowej struktury danych jest wykorzystana przy każdym dodawaniu nowego elementu, a także przeszukiwanie kolejno w˛ezłów listy powoduje dost˛ep do wielu miejsc w pami˛eci (każdy 8 Fragmentacja powstaje w przypadku dzielenia przez algorytm alokacji pami˛eci na bloki o stałym rozmiarze. Kiedy blok jest wykorzystywany na alokacj˛e pami˛eci o mniejszym rozmiarze, niż rozmiar bloku – w ten sposób niewykorzystana cz˛eść pami˛eci staje si˛e niedost˛epna. 9 Opis listowej struktury danych dla j˛ezyka C++: http://www.cplusplus.com/reference/list/list/ 20 w˛ezeł jest alokowany osobno i miejsce jego położenia w pami˛eci jest zależne od algorytmu alokacji). Natomiast zastosowanie wektorowej struktury danych10 pozwala na redukcj˛e liczby alokacji oraz przeglad ˛ kolejnych elementów struktury danych, charakteryzuje si˛e liniowym dost˛epem do kolejnych adresów pami˛eci (niemniej zysk ten obarczony jest wi˛eksza˛ złożonościa˛ obliczeniowa˛ przy usuwaniu elementów z wektora, w zwiazku ˛ z koniecznościa˛ przeniesienia elementów znajdujacych ˛ si˛e za usuwanym elementem w nowa˛ lokalizacj˛e11 ). Oprogramowanie systemu komputerowego można podzielić na trzy rodzaje: oprogramowanie wbudowane (firmware), system operacyjny oraz aplikacje użytkownika. Firmware jest oprogramowaniem dedykowanym dla poszczególnych urzadzeń ˛ i jest wykonywany przez układy elektroniczne stanowiace ˛ integralna˛ cz˛eść tych urzadzeń. ˛ Natomiast oprogramowanie systemu operacyjnego i aplikacji użytkownika wykonywane jest przez procesor systemu komputerowego. Istnieja˛ także metody pozwalajace ˛ na wykonywanie specjalnie zaprojektowanych programów na procesorach specjalizowanych karty graficznej w celu osiagni˛ ˛ ecia wi˛ekszej wydajności12 , jednak oprogramowanie tego typu nie jest rozważane w niniejszej rozprawie. Poniżej przedstawiona jest charakterystyka wymienionych typów oprogramowania zawierajaca ˛ opis struktury, funkcji oraz wzajemnych interakcji pomi˛edzy modułami programowymi. Oprogramowanie wbudowane Oprogramowanie wbudowane w komputerach typu COTS wyst˛epuje w wielu urzadzeniach ˛ – np. kartach graficznych, kontrolerach RAID, dyskach twardych, czy płytach głównych. Oprogramowanie to charakteryzuje si˛e wysokim stopniem specjalizacji – jego głównym celem jest zapewnienie poprawnej pracy obsługiwanych urzadzeń. ˛ Przykładowo zadaniem oprogramowania wbudowanego w dyski twarde jest realizacja strategii odczytu danych z wyprzedzeniem do pami˛eci podr˛ecznej oraz opóźnionego zapisu13 . Wspólna˛ cecha˛ oprogramowania wbudowanego jest to, iż rzadko jest modyfikowane w produkcyjnym cyklu życia urzadzenia. ˛ Jeżeli aktualizacja jest konieczna, to operacja ta wymaga przeprowadzenia dedykowanej procedury dla każdego typu sprz˛etu. Oprogramowanie wbudowane wykonywane jest niezależnie od głównego procesora systemu komputerowego przez układy elektroniczne poszczególnych urzadzeń ˛ (np. dysku twardego, adaptera sieciowego). Komunikacja natomiast z zewn˛etrznymi układami odbywa si˛e 10 Opis wektorowej struktury danych dla j˛ezyka C++: http://www.cplusplus.com/reference/vector/vector/ Niemniej dzi˛eki lokalności danych składowanych w wektorze czas usuni˛ecia losowo wybranego elementu z listy może być mniejszy, niż w przypadku listy: http://www.baptiste-wicht.com/2012/12/cpp-benchmark-vector-list-deque/ 12 Np. technologia CUDA umożliwia wykonanie oprogramowania na procesorze GPU – http://www.nvidia.com/object/cuda_home_new.html. 13 Funkcja ta polega na grupowaniu i zmianie kolejności żadań ˛ zapisania danych na dysk w celu optymalizacji operacji wykonywanych przez głowic˛e dysku twardego. 11 21 przez układy sprz˛etowe np. magistrale lub bezpośrednie przyłaczenie ˛ do przestrzeni adresowej procesora (Memory mapped I/O). System operacyjny System operacyjny jest oprogramowaniem pośredniczacym ˛ mi˛edzy zasobami sprz˛etowymi oraz oprogramowaniem użytkownika – posiada pełen dost˛ep do zasobów sprz˛etowych i udost˛epnia je aplikacjom użytkownika za pośrednictwem ujednoliconych interfejsów programistycznych (patrz [103]). Poniżej jako system operacyjny rozważane jest przede wszystkim jadro ˛ systemu operacyjnego. Aplikacje narz˛edziowe dostarczane wraz z systemem operacyjnym nie różnia˛ si˛e sposobem komunikacji z jadrem ˛ od pozostałych aplikacji użytkownika. System operacyjny wyposażony jest w szereg mechanizmów tworzacych ˛ środowisko wykonania aplikacji użytkownika. Podstawowym mechanizmem zaimplementowanym we współczesnych systemach operacyjnych jest mechanizm procesów. Proces jest to instancja wykonania programu wraz z przypisanymi do niej zasobami. System operacyjny odpowiedzialny jest za załadowanie kodu programu dla każdego procesu, a nast˛epnie przydziela zasoby takie jak czas procesora, pami˛eć, dost˛ep do pami˛eci masowej lub innych urzadzeń. ˛ Procesy sa˛ zorganizowane w struktur˛e drzewiasta,˛ gdzie każdy proces jest rodzicem dla uruchomionych przez siebie procesów (dzieci), a korzeniem drzewa jest specjalny proces uruchamiany przez system operacyjny. W ramach procesu może być uruchomionych wiele watków ˛ – podstawowa jednostka wykonywania, dysponujaca ˛ własnym zestawem rejestrów oraz stosem programowym współdzielaca ˛ pami˛eć z pozostałymi watkami ˛ w ramach procesu. Zastosowanie watków ˛ oraz procesów pozwala na przetwarzanie równoległe, co dzi˛eki zastosowaniu procesorów wielordzeniowych pozwala na równoczesne wykonanie kilku programów, zwi˛ekszajac ˛ w ten sposób wydajność systemu. Pozostałe usługi realizowane przez system operacyjny to: zarzadzanie ˛ procesami (np. wstrzymywanie/wznawianie wykonania), przydział czasu procesora poszczególnym procesom, synchronizacja i komunikacja mi˛edzyprocesowa, mechanizm sygnałów, zarzadzanie ˛ pami˛ecia,˛ obsługa urzadzeń ˛ peryferyjnych, realizacja połaczeń ˛ sieciowych, obsługa systemu plików. Całość usług dostarczanych przez system operacyjny stanowi środowisko wykonania dla aplikacji użytkownika. Aplikacje użytkownika komunikuja˛ si˛e z systemem operacyjnym za pośrednictwem wywołań systemowych. Procedura obsługi żadań ˛ aplikacji użytkownika składa si˛e z nast˛epujacych ˛ kroków (kursywa˛ zapisane sa˛ kroki wykonywane przez oprogramowanie systemu operacyjnego): 1. odłożenie na stos programowy parametrów wywołania systemowego, 2. wykonanie dedykowanej instrukcji przerwania programowego, 3. procesor przechodzi z trybu użytkownika do trybu systemu operacyjnego, 4. odczytanie parametrów wywołania systemowego, 22 5. obsługa wywołania, 6. zastapienie ˛ parametrów wywołania systemowego wynikiem wywołania, 7. powrót do trybu użytkownika i wznowienie wykonania. Oprócz wspomnianych przerwań wywołań systemowych system operacyjny obsługuje również przerwania sprz˛etowe oraz przerwania wywołane sytuacjami wyjatkowymi. ˛ Przerwania sprz˛etowe służa˛ do obsługi sygnałów pochodzacych ˛ z urzadzeń ˛ zewn˛etrznych lub magistrali danych – np. klawiatura systemowa, kontroler DMA14 . Obsługa przerwania sprz˛etowego najcz˛eściej oznacza odebranie danych z urzadzenia ˛ zewn˛etrznego i przekazanie ich do oczekujacego ˛ na nie procesu. Sytuacje wyjatkowe ˛ zgłaszane sa˛ przez procesor w przypadku naruszenia zasad bezpieczeństwa lub wykonania nieprawidłowych operacji. Cz˛eść sytuacji wyjatkowych ˛ jest krytyczna i nie pozwala na dalsze wykonanie kodu – np. wyjatek ˛ dzielenia przez zero lub próba zapisu do pami˛eci tylko do odczytu. Przykłady przerwań, które system operacyjny może obsłużyć, to pułapka debug (służy do wstrzymania wykonania procesu i przekazania sterowania do oprogramowania debuggera w celach diagnostycznych), czy bład ˛ stronicowania15 (ang. page fault). Przy zarzadzaniu ˛ pami˛ecia˛ procesor współpracuje z układem MMU opisanym w 2.1.1. W przypadku udanej obsługi sytuacji wyjatkowej ˛ wykonywanie kodu jest wznawiane od instrukcji, która wywołała przerwanie. Jeżeli obsługa nie jest możliwa, system operacyjny awaryjnie kończy działanie bł˛ednego programu. Gdy źródłem bł˛edu jest kod systemu operacyjnego implementowane sa˛ różne strategie działania: np. systemy operacyjne z rodziny Windows wyświetlaja˛ niebieski ekran z informacjami diagnostycznymi bł˛edu i wymagany jest restart systemu komputerowego, natomiast systemy z rodziny Linux wypisuja˛ informacje diagnostyczne na wszystkich dost˛epnych konsolach i kończa˛ działanie watku, ˛ na rzecz którego wykonywany był kod zgłaszajacy ˛ żadanie ˛ – restart systemu nie jest wymagany, jednak system komputerowy może działać niestabilnie lub nie odpowiadać na żadania. ˛ Procedura obsługi sytuacji wyjatkowej ˛ w systemie operacyjnym, w przypadku niepowodzenia przy jej obsłudze, zbiera możliwie najwi˛ecej danych o kontekście wystapienia ˛ wyjatku ˛ i wypisuje je na ekran. Dane te moga˛ zawierać m.in. typ zgłoszonego wyjatku, ˛ zawartość rejestrów procesora, załadowane moduły systemu operacyjnego, dane procesu, czy stos wywołań funkcji (ang. stack-trace). System operacyjny może być rozszerzany o dodatkowe funkcje poprzez ładowane w trakcie działania systemu moduły. Moduły moga˛ być wykorzystane do rozszerzenia zbioru wywołań systemowych, implementacji nowych mechanizmów w jadrze ˛ systemu operacyjnego (np. nowego system plików), jednak najcz˛estszym wykorzystaniem jest dostarczenie dla systemu operacyjnego sterowników – sa˛ to specjalne programy stanowiace ˛ 14 Ang. Direct Memory Access Jest to cz˛eść mechanizmu pami˛eci wirtualnej, sygnalizujaca ˛ dost˛ep do pami˛eci wirtualnej niedost˛epnej w danej chwili w pami˛eci fizycznej, a obsługa polega na załadowaniu przez system żadanej ˛ strony pami˛eci z pliku wymiany. 15 23 łacznik ˛ mi˛edzy systemem operacyjnym, a konkretnym urzadzeniem. ˛ Zadaniem sterowników jest implementacja określonego interfejsu zdefiniowanego w systemie operacyjnym dla danego typu urzadzenia, ˛ jednocześnie oprogramowujac ˛ specyficzny dla danego typu urzadzenia ˛ protokół wymiany danych, który może być różny dla urzadzeń ˛ dostarczanych przez różnych producentów. Istnieje kilka koncepcji konstrukcji systemu operacyjnego. Podstawowe z nich to architektura jadra ˛ monolitycznego oraz mikrojadra. ˛ W ramach architektury monolitycznej sterowniki oraz wszystkie usługi sa˛ integralna˛ cz˛eścia˛ jadra ˛ systemu operacyjnego. W przypadku mikrojadra ˛ kod wykonywany w przestrzeni jadra ˛ systemu operacyjnego jest ograniczony do minimum – sterowniki oraz inne usługi implementowane sa˛ jako aplikacje wykonywane w przestrzeni użytkownika, komunikujace ˛ si˛e z jadrem ˛ z użyciem komunikatów. Istotnym zagadnieniem sa˛ mechanizmy alokowania pami˛eci w systemach operacyjnych. Istnieje wiele mechanizmów wyspecjalizowanych do obsługi różnych żadań. ˛ Można wyróżnić dwa główne mechanizmy alokowania pami˛eci – alokowanie na potrzeby współpracy ze sprz˛etem oraz alokowanie na potrzeby obliczeń. Mechanizm alokacji pami˛eci do wykorzystania ze sprz˛etem musi spełniać nast˛epujace ˛ wymagania: 1. szybkość – watek ˛ wywołujacy ˛ alokacj˛e nie może być uśpiony w oczekiwaniu na alokacj˛e, 2. przydzielona pami˛eć musi być ciagła ˛ w sensie adresów fizycznych. Wymaganie 1. jest zwiazane ˛ z koniecznościa˛ sprawnej obsługi urzadzeń ˛ – alokacje cz˛esto sa˛ wywoływane w procedurach obsługi przerwań generowanych przez urzadzenia ˛ w celu przygotowania pami˛eci na dane przychodzace ˛ od urzadzeń. ˛ Powolna alokacja w tym scenariuszu może spowodować problemy wydajnościowe. Natomiast wymaganie 2. wynika z zastosowania techniki DMA16 , która pozwala na przesyłanie danych bezpośrednio z urzadzenia ˛ (np. dysku twardego) do pami˛eci RAM – wykorzystanie pojedynczego, ciagłego ˛ bloku pami˛eci fizycznej pozwala na unikni˛ecie wielokrotnego programowania kontrolera DMA. Implementacje tego mechanizmu alokacji zazwyczaj narzucaja˛ alokowanie bloków pami˛eci o stałym rozmiarze, co może powodować fragmentacj˛e pami˛eci. Alokacja na potrzeby obliczeń nie podlega takim restrykcjom jak alokacja pami˛eci dla sprz˛etu. Może wykorzystywać wolniejsze algorytmy alokacji, które gwarantuja˛ mniejsza˛ fragmentacj˛e. Ten mechanizm alokacji stosowany jest do przydzielania pami˛eci np. dla kodu, stosu i danych procesów użytkownika. Oprócz wymienionych głównych mechanizmów alokacji istnieja˛ również inne specjalistyczne mechanizmy. 16 Przykładowo sa˛ to mechanizmy zoptymalizowane pod Ang. Direct Memory Access. 24 katem ˛ przechowywania danych tymczasowych (cache), czy pozwalajace ˛ na wykorzystanie rozszerzonych przestrzeni adresowych17 . Aplikacje użytkownika Aplikacje użytkownika sa˛ to procesy uruchomione w systemie operacyjnym. Realizuja˛ one główne zadania powierzone systemom komputerowym: np. środowisko stacji roboczej, serwer WWW, czy serwer baz danych. Aplikacje te wykorzystuja˛ do swojego działania środowisko stworzone przez system operacyjny: systemy plików, mechanizmy alokacji pami˛eci, komunikacj˛e mi˛edzyprocesowa,˛ interfejsy do urzadzeń ˛ sieciowych, mechanizm bibliotek współdzielonych. Systemy plików pozwalaja˛ na zapis oraz odczyt plików na urzadzeniach ˛ takich jak dyski twarde, czy pami˛eci flash. Dzi˛eki abstrakcji systemu operacyjnego aplikacja użytkownika wykorzystuje jeden interfejs programistyczny niezależnie od typu urzadzenia ˛ przechowujacego ˛ dane. Mechanizm alokacji pami˛eci pozwala na wykorzystanie przez procesor dowolnej ilości pami˛eci z przestrzeni adresowej w celu realizacji swoich zadań. System operacyjny udost˛epnia pami˛eć z wykorzystaniem mechanizmu pami˛eci wirtualnej, co pozwala na wykorzystanie przez procesy wi˛ekszej ilości pami˛eci, niż jest dost˛epna w systemie komputerowym. Komunikacja mi˛edzyprocesowa pozwala na wymian˛e danych mi˛edzy procesami (potoki, wiadomości, pami˛eć współdzielona), synchronizacj˛e (semafor, mutex) oraz przesyłanie sygnałów. Dzi˛eki tym mechanizmom możliwe jest koordynowanie pracy wielu procesów. Interfejsy sieciowe pozwalaja˛ na oprogramowanie komunikacji z innymi systemami komputerowymi. Służa˛ zarówno do udost˛epniania usług jak i korzystania z usług innych systemów komputerowych. Ze wzgl˛edu na duży stopień skomplikowania oprogramowania opracowana została możliwość modularyzacji kodu w postaci bibliotek. Biblioteki moga˛ być powiazane ˛ z programem statycznie lub dynamicznie. Statyczne biblioteki sa˛ podczas kompilacji dołaczane ˛ do kompilowanego programu użytkownika. Natomiast biblioteki dynamiczne pozwalaja˛ na ładowanie bibliotek w trakcie działania programu – podczas kompilacji wykorzystywana jest jedynie informacja o interfejsie programistycznym biblioteki, na podstawie której w kodzie skompilowanego programu tworzone sa˛ niezwiazane ˛ symbole stanowiace ˛ punkty wywołań biblioteki. Ładowanie bibliotek w trakcie działania programu wymaga wsparcia ze strony systemu operacyjnego. W systemach operacyjnych z rodziny Unix biblioteki dynamiczne nazywane sa˛ dynamic shared object, natomiast w systemach z rodziny Windows dynamic-link library. Zadaniem systemu jest odnalezienie żadanej ˛ biblioteki i załadowanie 17 Rozszerzona przestrzeń adresowa umożliwia wykorzystanie wi˛ecej niż 4GB pami˛eci na architekturach wykorzystujacych ˛ 32-bitowe słowo adresowe. Implementacja firmy Microsoft polega na udost˛epnienia przesuwnego okna dost˛epu do pami˛eci. Szczegóły można znaleźć na stronie http://msdn.microsoft.com/en-us/library/windows/desktop/aa366527(v=vs.85).aspx 25 kodu wykonywalnego do przestrzeni adresowej procesów18 i powiazanie ˛ symboli z kodem załadowanej biblioteki. Kod biblioteki jest współdzielony – tzn. ładowany jest tylko raz w jedno miejsce pami˛eci i udost˛epniany klienckim procesom z zastosowaniem pami˛eci wirtualnej. Każdy z procesów posiada natomiast swoja˛ instancj˛e danych wykorzystywanych przez bibliotek˛e. Aplikacje te moga˛ realizować różne zadania, jednak wszystkie korzystaja˛ z systemu operacyjnego, jako jedynej drogi komunikacji z urzadzeniami ˛ oraz mi˛edzy soba.˛ 2.2. Modele bł˛edów Systemy komputerowe sa˛ oparte o układy cyfrowe, a ich działanie może być zaburzone wskutek różnorodnych procesów fizycznych. Powoduje to sytuacje, kiedy system przestaje prawidłowo wykonywać powierzone mu zadania. Efekty zaburzeń moga˛ rozciagać ˛ si˛e od trwałej niezdolności systemu do pracy, poprzez tymczasowe generowanie nieprawidłowych wyników, do maskowania takich sytuacji. wyst˛epujacych ˛ w systemie jest bład. ˛ Podstawowym modelem nieprawidłowości W niniejszym podrozdziale scharakteryzowane sa˛ źródła bł˛edów, ich modele oraz wpływ na funkcjonowanie poszczególnych układów systemu komputerowego. 2.2.1. Źródła bł˛edów Bł˛edy w systemach cyfrowych wynikaja˛ z budowy nowoczesnych układów oraz warunków ich eksploatacji. Przeprowadzone niedawno badania firmy Google [94] wykazały, że w 32% serwerów tej firmy w ciagu ˛ roku wykryto co najmniej jeden bład ˛ przekłamania pami˛eci. W [16, 27, 28] przedstawiono prognoz˛e zwi˛ekszenia liczby tego typu bł˛edów wraz ze stopniem upakowania układów scalonych. Dodatkowo systemy cyfrowe sa˛ eksploatowane w wielu różnych środowiskach, które mog˛e mieć niekorzystny wpływ na ich działanie – zaburzenia w działaniu moga˛ być spowodowane przez promieniowanie kosmiczne, czastki ˛ alfa, impulsy elektromagnetyczne, temperatur˛e, czy degradacj˛e układów wynikajac ˛ a˛ ze starzenia si˛e materiałów użytych do ich wytworzenia. W [59] przedstawiono wpływ wzrostu temperatury na cz˛estotliwość bł˛edów w prostych układach składajacych ˛ si˛e z przerzutników wykonanych w technologii 40 nm. Zbadano, że przy temperaturze 80 ◦ C cz˛estotliwość wyst˛epowania bł˛edów może wzrosnać ˛ dwukrotnie, a przy temperaturze 120 ◦ C trzykrotnie przy eksponowaniu układu na promieniowanie neutronowe. Dodatkowo w badaniach prowadzonych w Instytucie Telekomunikacji Politechniki Warszawskiej (patrz [68]) obserwowano znaczacy ˛ wzrost przekłamań w wynikach 18 Kod biblioteki jest specjalnie przygotowany pod katem ˛ możliwości załadowania pod różne adresy pami˛eci – jest to tzw. kod relokowalny. 26 generowanych przez układ szyfrujacy ˛ przy symulowaniu bł˛edów zegara nawet przy niewielkich zmianach temperatury pracy układu. W [94] przedstawiono analiz˛e wykazujac ˛ a,˛ że w modułach pami˛eci RAM po 24 miesiacach ˛ użytkowania cz˛estotliwość wyst˛epowania przekłamań pami˛eci rośnie od 1,7 do 3,5 raza w zależności od konkretnego produktu. Badania te również potwierdzaja˛ korelacj˛e cz˛estotliwości wyst˛epowania bł˛edów wraz ze wzrostem temperatury. Przytoczone badania świadcza˛ o wadze problemu wyst˛epowania bł˛edów. Niemniej wiele konfiguracji systemów komputerowych nie jest badanych pod katem ˛ wyznaczenia charakterystyki wrażliwości na bł˛edy w różnych warunkach eksploatacji. 2.2.2. Charakterystyka modeli bł˛edów Modele bł˛edów moga˛ być rozważane na różnych poziomach abstrakcji: fizycznym, logicznym oraz aplikacyjnym. Najniższym poziomem jest fizyczny model układu. Rozpatrywane sa˛ w nim elementy elektroniczne pod katem ˛ podatności na wymienione w 2.2.1 niekorzystne oddziaływania. W szczególności badany jest mechanizm przełożenia si˛e tych oddziaływań na nieprawidłowa˛ prac˛e układu: np. fizyczne uszkodzenie układu elektronicznego, zwarcia lub rozwarcia ścieżek, czy zwi˛ekszenie pradów ˛ upływowych. Istotnym zagadnieniem jest wyznaczanie (najcz˛eściej eksperymentalne [8, 59]) propagacji nieprawidłowości na poziomie fizycznym na modele bł˛edów logicznych. Bł˛edy logiczne rozumiane sa˛ jako nieprawidłowy stan rozpatrywanego układu. Przykładami takich modeli jest sklejenie z 0/1 (stuck-at-0/stuck-at-1), bł˛edy sprz˛eżeń, czy bit-flip. Warto zaznaczyć, że bł˛edy fizyczne moga˛ nie być łatwo modelowane jako bł˛edy warstwy logicznej (np. przekształcenie układu kombinacyjnego w sekwencyjny). Bł˛edy warstwy logicznej natomiast propaguja˛ si˛e na bł˛edy aplikacyjne, czyli inny przebieg wykonania aplikacji w stosunku do przebiegu niezaburzonego. Przykładowo bł˛edy logiczne przekłamań bitów w kodzie instrukcji procesora moga˛ powodować bł˛edy aplikacyjne zmian w argumentach instrukcji lub zamienić instrukcj˛e na inna˛ – w przypadku architektur o zmiennej długości instrukcji może to spowodować wr˛ecz lawinowe przekłamanie kolejnych instrukcji w zwiazku ˛ z odczytywaniem instrukcji spod nieprawidłowych adresów. Natomiast bł˛edy w strukturach danych moga˛ uszkodzić dane właściwe lub dane adresowe – skutki takich bł˛edów sa˛ ściśle zwiazane ˛ z typem struktury danych oraz właściwościami przechowywanych danych. Bł˛edy aplikacyjne objawiaja˛ si˛e generowaniem nieprawidłowych wyników, niedost˛epnościa˛ usług, awariami (wykonanie przez program nieprawidłowej operacji kończacej ˛ w trybie awaryjnym jego działanie) lub sa˛ one maskowane podczas wykonania oprogramowania. Warto zaznaczyć, że niektóre typy danych sa˛ w naturalny sposób odporne na bł˛edy – np. bład ˛ w pliku dźwi˛ekowym może spowodować niesłyszalne dla słuchaczy przekłamania. 27 Bł˛edy można scharakteryzować również według czasu utrzymywania si˛e w systemie: bł˛edy trwałe, bł˛edy przemijajace ˛ oraz bł˛edy migoczace ˛ (patrz [96]). Bł˛edy trwałe sa˛ wynikiem uszkodzeń układów cyfrowych. Układy te działaja˛ nieprawidłowo z powodu np. zwarcia lub przepalenia cz˛eści wewn˛etrznych połaczeń, ˛ wi˛ec ich naprawienie jest niemożliwe. Jedna˛ z metod redukcji efektów takich bł˛edów jest redundancja układowa, umożliwiajaca ˛ przej˛ecie funkcji niedziałajacego ˛ układu przez zapasowe komponenty. Bł˛edy przemijajace ˛ powstaja˛ w wyniku chwilowego zaburzenia pracy systemu – np. tymczasowe obce pola elektromagnetyczne, zakłócenia zasilania, promieniowanie kosmiczne. Charakteryzuja˛ si˛e tym, że układ nie jest uszkodzony, a jedynie jednorazowo zmienia si˛e jego wewn˛etrzny stan. Ponowne uruchomienie systemu pozwala w tej sytuacji przywrócić prawidłowe działanie. Bł˛edy migoczace ˛ sa˛ to bł˛edy powodujace ˛ tymczasowe nieprawidłowe działanie układu, tak jak w przypadku bł˛edów trwałych, niemniej możliwy jest powrót do prawidłowego działania układu po samoczynnym ustapieniu ˛ bł˛edu migoczacego. ˛ Detekcja bł˛edów tego typu jest możliwa wyłacznie ˛ w okresie aktywności bł˛edu. Utrudnia to diagnostyk˛e układu z uwagi na konieczność okresowego przeprowadzania testów, aby możliwe było zaobserwowanie nieprawidłowego działania układu. 2.2.3. Bł˛edy jednostek przetwarzajacych ˛ Nowoczesne procesory sa˛ układami cyfrowymi o dużym stopniu upakowania. W strukturach procesora znajduje si˛e wiele jednostek o dedykowanych funkcjach: dekoder instrukcji, potoki wykonania, układ przewidywania skoków, pami˛eć podr˛eczna, jednostki arytmetyczne i zmiennoprzecinkowe. Wiele z tych jednostek jest niedost˛epnych w modelu programistycznym procesora. Opracowywanie modeli bł˛edów logicznych procesora jest zadaniem trudnym. Badania przeprowadzone w [43, 65] wykazuja,˛ że bł˛edy przekłamań bitów w ukrytych rejestrach (poziom architektury) moga˛ powodować bł˛edy innego typu na poziomie logicznym funkcjonowania procesora. Przykładowo uszkodzenie jednego z rejestrów może objawić si˛e na poziomie logicznym uszkodzeniem kilku rejestrów ze wzgl˛edu na wykorzystanie registers renaming (patrz [51]). Niemniej możliwe jest rozpatrywanie cz˛eści układów procesora jako układów pami˛eci – w szczególności dotyczy to rejestrów, pami˛eci podr˛ecznej, układu MMU oraz układu przewidywania skoków. Dzi˛eki temu możliwe jest zastosowanie modeli bł˛edów opisanych w 2.2.4. Interesujacym ˛ zagadnieniem sa˛ przekłamania w pami˛eci podr˛ecznej stanowiacej ˛ integralna˛ cz˛eść procesora ze wzgl˛edu na jej redundantny charakter wzgl˛edem pami˛eci operacyjnej. Wystapienie ˛ bł˛edów zarówno po stronie pami˛eci operacyjnej i podr˛ecznej może zostać w sposób naturalny zamaskowane: 28 — przekłamanie w pami˛eci podr˛ecznej jest zamaskowane, jeżeli: dane te nie zostały odczytane i zostana˛ usuni˛ete z pami˛eci podr˛ecznej bez zapisywania do pami˛eci głównej (dane te nie były oznaczone w pami˛eci cache jako dirty), — przekłamanie w pami˛eci głównej jest zamaskowane, gdy prawidłowa kopia danych znajdowała si˛e w pami˛eci podr˛ecznej (kopia ta może być wykorzystana przy obliczeniach) i została nadpisana nowa˛ wartościa,˛ co oznacza nadpisanie zaburzonych danych w pami˛eci głównej. 2.2.4. Bł˛edy pami˛eci operacyjnej Bł˛edy pami˛eci moga˛ być spowodowane bł˛edami komórek pami˛eci lub układów adresujacych. ˛ Przykładowe bł˛edy jednostek adresujacych ˛ to: wybór bł˛ednej komórki pami˛eci, nieudany wybór zadanej komórki pami˛eci, wybór jednej z komórek pami˛eci przez wi˛ecej niż jeden adres, jednoczesny wybór kilku komórek pami˛eci przez jeden adres, a wynik jest funkcja˛ wartości wybranych komórek. Natomiast podstawowe modele bł˛edów komórek pami˛eci to (na podstawie [96]): bł˛edy sklejeń z 0/1 – komórka pami˛eci zawsze ma t˛e sama˛ wartość; bład ˛ typu bit-flip – negacja wartości przechowywanej w komórce pami˛eci; bład ˛ ulotności – zapami˛etana informacja w komórce jest tracona na skutek pradów ˛ upływowych; bł˛edy tranzycji – niemożność zmiany stanu z 1 na 0 lub z 0 na 1; bł˛edy sprz˛eżeń – wartość przechowywana w komórce lub jej zdolność do zmiany wartości jest zależna od przechowywanych w innych komórkach. Osobna˛ kategoria˛ bł˛edów sa˛ bł˛edy charakterystyczne dla poszczególnych technologii wytwarzania pami˛eci (patrz [57]): opóźnienie czasu dost˛epu; opóźnienie wzmacniacza odczytu – na wyjściu pojawia si˛e stan poprzednich bitów; opóźnienie zapisu – po dokonaniu zapisu kolejna operacja jest dokonywana na tej samej komórce pami˛eci pomimo zmiany adresu; bład ˛ niezrównoważenia – bł˛edna kwalifikacja wartości odczytywanej komórki, jeżeli wi˛ekszość komórek na tej samej linii adresowej ma stan odmienny od odczytywanej komórki. Popularna˛ metoda˛ wykrywania i ewentualnego zapobiegania bł˛edom pami˛eci w cyklu życia systemu jest stosowanie kodów korekcyjnych – sa˛ to pami˛eci ECC19 RAM (patrz [64]). Technika ta polega na rozszerzeniu pami˛eci o dodatkowe komórki, w których sa˛ przechowywane dodatkowe dane kodu korekcyjnego, pozwalajace ˛ na poprawienie i wykrywanie bł˛edów. Liczba wykrywanych i poprawianych bł˛edów pami˛eci różni si˛e w zależności od zastosowanego kodu. Weryfikacja i ewentualna korekta zawartości komórek pami˛eci odbywa si˛e przy odczycie. Niektóre implementacje tej techniki periodycznie skanuja˛ cała˛ przestrzeń adresowa˛ pami˛eci w celu wyeliminowania efektu kumulacji bł˛edów (tzw. error scrubbing). 19 Ang. Error-correcting code. 29 Pami˛eci ECC pozwalaja˛ skutecznie zwi˛ekszyć niezawodność systemów komputerowych – pozwalaja˛ na korekcj˛e bł˛edów przemijajacych ˛ oraz wykrycie bł˛edów trwałych. W [94] przedstawiono szczegółowe badanie nad cz˛estotliwościa˛ zgłaszania pojedynczych bł˛edów pami˛eci maskowanych przez ECC oraz podwójnych bł˛edów pami˛eci w środowisku produkcyjnym. Bł˛edy podwójne powodowały eliminacj˛e modułu pami˛eci z dalszych badań i zastapienie ˛ go nowym modułem. W ciagu ˛ roku w 32,2% maszyn obj˛etych badaniem zaobserwowano przynajmniej jeden bład ˛ pojedynczy (8,2% obj˛etych badaniem modułów pami˛eci) oraz w 1,29% maszyn wykryto bład ˛ podwójny (0,22% modułów pami˛eci). Przy dużej liczbie maszyn produkcyjnych koszt wymiany wadliwych modułów pami˛eci stanowi istotny koszt utrzymania. 2.2.5. Bł˛edy urzadze ˛ ń zewn˛etrznych Modele bł˛edów urzadzeń ˛ zewn˛etrznych stanowia˛ szeroka˛ dziedzin˛e badań, które sa˛ systematycznie pogł˛ebiane. Każde z urzadzeń ˛ dysponuje swoim odr˛ebnym profilem najcz˛eściej zgłaszanych bł˛edów. Bł˛edy urzadzeń ˛ zewn˛etrznych moga˛ być zwiazane ˛ zarówno z przekłamaniami danych lub nieprawidłowym zachowaniem przy komunikacji z systemem operacyjnym. Warto zaznaczyć, że bł˛edy moga˛ wystapić ˛ zarówno w urzadzeniu ˛ zewn˛etrznym, jak i kontrolerze stanowiacym ˛ integralna˛ cz˛eść systemu komputerowego. Przykładami zaburzania danych moga˛ być przekłamania jak w przypadku bł˛edów pami˛eci (typu bit-flip lub sklejeń z 0/1). Natomiast bł˛edy behawioralne moga˛ być modelowane jako niezgłaszane/nadmiarowe przerwania, zachowanie niezgodne z protokołem współpracy z urzadzeniem ˛ (np. brak odpowiedzi na wysyłane komendy). Bł˛edy danych w szczególności dotycza˛ urzadzeń ˛ przechowywania danych oraz urzadzeń ˛ komunikacyjnych. Urzadzenia ˛ przechowywania danych to dyski twarde, pami˛eci USB, czy pami˛eci Compact Flash. Przykładowo dyski twarde wykorzystuja˛ talerze z nośnikiem magnetycznym, na którym zapisywane sa˛ informacje. Urzadzenia ˛ te zapisuja˛ dane na nośniku z zastosowaniem kodów korekcyjnych, pomimo to bł˛edy nienaprawialne wyst˛epuja.˛ W badaniu opisanym w [106] w przeciagu ˛ 12 miesi˛ecy 0,04% spośród 387 840 głowic dysków twardych natrafiło na bł˛edy nienaprawialne. W krytycznych zastosowaniach wykorzystuje si˛e macierze dyskowe typu RAID. Bł˛edy danych w urzadzeniach ˛ komunikacyjnych najcz˛eściej zwiazane ˛ sa˛ z bł˛edami kanału przesyłu informacji. W przypadku sieci komputerowych duża˛ rol˛e odgrywa zastosowany protokół komunikacji – UDP20 lub TCP21 . Protokół UDP nie zakłada żadnej kontroli spójności danych, natomiast TCP posiada takie mechanizmy wbudowane. W Instytucie Informatyki Politechniki Warszawskiej prowadzono badania nad tymi mechanizmami i w [38] 20 21 Ang. User Datagram Protocol. Ang. Transmission Control Protocol. 30 przedstawiono zależność opóźnienia transmisji TCP od liczby bł˛edów w kanale transmisyjnym. Warto zaznaczyć, że pomimo zastosowania kodów korekcyjnych w TCP wcia˛ż istnieje możliwość przekłamania danych i prowadzone sa˛ badania nad poprawa˛ tego mechanizmu (patrz [60]). Oprócz bł˛edów danych przechowywanych lub przesyłanych przez urzadzenie ˛ moga˛ wystapić ˛ także bł˛edy protokołu współpracy urzadzenia ˛ z systemem operacyjnym. Bł˛edy te moga˛ być modelowane jako nadmiarowe przerwania (patrz [8]), bł˛edy danych protokołu (np. bł˛edy w ramkach protokołu SATA22 ) lub w przypadku urzadzeń ˛ korzystajacych ˛ z DMA zapisywanie danych pod inny adres niż przeznaczony do wykorzystania przez urzadzenie. ˛ 2.3. Mechanizmy zwi˛ekszania niezawodności Mechanizmy zwi˛ekszania niezawodności spełniaja˛ nast˛epujace ˛ funkcje: maskowanie oraz tolerowanie bł˛edów. systemie. detekcja, Detekcja jest to wykrycie istnienia bł˛edu w Maskowanie jest to zdolność do usuni˛ecia efektu bł˛edu zanim b˛edzie miał on wpływ na działanie systemu. Natomiast tolerowanie bł˛edów jest to mechanizm umożliwiajacy ˛ prawidłowa˛ prac˛e systemu pomimo wyst˛epowania bł˛edów. Można wyróżnić kilka podstawowych technik zwi˛ekszania niezawodności: redundancja masowa, redundancja cz˛eściowa, redundancja informacji, asercje, mechanizmy typu watchdog, izolacja oraz mechanizmy typu checkpoint. Wymienione techniki moga˛ realizować jedna˛ lub wi˛ecej funkcji niezawodności. Techniki zwi˛ekszania niezawodności moga˛ być implementowane jako mechanizmy sprz˛etowe, programowe lub programowo-sprz˛etowe. Redundancja masowa jest to technika polegajaca ˛ na wykorzystaniu wielu modułów w celu realizacji tego samego zadania lub wielokrotnym wykonaniu zadania przez jeden moduł, w przypadku założenia wyst˛epowania bł˛edów przemijajacych. ˛ Wyniki działania wszystkich modułów moga˛ brać udział w głosowaniu (redundancja bierna) – opracowanych jest wiele algorytmów przeprowadzania głosowania (patrz [96]). Alternatywnym rozwiazaniem ˛ jest zastosowanie detektora bł˛edów, który testuje wyniki działania modułów i w przypadku wykrycia bł˛edu dokonuje rekonfiguracji układu np. poprzez wyłaczenie ˛ zasilania wadliwych modułów (redundancja aktywna). Przykładem redundancji masowej realizowanej w oprogramowaniu jest N-version programming (patrz [88]). Opis badań majacych ˛ na celu zastosowania tego typu rozwiazań ˛ w systemach operacyjnych można znaleźć w [79, 111]. Istotna˛ wada˛ rozwiazań ˛ tego typu jest duży narzut na koszty tworzenia tego typu rozwiazań. ˛ Redundancja cz˛eściowa różni si˛e od redundancji masowej ograniczonym zakresem replikacji tylko do cz˛eści zasobów – przykładowo jest to zastosowanie w systemie komputerowym macierzy dyskowych RAID lub wyposażenie dysków twardych w zapasowe 22 Ang. Serial Advanced Technology Attachment. 31 cylindry na etapie produkcji. Istotne jest również wprowadzenie mechanizmów detekcji i rekonfiguracji systemu. Macierze RAID pozwalaja˛ na maskowanie bł˛edów w trakcie pracy systemu, natomiast zapasowe cylindry dysku twardego moga˛ być aktywowane jako zamiennik uszkodzonego cylindra (niemniej liczba zapasowych cylindrów jest ograniczona i w przypadku długiej pracy systemu taka zamiana może już nie być możliwa). Redundancja informacji polega na wzbogacaniu danych o dodatkowe informacje pozwalajace ˛ na dokonanie korekcji ewentualnych bł˛edów. Technika ta jest w szczególności wykorzystywana przy przesyłaniu informacji przez kanał z zakłóceniami, co pozwala zniwelować negatywne efekty. Niemniej techniki te moga˛ być również wykorzystane do zabezpieczania danych (np. RAID 3, 4, 5, 6 lub pami˛eci RAM ECC). Technika ta należy do rodziny technik forward recovery. Umieszczanie asercji w oprogramowaniu służy sygnalizacji naruszeń niezmienników działania oprogramowania. Umożliwia to wykrycie nieprawidłowego stanu systemu i podj˛ecie działań naprawczych. Zagadnienie umieszczania asercji w kodzie i oceny ich skuteczności jest przedmiotem badań prowadzonych w Instytucie Informatyki Politechniki Warszawskiej (patrz [82, 83]). Mechanizmy typu watchdog polegaja˛ na tworzeniu systemów monitorujacych ˛ działanie systemu podstawowego. Monitorowanie zazwyczaj odbywa si˛e poprzez wygenerowanie żadania ˛ i sprawdzenie odpowiedzi monitorowanego systemu z pewnym wzorcem – nieprawidłowości sa˛ wykrywane poprzez stwierdzenie braku odpowiedzi lub jej rozbieżności wzgl˛edem wzorca. Warto zaznaczyć, że mechanizmy typu watchdog moga˛ być implementowane zarówno sprz˛etowo, jak i programowo (patrz [30]). Izolacja w zwi˛ekszaniu niezawodności służy odseparowaniu poszczególnych modułów oprogramowania lub sprz˛etu. Celem jest możliwość odłaczenia ˛ nieprawidłowo działajacego ˛ modułu, tak aby działanie systemu było niezakłócone podczas dalszej eksploatacji. Przykładowo system operacyjny realizuje t˛e koncepcj˛e poprzez mechanizm procesów, gdzie awaria jednego nie ma wpływu na działanie pozostałych (szerzej w 5.1). Nieprawidłowości wykryte przy użyciu asercji lub mechanizmów watchdog wymagaja˛ podj˛ecia akcji naprawczych majacych ˛ na celu usuni˛ecie zaburzeń i ewentualna˛ diagnostyk˛e. Najprostsza˛ metoda˛ post˛epowania w przypadku wykrycia nieprawidłowości jest wymuszenie ponownego uruchomienia systemu komputerowego. Rozwiazanie ˛ to jednak jest niedopuszczalne w niektórych sytuacjach z uwagi na utrat˛e cz˛eści wyników i niedost˛epność systemu w czasie ponownego uruchamiania. Bardziej zaawansowana˛ technika˛ jest odtwarzanie systemu z kopii historycznej – jest to technika checkpointing. Technika ta jest przedmiotem wielu badań opisanych w [29, 72, 87, 109]. Ciekawym zastosowaniem tej techniki jest migracja – tzn. kopia historyczna jest odtwarzana na innym systemie komputerowym, ponieważ system 32 pierwotny uległ trwałemu uszkodzeniu (patrz [81, 86]). Checkpointing należy do rodziny technik backward recovery. Warto zaznaczyć, że podejmowane sa˛ próby tworzenia bibliotek programowych, umożliwiajacych ˛ wzbogacenie istniejacego ˛ oprogramowania o funkcje zwi˛ekszajace ˛ niezawodność (patrz [39, 76]). Opracowanie tego typu rozwiazań ˛ jest pozwoliłoby na szerokie wykorzystanie mechanizmów, które dost˛epne sa˛ wyłacznie ˛ w specjalistycznych systemach. 2.4. Symulacja bł˛edów w badaniu niezawodności systemów komputerowych Podstawa˛ badań niezawodności systemów komputerowych jest analiza produkcyjnych systemów. Wykonywana jest ona na podstawie raportów o awariach. W [69, 70, 71, 94, 97, 113] przedstawione sa˛ przykładowe projekty majace ˛ na celu zbieranie tego typu danych. Jest to najbardziej wartościowe źródło wiedzy ze wzgl˛edu na możliwość zbierania informacji o działaniu systemu w warunkach jego rzeczywistego użytkowania. Istotnym problemem opisanym w [113] jest trudność w interpretacji zebranych w ten sposób danych – wynika to z faktu, że raporty o bł˛edach oprogramowania moga˛ być wywołane zarówno bł˛edami programów, bł˛edami konfiguracyjnymi, a także usterkami sprz˛etu. W celu umożliwienia szczegółowych badań nad efektami bł˛edów opracowane zostały techniki wstrzykiwania bł˛edów umożliwiajace ˛ prowadzenie badań w warunkach laboratoryjnych. Sa˛ to mi˛edzy innymi metody takie jak celowe eksponowanie układów cyfrowych na niekorzystne warunki – pole elektromagnetyczne, promieniowanie czastek ˛ alfa, naświetlanie laserem, modyfikowanie ścieżek drukowanych układu, czy też akceleracja procesów starzenia si˛e układów poprzez podwyższona˛ temperatur˛e (patrz [8, 59, 92]). Badania tego typu sa˛ wartościowym narz˛edziem weryfikacji odporności układów przed użyciem ich w produkcji, niemniej obarczone sa˛ one pewnymi ograniczeniami: duży koszt aparatury koniecznej do przeprowadzania tego typu eksperymentów, mała kontrola nad procesem wstrzykiwania bł˛edów oraz potencjalne ryzyko trwałego uszkodzenia testowanych układów. W zwiazku ˛ z opisanymi trudnościami popularność zdobyły techniki programowego wstrzykiwania bł˛edów – SWIFI. Techniki te rozwijane sa˛ od kilkudziesi˛eciu lat [8, 19, 75], jednak wcia˛ż pozwalaja˛ na uzyskiwanie nowych, wartościowych rezultatów. Instytut Informatyki Politechniki Warszawskiej posiada bogate doświadczenie w tej dziedzinie nauki (m.in. [40, 41, 42, 96]). W [8] przedstawiono studium nad porównaniem technik fizycznego wstrzykiwania bł˛edów oraz SWIFI. Autorzy przedstawiaja˛ przypadki, gdy zastosowanie obu metod skutkuje podobnymi efektami, oraz takie gdzie rezultaty si˛e różnia.˛ 33 Rozbieżności pojawiały si˛e przede wszystkim w zwiazku ˛ z ograniczeniem modeli bł˛edów wstrzykiwanych metoda˛ SWIFI – w jednym z eksperymentów fizycznego zaburzania zaobserwowano zgłaszanie przez sprz˛et niemaskowanych przerwań, które nie były obserwowane przy bł˛edach symulowanych metoda˛ SWIFI. Oznacza to komplementarność technik fizycznych oraz SWIFI. Zaletami technik fizycznych jest odwzorowanie rzeczywistych bł˛edów, natomiast SWIFI pozwala na przeprowadzanie eksperymentów z wi˛eksza˛ sterowalnościa,˛ obserwowalnościa˛ oraz możliwościa˛ powtarzania przebiegu eksperymentu – niemniej modele SWIFI powinny być uzupełniane o nowe modele bł˛edów i zaburzane komponenty w celu pokrycia możliwie szerokiego spektrum przypadków testowych. O popularności metod SWIFI może świadczyć pojawianie si˛e prac zmierzajacych ˛ do ujednolicenia metod opisu profili wstrzykiwania (patrz [9, 55]) rozumianych jako sposób odtworzenia charakterystyki bł˛edów rzeczywistych urzadzeń ˛ przez narz˛edzia SWIFI. Dodatkowo opracowywane sa˛ uniwersalne formaty konfiguracji eksperymentów (patrz [31, 36]), które maja˛ na celu uniezależnić definicj˛e eksperymentu od konkretnej platformy SWIFI umożliwiajac ˛ uruchamianie tych samych eksperymentów na różnych platformach w celu weryfikacji uzyskiwanych rezultatów. Rozpatrujac ˛ metody typu SWIFI należy zaznaczyć, że metody te sa˛ ukierunkowane na wstrzykiwanie bł˛edów według zdefiniowanych modeli w ściśle określona˛ przestrzeń testowania. Oznacza to wi˛eksza˛ kontrol˛e nad procesem wstrzykiwania bł˛edów w porównaniu z metodami wykorzystujacymi ˛ fizyczne zaburzanie działania układów, niemniej zdefiniowana przestrzeń testowania jest zazwyczaj ograniczona i charakterystyczna dla każdego z opracowanych narz˛edzi. W celu ilustracji tego zagadnienia opisane zostały przykłady różnych narz˛edzi typu SWIFI. Podstawowa˛ rodzina˛ narz˛edzi typu SWIFI sa˛ narz˛edzia operujace ˛ na modelach testowanych urzadzeń. ˛ Modele te moga˛ być opracowane m.in. w j˛ezykach takich jak VHDL23 , czy Matlab. Opis narz˛edzi tego typu można znaleźć w pracach [43, 47, 63, 90, 95, 102, 104, 105, 110]. Wspólna˛ cecha˛ tych rozwiazań ˛ jest modelowanie układów i oprogramowania wbudowanego o ściśle określonych funkcjach. Rozwiazania ˛ te sa˛ rzadko stosowane do badania niezawodności komponentów COTS z uwagi na duży stopień ich skomplikowania, co znaczaco ˛ spowalnia proces przeprowadzania eksperymentów. Osobna˛ rodzina˛ narz˛edzi SWIFI sa˛ narz˛edzia ukierunkowane na konkretna˛ platform˛e sprz˛etowa˛ lub programowa.˛ Do nich można zaliczyć oprogramowanie FITS opracowane w Instytucie Informatyki Politechniki Warszawskiej (patrz [40, 41, 42]). Proces wstrzykiwania bł˛edów zaimplementowany w tym rozwiazaniu ˛ polega na wykorzystaniu mechanizmów debuggowania dost˛epnych w systemach operacyjnych (np. Windows API24 , ptrace25 ) do kontroli i zaburzania wykonania testowanego oprogramowania. 23 24 25 J˛ezyk opisu układów cyfrowych. http://msdn.microsoft.com/en-us/library/ms809754.aspx http://linux.die.net/man/2/ptrace 34 W [112] przedstawione zostało porównanie trzech metod modelowania bł˛edów w SWIFI: modyfikacja wartości parametrów wywołań procedur, zamiana wartości zwracanych przez procedury oraz przekłamania pojedynczych bitów w dowolnych miejscach pami˛eci. Przekłamania parametrów wywołań procedur imituja˛ propagacj˛e bł˛edów wygenerowanych w rejestrach urzadzeń ˛ do programów. bł˛edy programistyczne. Zaburzanie wartości zwracanych symuluje Natomiast zaburzanie pami˛eci stanowi model nieprawidłowości wyst˛epujacych ˛ w pami˛eci RAM. Badania te ilustruja˛ różne podejścia do wstrzykiwania bł˛edów i autorzy wskazuja˛ na najwi˛eksza˛ skuteczność (w sensie liczebności typów zgłaszanych awarii) metody zaburzania losowych komórek pami˛eci. W [115] opisany został eksperyment wykorzystujacy ˛ przekłamania na poziomie pojedynczych bitów do zaburzania różnych typów danych składowanych w pami˛eci w celu porównania ich wrażliwości na bł˛edy. Wyniki uzyskane przez autorów wskazuja,˛ że dane alokowane dynamicznie sa˛ wielokrotnie bardziej wrażliwe na zaburzenia, niż dane statyczne. Zagadnieniem wartym uwagi jest stosowanie SWIFI do ewaluacji niezawodności systemów operacyjnych, ponieważ nie jest możliwe wykorzystanie mechanizmów debuggowania i konieczne jest opracowywanie rozwiazań ˛ innego typu. Wiele koncepcji testowania systemów operacyjnych wia˛że si˛e z testowaniem sterowników obsługiwanych urzadzeń ˛ (patrz 2.1.2). Np. w [33] przedstawiono rozwiazanie ˛ wprowadzajace ˛ bł˛edy do sterowników DMA, a w [38, 58] opisano metody zaburzania danych pochodzacych ˛ z sieci. Rozwiazania ˛ skupiajace ˛ si˛e na zaburzaniu parametrów wywołań procedur wykonywanych w przestrzeni jadra ˛ systemu operacyjnego opracowano w [5, 38, 61, 62]. Jednakże niewiele jest opracowań pozwalajacych ˛ całościowo badać systemy operacyjne. W [34] zaprezentowane jest nast˛epujace ˛ podejście: do symulowania bł˛edów wykorzystywany jest moduł systemu operacyjnego, natomiast kontrola eksperymentu powierzona jest osobnej maszynie, która rejestruje wynik symulacji bł˛edu na maszynie realizujacej ˛ eksperyment. Podejście to ma szereg wad: konieczne jest opracowanie modułu symulujacego ˛ bł˛edy zależnego od testowanego systemu komputerowego, wymagany jest dodatkowy system komputerowy wykorzystywany jako nadzorca (wia˛że si˛e to z kosztami i utrudnia skalowalność) oraz ograniczone sa˛ możliwości badania efektów awarii. W [78] przedstawiono rozwiazanie ˛ niewymagajace ˛ implementacji dedykowanego modułu systemu operacyjnego symulujacego ˛ bł˛edy – praca opisuje badanie systemu wbudowanego opartego o FPGA26 działajacego ˛ pod kontrola˛ systemu GNU/Linux i wyposażonego w możliwość symulowania bł˛edów poprzez modyfikacj˛e konfiguracji układu FPGA. W przypadku ch˛eci równoległego przeprowadzania eksperymentów rozwiazanie ˛ to również wymaga nakładu kosztów na dodatkowe jednostki układów przeprowadzajacych ˛ testy. Wymienione problemy sa˛ cz˛eściowo rozwiazane ˛ przez dwa projekty opisane w [18] oraz [93]. 26 Ang. Field Programmable Gate Array. 35 W [18] wykorzystany został emulator systemu operacyjnego User Mode Linux27 , gdzie odpowiednio zmodyfikowane jadro ˛ systemu operacyjnego uruchamiane jest jako proces użytkownika, a wstrzykiwanie bł˛edów odbywa si˛e poprzez interfejs ptrace. Wada˛ takiego rozwiazania ˛ jest konieczność modyfikowania testowanego oprogramowania (źródeł jadra ˛ systemu operacyjnego) w celu uruchomienia na platformie testowej oraz możliwość testowania wyłacznie ˛ jednego systemu operacyjnego na jednej z dwóch obsługiwanych architektur sprz˛etowych: x86 i AMD64. Natomiast w [93] opisano prób˛e stworzenia w pełni deterministycznego emulatora systemu komputerowego, wzbogacajac ˛ go o możliwość integracji z modułami sprz˛etowymi modelowanymi w j˛ezyku VHDL. Proces wstrzykiwania bł˛edów polega na zaburzaniu pracy wspomnianych modułów sprz˛etowych i obserwowaniu zachowania systemu operacyjnego uruchomionego w emulowanym środowisku. Rozwiazanie ˛ to jest bardzo obiecujace, ˛ jednak ogranicza si˛e tylko do testowania układów. Reasumujac, ˛ narz˛edzia typu SWIFI sa˛ uznana˛ w środowisku naukowym metoda˛ ewaluacji niezawodności oprogramowania, jednak konieczne jest ciagłe ˛ rozwijanie scenariuszy testowych oraz metod analizy wyników. Według autora, na podstawie przeanalizowanej literatury, istotnym brakiem we współczesnych narz˛edziach SWIFI sa˛ ograniczone możliwości ewaluacji niezawodności oprogramowania systemu operacyjnego. Oprogramowanie systemu operacyjnego jest krytyczne dla prawidłowego działania systemu komputerowego, a jego ewaluacja jest wielopłaszczyznowa: m.in. wrażliwość na bł˛edy pami˛eci, wrażliwość na bł˛edy urzadzeń, ˛ stabilność systemu, czy porównanie cech kodu tego samego systemu operacyjnego skompilowanego na różne platformy sprz˛etowe. Opracowana na potrzeby niniejszej rozprawy metodyka symulacji bł˛edów wsparta przez opracowany przez autora system QEFI (patrz rozdział 3) stanowi prób˛e stworzenia narz˛edzia typu SWIFI umożliwiajacego ˛ ewaluacj˛e oprogramowania systemu operacyjnego poprzez zastosowanie emulacji systemu komputerowego. 2.5. Analiza efektów bł˛edów Wystapienie ˛ bł˛edu w systemie może powodować różnego typu nast˛epstwa – od maskowania bł˛edu do awarii. Opracowywanie skutecznych technik obsługi bł˛edów wymaga szczegółowej analizy cyklu życia bł˛edu w systemie. Poniżej przedstawiona jest charakterystyka zdarzeń opisujacych ˛ wystapienie ˛ bł˛edu oraz poj˛ecia i miary zwiazane ˛ z symulacja˛ bł˛edów, które pozwalaja˛ na dogł˛ebna˛ analiz˛e wpływu bł˛edów na działanie systemu. 27 http://user-mode-linux.sourceforge.net/ 36 2.5.1. Scenariusz wystapienia ˛ bł˛edu Analiza efektów bł˛edów w systemie komputerowym wymaga opisania zdarzeń, które maja˛ miejsce w sytuacji wystapienia ˛ bł˛edu. Poniżej zamieszczone sa˛ definicje rozpatrywanych zdarzeń: — wystapienie ˛ bł˛edu na poziomie fizycznym – jest to moment, kiedy działanie układu zostało zaburzone i nie realizuje on funkcji zgodnie ze swoja˛ specyfikacja,˛ — wystapienie ˛ bł˛edu na poziomie logicznym – jest to sytuacja, kiedy zaburzenie na poziomie fizycznym zmienia stan logiczny układu (np. zmiana wartości bitów), — aktywacja bł˛edu – jest to chwila, gdy dane zmodyfikowane na skutek bł˛edu logicznego zostały wykorzystane w procesie wykonania oprogramowania, — maskowanie – sytuacja, gdy aktywacja bł˛edu nie wpłyn˛eła na działanie systemu komputerowego, — manifestacja – wyst˛epuje, gdy zaistniała w systemie nieprawidłowość wywołuje obserwowalne odst˛epstwo od pracy systemu (np. generowanie nieprawidłowych wyników, nieudany wynik sprawdzenia asercji, zniekształcone komunikaty systemu), — awaria – jest to zdarzenie b˛edace ˛ manifestacja˛ bł˛edu oznaczajace ˛ wystapienie ˛ sytuacji wyjatkowej ˛ uniemożliwiajacej ˛ kontynuacj˛e wykonania oprogramowania, — detekcja bł˛edu – wyst˛epuje, gdy zaistniała w systemie nieprawidłowość zostaje zamanifestowana i zidentyfikowana jako bład ˛ sprz˛etowy. Odst˛ep mi˛edzy wystapieniem ˛ bł˛edu na poziomie fizycznym a jego aktywacja˛ nazywany jest utajeniem bł˛edu. Natomiast interwał mi˛edzy wystapieniem ˛ bł˛edu, a manifestacja˛ jest określany opóźnieniem manifestacji bł˛edu. W przypadku powyższych zdarzeń odst˛epy pomi˛edzy nimi moga˛ być mierzone zarówno czasem rzeczywistym jak i czasem logicznym (np. liczba wykonań instrukcji, czy liczba taktów zegara procesora). Istotnym zagadnieniem zwiazanym ˛ z aktywacja˛ bł˛edów jest aktywność zasobów. Zasób, czyli przykładowo komórka pami˛eci RAM, jest aktywny, jeżeli przechowuje dane, które b˛eda˛ wykorzystane w przebiegu programu do uzyskania wyniku. Oznacza to, że zasób jest nieaktywny w przedziałach czasu pomi˛edzy ostatnim odczytem zasobu, a zapisem nowymi wartościami28 . Nie wszystkie bł˛edy maja˛ wpływ na obliczenia. Mamy do czynienia z takim scenariuszem, gdy bład ˛ przemijajacy ˛ wystapił ˛ w okresie nieaktywności zasobu. Chociaż możliwe sa˛ również przypadki, kiedy bład ˛ aktywowany nie miał wpływu na obliczenia. 28 Pod warunkiem, że nowa wartość b˛edzie odczytana. W przypadku, gdy kolejna˛ operacja˛ na zasobie jest zapis, to czas nieaktywności zasobu wydłuża si˛e do tej operacji. 37 2.5.2. Symulowanie bł˛edów W technice symulacji bł˛edów możliwe jest dokładne określenie skutków wstrzykiwania bł˛edów. Poniżej przedstawione sa˛ miary pozwalajace ˛ określić zarówno cechy efektów wstrzykiwania pojedynczych bł˛edów, jak i zbiorczych eksperymentów. Bł˛edy moga˛ być symulowane w różnych komponentach systemu komputerowego, a także w różnych momentach. Definicja 2.5.1. Zaburzana przestrzeń jest to charakterystyczny dla danego typu bł˛edu zbiór zasobów i momentów symulacji bł˛edu. Przykładowo dla bł˛edów pami˛eci zaburzana˛ przestrzenia˛ sa˛ komórki pami˛eci w czasie pracy systemu komputerowego. Warto zaznaczyć, że wprowadzanie bł˛edów w pewnych podzbiorach zaburzanej przestrzeni nie b˛edzie miało wpływu na działanie systemu komputerowego. W przypadku bł˛edów bit-flip pami˛eci celowe jest tylko zaburzanie zasobów aktywnych w danym momencie wstrzykni˛ecia, ponieważ w nieaktywnej komórce pami˛eci zostanie zapisana nowa wartość maskujac ˛ w ten sposób wystapienie ˛ bł˛edu. Natomiast sytuacja jest odmienna w przypadku bł˛edów stuck-at-0/stuck-at-1, kiedy symulacja bł˛edu w nieaktywnej komórce pami˛eci utrzymuje si˛e po zapisie nowej wartości. Oprogramowanie systemu operacyjnego powinno być w stanie obsługiwać bł˛edy, które pochodza˛ z urzadzeń ˛ systemu komputerowego (komponentów obsługiwanych przez system operacyjny, np. sprz˛etu stanowiacego ˛ integralna˛ cz˛eść systemu komputerowego oraz urzadzeń ˛ zewn˛etrznych) jak i bł˛edów w komponentach wykorzystywanych przez system operacyjny do działania – kodu oraz danych. Skutkuje to podziałem na dwa rodzaje symulowanych bł˛edów: bł˛edy zewn˛etrzne oraz bł˛edy wewn˛etrzne. Przykładem bł˛edu zewn˛etrznego jest nieprawidłowo działajacy ˛ kontroler USB generujacy ˛ losowe pakiety. Natomiast bł˛edem wewn˛etrznym może być przekłamanie typu bit-flip w obszarze pami˛eci RAM przechowujacej ˛ kod systemu operacyjnego. Opóźnienie awarii jest miara˛ zwiazan ˛ a˛ z opóźnieniem manifestacji bł˛edu w przypadku, gdy bład ˛ skutkuje awaria.˛ Definicja 2.5.2. Opóźnienie awarii stanowi liczb˛e instrukcji kodu programu wykonanych przez jednostk˛e przetwarzajac ˛ a˛ od wykonania pierwszej instrukcji aktywujacej ˛ bład ˛ do wykonania instrukcji wywołujacej ˛ awari˛e. Manifestacja bł˛edu dla celów niniejszej rozprawy została podzielona na kategorie uwzgl˛edniajace ˛ czy system komputerowy wygenerował powierzone mu zadanie (np. prawidłowo przetworzony został pewien plik) oraz czy system operacyjny zgłosił komunikaty sygnalizujace ˛ nieprawidłowości w działaniu systemu: 38 — PU – prawidłowy wynik realizowanego zadania; bład ˛ spowodował odst˛epstwo w pracy aplikacji użytkownika (np. deformacja wypisywanych przez aplikacj˛e użytkownika komunikatów); jest to niekrytyczny przypadek manifestacji bł˛edu, — PS – prawidłowy wynik realizowanego zadania; system operacyjny zgłosił komunikat o wystapieniu ˛ nieprawidłowości w systemie (np. awaria procesu niemajacego ˛ wpływu na proces realizacji zadania – przykładowo procesu defragmentacji dysku); jest to niekrytyczny przypadek manifestacji bł˛edu z punktu widzenia realizacji zadania, niemniej praca systemu operacyjnego została zaburzona, — NU – nieprawidłowy wynik realizowanego zadania lub brak wyniku; brak komunikatu zgłoszonego przez system operacyjny; jest to krytyczny scenariusz, ponieważ bład ˛ spowodował bł˛edne działanie aplikacji użytkownika, uniemożliwił dostarczenie wyniku lub wr˛ecz spowodował zawieszenie si˛e systemu operacyjnego, — NS – nieprawidłowy wynik realizowanego zadania lub brak wyniku; system operacyjny zgłosił komunikat o odst˛epstwie od prawidłowej pracy systemu; jest to krytyczny scenariusz z uwagi na brak prawidłowego wyniku, jednak dostarcza on wi˛ecej informacji o przyczynie nieprawidłowości, niż kategoria NU . Przykłady wymienionych typów manifestacji wraz z opisem przedstawione sa˛ w 4.2. Dodatkowo możliwe jest rozróżnienie, czy w przypadku manifestacji bł˛edu system komputerowy pozostał dost˛epny i czy użytkownik mógł obserwować manifestacj˛e bł˛edu. System komputerowy uznawany jest za dost˛epny, kiedy możliwa jest interakcja z systemem. Dost˛epność systemu została podzielona na nast˛epujace ˛ kategorie: — DU – system dost˛epny, odst˛epstwa od prawidłowej pracy systemu sa˛ zwiazane ˛ z komunikatami zgłaszanymi przez aplikacje użytkownika, — DS – system dost˛epny, system operacyjny zgłosił komunikat o wystapieniu ˛ nieprawidłowości, — N DU – system niedost˛epny, brak informacji o wykryciu bł˛edu aplikacyjnego przez system operacyjny, — N DS – system niedost˛epny, system operacyjny zgłosił komunikat o wystapieniu ˛ nieprawidłowości przed utrata˛ możliwości interakcji. Dla zbiorczej oceny efektów symulowanych bł˛edów wprowadzone zostały nast˛epujace ˛ współczynniki: — współczynnik wrażliwości na bł˛edy Fs = M , W — współczynnik naturalnej odporności na bł˛edy I = 1 − — współczynnik detekcji bł˛edów Fd = Wd , Wa — współczynnik naprawy bł˛edów określony Fr = gdzie: — M – liczba bł˛edów zamanifestowanych, 39 R , Wd M , Wa — W – liczba bł˛edów symulowanych w systemie, — Wa – liczba bł˛edów aktywowanych w systemie, — Wd – liczba bł˛edów wykrytych w systemie, — R – liczba bł˛edów, dla których przeprowadzono procedur˛e naprawcza˛ i uzyskano prawidłowy wynik realizowanego zadania. Współczynniki te dotycza˛ eksperymentu składajacego ˛ si˛e z wielu pojedynczych testów symulowania bł˛edu. Wyznaczenie dokładnej wartości każdego ze współczynników wymagałoby zupełnego pokrycia zaburzanej przestrzeni (np. zaburzanie wszystkich adresów pami˛eci RAM), niemniej możliwe jest oszacowanie ich wartości poprzez odpowiednio liczna˛ i reprezentatywna˛ prób˛e wstrzykni˛etych bł˛edów (szerzej opisane w 4.2). Współczynnik wrażliwości na bł˛edy określa podatność systemu na bł˛edy. Współczynnik naturalnej odporności na bł˛edy wyznacza zdolność systemu do maskowania bł˛edów – określa on liczb˛e bł˛edów, które nie zostały zamanifestowane, pomimo że były aktywowane. Współczynnik detekcji bł˛edów określa zdolność systemu do wykrywania bł˛edów sprz˛etowych. Przykładowo, jeżeli system wykrył bład ˛ w danych tylko do odczytu poprzez wyliczenie sumy kontrolnej i wypisał zwiazany ˛ z tym komunikat, to jest to detekcja bł˛edu, natomiast jeżeli bład ˛ spowodował awari˛e, to jest to jedynie manifestacja bł˛edu, ponieważ nie jest możliwe określenie, czy awaria jest skutkiem bł˛edu pracy systemu, czy bł˛edu programistycznego. Współczynnik naprawy bł˛edów wyraża zdolność systemu do przeprowadzenia skutecznych procedur naprawczych w przypadku detekcji bł˛edu sprz˛etowego. 2.6. Podsumowanie W rozdziale przedstawiony został model rozważanego systemu komputerowego jako sprz˛etu oraz oprogramowania. Opisana została również dziedzina badania niezawodności systemów komputerowych. Scharakteryzowane zostały źródła bł˛edów oraz znane z literatury mechanizmy zwi˛ekszania niezawodności wraz z technikami pozwalajacymi ˛ ocenić ich skuteczność. Przedstawiona w ostatniej cz˛eści rozdziału analiza pozwala określić podstawowe zadania mechanizmów zwi˛ekszania niezawodności. Głównym zadaniem jest maksymalizacja detekcji bł˛edów w systemie. Dzi˛eki temu możliwe jest stwierdzenie, że system może potencjalnie działać nieprawidłowo w zwiazku ˛ z bł˛edami sprz˛etowymi – niezależnie od tego, czy bład ˛ zostanie aktywowany. Informacja o tych bł˛edach stanowi również cenne źródło wiedzy o kondycji systemu komputerowego, ponieważ bł˛edy maja˛ charakter nawracajacy ˛ (czyli wystapienie ˛ bł˛edu zwi˛eksza szanse na ponowne wystapienie ˛ bł˛edu w tym samym urzadzeniu ˛ – patrz [84]). Kolejnym zadaniem zwi˛ekszania niezawodności jest maksymalizacja tolerancji bł˛edów, czyli możliwości podj˛ecia procedur naprawczych niwelujacych ˛ efekty 40 bł˛edu. Optymalizacja detekcji i tolerancji bł˛edów pozwala na osiagni˛ ˛ ecie wyższych poziomów niezawodności określonych za pomoca˛ współczynników przedstawionych w 2.5.2. 41 3. Metodyka symulacji bł˛edów w emulowanym środowisku W rozdziale przedstawiono wykorzystanie emulacji systemu komputerowego do analizy niezawodności oprogramowania. Poczatek ˛ rozdziału uzasadnia obrany kierunek badań. Nast˛epnie przedstawiony jest opis obecnego stanu technologii w dziedzinie emulacji systemów komputerowych oraz prezentacja cech emulatorów, które sa˛ szczególnie istotne z perspektywy badania niezawodności oprogramowania. Ostania cz˛eść rozdziału zawiera opis stworzonej na potrzeby niniejszej rozprawy oryginalnej metodyki przeprowadzania eksperymentów oraz opracowanych algorytmów symulacji bł˛edów. 3.1. Motywacja Podj˛ecie zagadnienia zastosowania emulacji w analizie niezawodności oprogramowania zwiazane ˛ jest z próba˛ poszerzenia horyzontu badań w stosunku do narz˛edzi, które ukierunkowane sa˛ na kod pojedynczych aplikacji (patrz 2.4). Wada˛ takich narz˛edzi jest skupienie si˛e na pojedynczym programie w oderwaniu od środowiska wykonania. Według autora potrzeba zbadania całego środowiska operacyjnego oprogramowania jest istotnym zagadnieniem niedostatecznie opisanym w literaturze. Dzi˛eki zwi˛ekszeniu w ostatnich latach wydajności emulacji systemów komputerowych stało si˛e możliwe wykorzystanie tego typu oprogramowania do badań nad niezawodnościa.˛ Podstawowa˛ technika˛ wykorzystywana˛ w dziedzinie ewaluacji niezawodności jest wstrzykiwanie bł˛edów (patrz 2.4). Wzbogacenie emulatorów systemów komputerowych o funkcje symulacji bł˛edów b˛edacych ˛ modelami rzeczywistych zaburzeń pracy systemu pozwoli na stworzenie narz˛edzi pozwalajacych ˛ na wszechstronna˛ ewaluacj˛e niezawodności oprogramowania. Zastosowanie emulatorów usprawnia prowadzenie eksperymentów poprzez brak konieczności instrumentacji testowanego oprogramowania oraz pełna˛ kontrol˛e nad procesem emulacji, gdzie możliwe jest efektywne śledzenie zmian w środowisku. Dodatkowo otwieraja˛ si˛e nowe obszary badań takie jak: ewaluacja oprogramowania systemów operacyjnych, badanie efektów usterek urzadzeń, ˛ porównywanie właściwości różnych architektur sprz˛etowych, 43 czy opracowywanie nowych mechanizmów zwi˛ekszania niezawodności wykorzystujacych ˛ współprac˛e aplikacji i systemu operacyjnego. Zdaniem autora funkcje umożliwiajace ˛ symulowanie bł˛edów w emulatorach b˛eda˛ coraz popularniejsze i maja˛ potencjał stać si˛e standardem w testowaniu oprogramowania. Wynika to z faktu, że symulacja bł˛edu jest zadaniem znacznie łatwiejszym i precyzyjniejszym niż wprowadzenie rzeczywistego bł˛edu, a emulatory znacznie poszerzaja˛ zakres stosowania tej techniki. 3.2. Emulacja systemów komputerowych Emulatory systemów komputerowych sa˛ bardzo popularnymi narz˛edziami w przemyśle informatycznym. Na rynku dost˛epnych jest wiele rozwiazań, ˛ które różnia˛ si˛e posiadanymi funkcjami i sa˛ przeznaczone do różnych zadań: testowanie oprogramowania [98], izolacja środowiska wykonania oprogramowania [20], czy zarzadzanie ˛ wirtualnymi komputerami1 . W niniejszych rozważaniach emulator systemu komputerowego jest zdefiniowany nast˛epujaco: ˛ Definicja 3.2.1. Emulatorem systemu komputerowego A jest oprogramowanie działajace ˛ na systemie komputerowym B, które umożliwia działanie niezmodyfikowanego oprogramowania X przeznaczonego na system komputerowy A. Definicja 3.2.1 określa główne wymagania sformułowane dla emulatorów – oprogramowanie X nie może być zmodyfikowane w żaden sposób oraz musi realizować programowo środowisko systemu komputerowego (patrz 2.1.1). Niemniej emulatory moga˛ pracować na różnych poziomach abstrakcji. Warto wyróżnić trzy poziomy abstrakcji: — emulacja układów cyfrowych, — emulacja logicznego funkcjonowania urzadzeń, ˛ — emulacja systemu operacyjnego. Emulacja na poziome układów cyfrowych oznacza modelowanie systemu komputerowego A poprzez niskopoziomowa˛ specyfikacj˛e sprz˛etu – np. definiowanie procesorów, pami˛eci i innych urzadzeń ˛ w j˛ezyku VHDL. Przykłady badań ukierunkowanych na przeprowadzanie eksperymentów na modelach mikrokontrolerów można znaleźć w [43, 44, 47] . Warto zaznaczyć, że ten sposób emulacji jest rozwiazaniem ˛ bardzo kosztownym obliczeniowo przy zastosowaniu dla wszystkich komponentów systemu komputerowego, co czyni to rozwiazanie ˛ niepraktycznym. Emulacja na poziomie logicznego funkcjonowania urzadzeń ˛ pozwala na modelowanie sprz˛etu poprzez implementacj˛e funkcji, które sa˛ przez niego realizowane. 1 http://www.vmware.com/pdf/virtualization.pdf 44 Przykładem jest emulacja dysku twardego systemu komputerowego A poprzez moduł programowy, który wykorzystuje plik w systemie B do realizacji funkcji zapisu i odczytu danych. Zadaniem modułu programowego jest wtedy implementacja protokołu wymiany danych mi˛edzy urzadzeniem, ˛ a pozostałymi komponentami emulowanego systemu – np. SATA. Podejście takie pozwala na emulacj˛e sprz˛etu bez znajomości jego wewn˛etrznej struktury. Dodatkowo jest ono wydajniejsze od emulacji układów cyfrowych z uwagi na możliwość wykorzystania mechanizmów dost˛epnych w systemie B bez narzutu na replikacj˛e wewn˛etrznych stanów emulowanych urzadzeń. ˛ Emulacja na poziomie systemu operacyjnego zwiazana ˛ jest z ograniczeniem oprogramowania X tylko do aplikacji użytkownika. Aplikacje te komunikuja˛ si˛e z systemem operacyjnym poprzez wywołania systemowe (patrz 2.1.2). Koncepcja emulacji na poziomie systemu operacyjnego polega na przechwytywaniu wywołań systemowych pochodzacych ˛ z oprogramowania X i obsługi ich przez oprogramowanie emulatora, który w razie potrzeby wywołuje system operacyjny działajacy ˛ na systemie B. Dzi˛eki tej metodzie na potrzeby oprogramowania X emulowany jest jedynie procesor i pami˛eć systemu A, natomiast dost˛ep do dodatkowych urzadzeń ˛ takich jak dyski twarde, czy interfejs sieciowy realizowany jest przez system B. Ciekawa˛ technika˛ cz˛esto wykorzystywana˛ w emulacji jest również możliwość współdzielenia urzadzeń ˛ wyst˛epujacych ˛ w systemie A z systemem B – rozwiazanie ˛ takie jest możliwe przy wsparciu systemu operacyjnego maszyny emulujacej. ˛ Zasada działania jest nast˛epujaca: ˛ dane wysyłane do urzadzenia ˛ sa˛ przechwytywane z emulowanej magistrali do systemu operacyjnego rzeczywistego komputera, który nast˛epnie wysyła je do urzadzenia ˛ (z zastosowaniem rzeczywistej magistrali). Analogicznie system operacyjny rzeczywistego komputera przekazuje (ewentualnie po wst˛epnej obróbce) dane otrzymane z urzadzenia ˛ do oprogramowania emulatora, po czym przekazywane sa˛ one do emulowanego systemu za pośrednictwem emulowanej magistrali. W [73] przedstawiono mechanizm udost˛epniania rzeczywistych urzadzeń ˛ USB dla emulowanego systemu w sposób imitujacy ˛ bezpośrednie podłaczenie ˛ tych urzadzeń. ˛ Niemniej podobne rozwiazania ˛ sa˛ dost˛epne w wielu komercyjnych rozwiazaniach ˛ (VMware, VirtualBox, Virtual PC) – w szczególności możliwe jest wykorzystanie przez emulowany system rzeczywistego dysku twardego, urzadzeń ˛ USB, czy kart graficznych. W implementacjach emulatorów moga˛ być stosowane rozwiazania ˛ hybrydowe, gdzie emulacja poszczególnych urzadzeń ˛ realizowana jest na różnych poziomach abstrakcji. Przykładowo procesor systemu A może być emulowany na poziomie układów cyfrowych, pami˛eć RAM jako plik rezydujacy ˛ w systemie B, a pozostałe urzadzenia ˛ sa˛ dost˛epne za pośrednictwem systemu operacyjnego działajacego ˛ na systemie B. 45 W dalszej cz˛eści rozdziału opisane sa˛ wyłacznie ˛ zagadnienia zwiazane ˛ z emulacja˛ na poziomie logicznego funkcjonowania urzadzeń. ˛ Emulacja na poziomie układów cyfrowych została wykluczona z powodu niedost˛epności wewn˛etrznej specyfikacji poszczególnych urzadzeń ˛ – stanowia˛ one własność intelektualna˛ producentów i cz˛esto nie sa˛ udost˛epniane publicznie. Natomiast emulacja na poziomie systemu operacyjnego ograniczyłaby badania do oprogramowania aplikacji użytkownika, co stoi w sprzeczności z jednym z celów rozprawy, jakim jest ewaluacja oprogramowania systemu operacyjnego. Przy emulacji na poziomie logicznego funkcjonowania urzadzeń ˛ implementacja modelu pami˛eci oraz urzadzeń ˛ wejścia/wyjścia może być zbliżona mi˛edzy różnymi emulatorami. Bardzo istotnym zagadnieniem jest sposób emulacji jednostek przetwarzajacych, ˛ który ma decydujacy ˛ wpływ na wydajność. Należy wyróżnić trzy główne sposoby rozwiazania ˛ tego problemu: — interpretacja, — translacja binarna, — wirtualizacja. Wszystkie z wymienionych technik maja˛ za zadanie obsług˛e zestawu instrukcji architektury (ISA2 ) emulowanego procesora, jednak każda z nich ma swoje zalety oraz ograniczenia. Poniżej zamieszczona jest charakterystyka poszczególnych rozwiazań. ˛ Interpretacja Technika interpretowania polega na obsłudze emulowanych instrukcji procesora pojedynczo przez program emulatora. Emulator pobiera instrukcj˛e programu emulowanego, dekoduje ja˛ przy pomocy zestawu instrukcji warunkowych if lub switch, a nast˛epnie pobiera argumenty instrukcji i wykonuje przypisane jej działanie, modyfikujac ˛ struktur˛e danych reprezentujac ˛ a˛ stan emulowanego procesora. Interpretacja jest bardzo prosta˛ technika˛ emulacji procesora, jednak nie jest ona wydajna. Spowodowane jest to tym, że współczesne procesory sa˛ budowane w oparciu o potoki instrukcji. Rozwiazanie ˛ to powoduje przyśpieszenie wykonania kodu, gdy trafnie przewidywane sa˛ adresy docelowe instrukcji skoków. Za każdym razem, gdy przewidywanie nie powiedzie si˛e, nast˛epuje unieważnienie zawartości potoku i konieczne jest ładowanie nowego zestawu instrukcji do wykonania. W przypadku interpretacji przewidywanie skoków jest zadaniem bardzo trudnym z uwagi na dekodowanie emulowanych instrukcji, gdzie konieczne jest wykonanie wielu skoków warunkowych w procesie wyboru odpowiedniej procedury obsługi. Zagadnienie optymalizacji interpretacji jest szeroko opisane w literaturze [11, 13, 32, 67], jednak wiele z nich polega na manipulowaniu zestawem emulowanych instrukcji3 , 2 Ang. Instruction Set Architecture. Techniki te sa˛ stosowane np. w przypadku kompilowania j˛ezyka programowania do bytecode’u, który podlega interpretacji. 3 46 co nie jest możliwe w przypadku emulowania konkretnego ISA. Zdaniem autora jedna˛ z najbardziej interesujacych ˛ technik, która pozwala na przyśpieszenie interpretacji dowolnego ISA jest context threading (patrz [13]). Technika ta jest dwuetapowa. Pierwszy etap to przygotowanie dynamicznego bufora wypełnionego instrukcjami wywołań procedur obsługi kolejnych emulowanych instrukcji. Drugi etap polega na wykonaniu instrukcji zawartych w tym buforze. Pozwala to na wyeliminowanie dekodowania emulowanej instrukcji podczas interpretacji. Pewnym problemem pozostaja˛ instrukcje skoku, które musza˛ być tłumaczone na zestawy instrukcji maszyny emulujacej ˛ i również umieszczone w buforze, co czyni to rozwiazanie ˛ zbliżonym do translacji binarnej. Translacja binarna Celem translacji binarnej jest przetłumaczenie instrukcji emulowanego systemu na instrukcje emulujacego ˛ systemu komputerowego. Można wyróżnić dwa rodzaje translacji binarnej: statyczna oraz dynamiczna. Statyczna translacja binarna polega na przetłumaczeniu pliku wykonywalnego zawierajacego ˛ instrukcje maszyny emulowanej na plik wykonywalny maszyny emulujacej ˛ w celu późniejszego uruchomienia. Technika ta jednak nie pozwala na uruchamianie wszystkich typów programów. W szczególności nie jest możliwe uruchomienie programów wykorzystujacych ˛ samo-modyfikacj˛e (patrz [46]). Zmiany wprowadzone w uruchomionym programie zostana˛ przetłumaczone na instrukcje maszyny emulujacej ˛ i spowoduje to w konsekwencji bł˛edne działanie. Dodatkowo próba emulowania całego systemu operacyjnego ta˛ technika˛ byłaby bardzo niepraktyczna w zwiazku ˛ z koniecznościa˛ translacji statycznej nie tylko systemu operacyjnego, ale również i programów użytkownika. W efekcie statyczna translacja binarna jest rzadko stosowana w praktyce. Technika dynamicznej translacji binarnej skupia si˛e na tłumaczeniu bloków instrukcji podlegajacych ˛ emulacji w trakcie działania programu. W momencie napotkania nieprzetłumaczonego kodu emulator tłumaczy instrukcje systemu emulowanego na reprezentacj˛e pośrednia.˛ Reprezentacja pośrednia jest etapem translacji binarnej, pozwalajacym ˛ na wykonanie nast˛epujacych ˛ operacji: — zapis instrukcji logicznych wykonywanych wewnatrz ˛ bloku, — wygenerowanie poprawnych adresów docelowych dla instrukcji skoków wewnatrz ˛ tłumaczonego bloku instrukcji, — wygenerowanie wywołań odpowiednich procedur dla skoków poza przestrzeń aktualnie przetwarzanego bloku, — opcjonalna optymalizacja technikami takimi jak peephole optimization (patrz [3, 7]). Rozwiazanie ˛ to jest bardzo efektywne, ponieważ pozwala na zachowanie cz˛esto wykonywanych bloków i odwoływanie si˛e do nich bez konieczności ponownego tłumaczenia. Opcjonalne zastosowanie peephole optimization polega na automatycznym skanowaniu ciagłych ˛ 47 fragmentów kodu składajacych ˛ si˛e z od kilku do kilkunastu instrukcji (nazywanych oknem) w celu eliminacji zb˛ednych operacji lub zamianie instrukcji na ich szybsze odpowiedniki. Przykłady takich optymalizacji to np. zast˛epowanie wyrażeń, które można obliczyć w czasie kompilacji, wyrażeniami stałymi, czy zamiana operacji mnożenia przez liczb˛e b˛edac ˛ a˛ pot˛ega˛ liczby 2 na operacj˛e przesuni˛ecia bitowego z uwagi na szybsza˛ realizacj˛e w czasie wykonania. Peephole optimization może być stosowane zarówno na kodzie reprezentacji pośredniej jak i na kodzie konkretnego ISA. Technika dynamicznej translacji binarnej znana jest również pod nazwa˛ Just-in-time compilation i jest szeroko stosowana w popularnych środowiskach Java (patrz [89]) oraz .Net (patrz [107]), gdzie tłumaczeniu na ISA maszyny emulujacej ˛ podlega bytecode. Bytecode jest typem reprezentacji pośredniej neutralnej wzgl˛edem docelowego ISA – tzn. składa si˛e z podstawowego zestawu instrukcji, który może być przetłumaczony na każda˛ z obsługiwanych ISA. Kod bytecode z założenia nie wykorzystuje wszystkich możliwości docelowej architektury, ponieważ mogłoby to uniemożliwić przenośność na inne architektury. Dopiero dzi˛eki zastosowaniu translacji binarnej tworzony jest kod wykonywalny przystosowany do końcowej platformy. Wirtualizacja Szczególnym przypadkiem emulacji jest wirtualizacja. Technika ta wymaga spełnienia dodatkowego warunku zaw˛eżajacego ˛ definicj˛e 3.2.1: oprogramowanie X może być uruchamiane bezpośrednio na systemie komputerowym B. Warunek ten sprowadza si˛e do możliwości emulowania jedynie oprogramowania skompilowanego na t˛e sama˛ architektur˛e ISA, na której działa system emulujacy. ˛ Zasada działania wirtualizacji to trap-and-emulate (patrz [14]) – instrukcje emulowanego systemu komputerowego sa˛ wykonywane bezpośrednio przez procesor systemu emulujacego, ˛ aż napotkana zostanie instrukcja wymagajaca ˛ interakcji z urzadzeniami ˛ wejścia/wyjścia (patrz [2]). Oprogramowanie emulatora przechwytuje takie żadania, ˛ emuluje działanie sprz˛etu, a nast˛epnie zwraca odpowiedni rezultat do systemu emulowanego sygnalizujac ˛ gotowość rezultatu poprzez wygenerowanie emulowanego przerwania sprz˛etowego. Emulowane sa˛ również dodatkowe urzadzenia ˛ takie jak zegary, czy kontroler pami˛eci MMU. Wirtualizacja jest najszybsza˛ technika˛ emulacji, ponieważ nie wymaga ani interpretowania, ani tłumaczenia instrukcji systemu emulowanego. Niemniej warto zauważyć, że pierwsze implementacje trap-and-emulate nie były szybsze od translacji binarnej (patrz [2]), co było spowodowane cz˛estymi zmianami kontekstu procesora mi˛edzy systemem emulowanym a emulujacym. ˛ Na dzień dzisiejszy wirtualizacja jest najpopularniejsza˛ technika˛ emulacji, właśnie dzi˛eki swojej wydajności. 48 Każda z przedstawionych technik emulacji może być wykorzystywania w procesie wstrzykiwania bł˛edów, jednak wybrana metoda może okazać si˛e nieodpowiednia do pewnych zastosowań w zwiazku ˛ z powiazanymi ˛ z nia˛ ograniczeniami. Wybór emulatora na potrzeby niniejszej rozprawy wraz z uzasadnieniem został opisany w sekcji 3.4.1. 3.3. Zastosowanie emulacji Zastosowanie emulacji systemu komputerowego jest szczególnie użyteczne w badaniu niezawodności oprogramowania z zastosowaniem techniki wstrzykiwania bł˛edów. Wpływa na to wiele cech emulatorów zwi˛ekszajacych ˛ kontrol˛e nad środowiskiem eksperymentu oraz bogate możliwości badania efektów wstrzykiwanych bł˛edów. Poniżej przedstawione sa˛ najważniejsze cechy emulatorów, które czynia˛ je bardzo efektywnymi narz˛edziami w analizie niezawodności. Automatyzacja sterowania Emulator systemu komputerowego jest programem, który udost˛epnia funkcje pozwalajace ˛ sterować zachowaniem emulowanego systemu komputerowego. Możliwe jest zarówno uruchamianie, zatrzymywanie, restart emulowanej maszyny jak i podłaczanie/odł ˛ aczanie ˛ urzadzeń ˛ peryferyjnych. Funkcje te pozwalaja˛ na automatyzacj˛e scenariuszy testowania na poziomie oprogramowania, które w przypadku pracy z rzeczywistym urzadzeniem ˛ wymagałyby dodatkowych urzadzeń ˛ (np. watchdog). Połaczenie ˛ tych funkcji z możliwościa˛ automatycznej interakcji z oprogramowaniem uruchomionym w emulowanym systemie komputerowym pozwala przeprowadzać eksperymenty według nast˛epujacego ˛ schematu: — wprowadzenie emulowanego systemu komputerowego w pożadany ˛ stan (np. uruchomienie wymaganych aplikacji użytkownika), — symulacja bł˛edu w trakcie realizacji powierzonych zadań, — zebranie informacji o efektach bł˛edów/kondycji systemu, — przywrócenie wyjściowego stanu emulowanego systemu. Obserwowalność efektów bł˛edów Atutem stosowania emulowanego środowiska jest łatwy podglad ˛ stanu wewn˛etrznego emulowanego systemu. Precyzja inspekcji stanu jest ściśle zwiazana ˛ z poziomem emulacji – np. przy emulacji procesorów na poziomie ISA nie sa˛ dost˛epne stany ukrytych rejestrów4 . Niemniej emulatory pozwalaja˛ na zatrzymanie wykonania emulowanego systemu w dowolnej chwili i dokonanie diagnostyki pami˛eci, zawartości rejestrów procesora, jak i stanu emulowanych urzadzeń. ˛ Możliwe jest również zapisywanie historii interakcji poszczególnych urzadzeń ˛ – stworzenie dziennika przerwań obsługiwanych przez emulowany procesor jest 4 Sa˛ to rejestry niedost˛epne w interfejsie programistycznym procesora. 49 stosunkowo łatwe do realizacji jako moduł programu emulatora. W przypadku wystapienia ˛ sytuacji wyjatkowej ˛ na poziomie systemu operacyjnego na fizycznej maszynie informacje o stanie wewn˛etrznym sa˛ ograniczone najcz˛eściej do komunikatów wyświetlanych na ekranie (np. niebieski ekran bł˛edu systemu Windows lub komunikat kernel panic dla systemu GNU/Linux, patrz 2.1.2) lub wymagaja˛ zastosowania dedykowanych interfejsów debugowania (np. interfejs JTAG5 dost˛epny w wielu rozwiazaniach ˛ mikroprocesorowych – patrz [1]). Dopiero specjalistyczne systemy umożliwiaja˛ działania takie jak uruchomienie „zapasowego” systemu operacyjnego, zbierajacego ˛ informacje o bł˛edach i zapisujacego ˛ te dane na dysku do późniejszego zbadania. Możliwość multiplikacji emulowanego środowiska Istotna˛ cecha˛ emulatorów jest możliwość multiplikacji środowiska testowania. Ponieważ emulator jest programem komputerowym, możliwe jest uruchomienie wielu instancji. Pozwala to na jednoczesne przeprowadzanie wielu testów na jednym lub wi˛ekszej liczbie komputerów. Właściwość ta prowadzi do znacznego obniżenia kosztów dzi˛eki usuni˛eciu z procesu testowania konieczności dysponowania fizycznym sprz˛etem. Dodatkowo kopiowanie konfiguracji emulatora stanowi duże ułatwienie wzgl˛edem konfigurowania wielu fizycznych komputerów. Nieinwazyjne monitorowanie działania systemu Kontrola nad procesem wykonywania kodu systemu emulowanego daje unikatowa˛ możliwość monitorowania zachowania systemu bez ingerencji w oprogramowanie. Istnieje wiele mechanizmów śledzenia wykonania, zarówno oprogramowania działajacego ˛ w przestrzeni użytkownika (debuggery, profilery), jak i po stronie jadra ˛ systemu operacyjnego (sa˛ to mechanizmy dedykowane dla każdego systemu). Rozwiazania ˛ te działaja˛ jednak w oparciu o funkcje systemu operacyjnego. Zastosowanie emulacji pozwala na śledzenie wykonania przez zewn˛etrzny komponent bez uruchamiania dodatkowego oprogramowania, ani instrumentacji. Testowanie sterowników sprz˛etu Emulacja urzadzeń ˛ peryferyjnych pozwala na przetestowanie oprogramowania sterowników sprz˛etu w sytuacjach zarówno bł˛ednego działania, jak i trudnych do odtworzenia przez programist˛e granicznych wartości wyjść. Przykładem może być czujnik przyśpieszenia, gdzie uzyskanie wysokich lub wykraczajacych ˛ poza zakres działania urzadzenia ˛ wskazań wymagałoby rzeczywistego przyśpieszenia. Dzi˛eki zastosowaniu emulowanego rozwiazania ˛ możliwe jest uzyskanie dowolnego wyjścia z urzadzenia ˛ i przetestowanie reakcji stosu programowego, właczaj ˛ ac ˛ w to sterowniki systemu operacyjnego. Można rozwinać ˛ takie zastosowanie do rozpocz˛ecia prac nad sterownikami w emulowanym środowisku programistycznym dla nowych urzadzeń ˛ zanim urzadzenia ˛ te b˛eda˛ fizycznie dost˛epne dla 5 Ang. Joint Test Action Group. 50 programisty (rozwiazanie ˛ takie opisano w [49]) – konieczne jest jedynie przygotowanie programistycznego modelu danego urzadzenia ˛ w oparciu o specyfikacj˛e. Jest to szczególnie cenna cecha, ponieważ pozwala zredukować czas potrzebny do wydania gotowego produktu, jednocześnie umożliwiajac ˛ przeprowadzenie dodatkowych testów niezawodności. Testowanie oprogramowania w nowych dziedzinach Metody programowego wstrzykiwania bł˛edów SWIFI opisane w podrozdziale 2.4 polegaja˛ na usługach dost˛epnych w systemie operacyjnym. Jest to istotne ograniczenie z dwóch powodów: — zaburzenie działania systemu operacyjnego przy jednoczesnym poleganiu na jego usługach utrudnia zbieranie danych o wynikach eksperymentów oraz obniża poziom zaufania do ich poprawności, — brak możliwości badania efektów bł˛edów wyst˛epujacych ˛ w urzadzeniach. ˛ Zastosowanie emulacji we wstrzykiwaniu bł˛edów dzi˛eki łatwej obserwowalności efektów bł˛edów i możliwości nieinwazyjnego śledzenia wykonania stanowi unikatowe narz˛edzie pozwalajace ˛ testować system operacyjny, co eliminuje ograniczenia wspomnianych metod. Testowanie w bezpiecznych warunkach Dla wielu urzadzeń ˛ docelowe środowisko działania jest ucia˛żliwe lub szkodliwe dla człowieka ze wzgl˛edu na czynniki takie jak temperatura, czy promieniowanie. Emulacja pozwala na przeprowadzenie cz˛eści testów bez narażania programisty na niedogodności, czy niebezpieczeństwo. 3.4. Środowisko zautomatyzowanych testów W zwiazku ˛ z potencjalnymi zaletami zastosowania emulacji w badaniu niezawodności oprogramowania opisanymi w podrozdziale 3.3 autor przeprowadził przeglad ˛ dost˛epnych na rynku emulatorów oraz opartych o nie narz˛edzi wspierajacych ˛ wstrzykiwanie bł˛edów. W literaturze jednak niewiele jest prac poświ˛econych badaniu niezawodności systemów operacyjnych oraz technik obsługi bł˛edów wyst˛epujacych ˛ w przestrzeni jadra ˛ systemu operacyjnego (patrz 2.4). Dodatkowo nie udało si˛e autorowi znaleźć wyczerpujacych ˛ badań wpływu bł˛edów na różne architektury sprz˛etowe lub różne systemy operacyjne. Ch˛eć dokładnej analizy tych zagadnień stanowiła motywacj˛e do przygotowania oryginalnego środowiska zautomatyzowanych testów, które pozwala kompleksowo zbadać zachowanie systemów operacyjnych w obliczu bł˛edów. W niniejszym podrozdziale przedstawiono oryginalne narz˛edzie QEMU Fault Injection Framework (QEFI), którego podstawa˛ działania jest programowe symulowanie bł˛edów (SWIFI) stanowiacych ˛ model rzeczywistych bł˛edów (patrz rozdział 2) w emulowanym systemie 51 komputerowym. Opisane zostały decyzje projektowe podj˛ete przy tworzeniu QEFI, możliwości i ograniczenia jego zastosowań oraz realizowana metodyka przeprowadzania testów. 3.4.1. Wybór emulatora systemu komputerowego Na rynku dost˛epnych jest wiele rozwiazań ˛ pozwalajacych ˛ na uruchamianie systemu komputerowego w emulowanym środowisku. Najbardziej popularne programy pozwalajace ˛ na emulacj˛e to: Bochs, QEMU, User Mode Linux, VirtualBox, Virtual PC, Xen, KVM, VMWare. Spośród nich tylko Bochs stosuje technik˛e interpretacji opisana˛ w podrozdziale 3.2. Pozostałe emulatory stosuja˛ wirtualizacj˛e – wyjatkiem ˛ jest QEMU, które oprócz wirtualizacji może pracować również w trybie dynamicznej translacji binarnej (patrz [12]). Cz˛eść z wymienionych programów jest wykorzystywana w projektach badawczych. Bochs wykorzystany został w Instytucie Informatyki Politechniki Warszawskiej do badania testowalności procesora (patrz [98]), QEMU jest podstawa˛ projektu FAU Machine (patrz [93]) majacego ˛ na celu stworzenie w pełni deterministycznego emulatora, natomiast Xen posłużył jako platforma automatycznego testowania oprogramowania pod wzgl˛edem bezpieczeństwa (patrz [116]). Jako podstawa przygotowanego przez autora środowiska zautomatyzowanych testów został wybrany emulator QEMU. Decyzja ta uzasadniona jest nast˛epujacymi ˛ cechami QEMU: — wsparcie dla emulacji wielu architektur sprz˛etowych, — zadowalajaca ˛ wydajność – porównanie liczby cykli procesora potrzebnej do emulacji poszczególnych operacji maszyny emulowanej wzgl˛edem emulatora Bochs można znaleźć w [77], gdzie QEMU dla wi˛ekszości testowanych operacji było znacznie szybsze6 , — dynamiczna translacja – pozwala na nieinwazyjne monitorowanie systemu emulowanego, — licencja open-source, dzi˛eki czemu modyfikowanie źródeł nie jest ograniczone, a efekt prac może być przedstawiany publicznie, — przeprowadzone zostały badania potwierdzajace ˛ zbliżone efekty bł˛edów przy wstrzykiwaniu bł˛edów w system rzeczywisty i emulowany przez QEMU (patrz 3.4.2). Projektem badawczym, który również wykorzystuje QEMU jest wymieniony powyżej FAU Machine. Wyposażony jest on w możliwość wstrzykiwania bł˛edów, jednak autorzy położyli nacisk na funkcje, które sa˛ niewymagane z punktu widzenia niniejszej rozprawy – opracowany został zaawansowany interpreter j˛ezyka VHDL wraz z systemem pozwalajacym ˛ na dokładne odtworzenie sekwencji przerwań zgłaszanych w systemie. Dzi˛eki temu możliwe jest dogł˛ebne testowanie integracji i odporności na bł˛edy projektowanych nowych układów. Natomiast kluczowe dla niniejszej rozprawy funkcje takie jak zaawansowana automatyzacja scenariuszy testowych, profilowanie, możliwość zaburzania pracy różnych komponentów systemu, czy 6 Testowane były m.in. nast˛epujace ˛ operacje: kopiowanie zawartości rejestrów, operacje arytmetyczne, mnożenie liczb zmiennoprzecinkowych, skoki pośrednie z adresem docelowym odczytanym z rejestru EAX, obsługa przerwań Page fault. 52 Emulowany system (I) Poprawne [%] Manifestacja [%] Bład ˛ [%] Poprawne [%] Manifestacja [%] Bład ˛ [%] Poprawne [p.p.] Manifestacja [p.p.] Bład ˛ [p.p.] P3 Iteracje P2 Cel Program P1 ∆ = I − II Rzeczywisty system (II) Dane Kod Rejestry Dane Kod Rejestry Dane Kod Rejestry 8256 8240 1152 8192 5928 1152 b.d. 281248 1152 86,38 18,68 19,53 53,30 23,94 25,87 b.d. 72,40 20,12 2,97 60,84 79,43 0,06 64,25 72,14 b.d. 20,12 73,92 10,65 20,48 1,04 46,64 11,81 2,00 b.d. 7,48 5,96 87,06 20,43 18,84 51,61 21,36 24,83 b.d. 75,96 18,97 2,89 59,45 79,51 0,07 64,84 72,22 b.d. 17,93 74,79 10,05 20,12 1,65 48,32 13,80 2,95 b.d. 6,11 6,24 -0,68 -1,75 0,69 1,69 2,58 1,04 b.d. -3,56 1,15 0,08 1,39 -0,08 -0,01 -0,59 -0,08 b.d. 2,19 -0,87 0,60 0,36 -0,61 -1,68 -1,99 -0,95 b.d. 1,37 -0,28 Tabela 3.1: Wyniki wstrzykiwania bł˛edów dla systemu emulowanego i rzeczywistego (na podstawie: [80]) zbieranie i analiza zbiorczych wyników testowania sa˛ rozwini˛ete niewystarczajaco. ˛ Niemniej możliwe jest w przyszłości integracja cz˛eści funkcji FAU Machine z QEFI. 3.4.2. Dokładność emulacji Kluczowym aspektem dla wiarygodności testów przeprowadzanych z użyciem QEFI jest dokładność symulacji QEMU w przypadku wystapienia ˛ bł˛edu. W [80] opisano przebieg eksperymentu sprawdzajacego ˛ skuteczność QEMU jako platformy testowania oprogramowania. Autorzy przygotowali narz˛edzie wstrzykiwania bł˛edów w proces użytkownika zaimplementowane jako moduł jadra ˛ systemu operacyjnego GNU/Linux działajacego ˛ na architekturze x86. Narz˛edzie to wykorzystano do manipulowania danymi, kodem oraz rejestrami trzech przykładowych programów. Przebieg każdego wstrzykni˛ecia bł˛edu został opisany nast˛epujacymi ˛ cechami: wynik poprawny, wynik niepoprawny oraz manifestacja bł˛edu (manifestacja oznacza wyłacznie ˛ pojawienie si˛e dodatkowych komunikatów, wi˛ec program mógł si˛e zakończyć zarówno z wynikiem poprawnym, jak i niepoprawnym). Najistotniejszym elementem tego eksperymentu było przeprowadzenie testów w dwóch środowiskach: rzeczywistym oraz emulowanym przez QEMU. Wyniki eksperymentu zamieszczone sa˛ w tabeli 3.1. Według przedstawionych wyników w wi˛ekszości przypadków różnica w ilościowych wynikach wynosi poniżej jednego procenta. Uwiarygodnia to zastosowanie QEMU jako platformy testowania niezawodności oprogramowania, a dodatkowo wykryte różnice pomi˛edzy 53 systemem rzeczywistym i emulowanym stanowia˛ cenne źródło informacji o tym, jak należy poprawić sam proces emulacji. Warto podkreślić, że rozwiazanie ˛ opisane w [80] zaburza tylko i wyłacznie ˛ procesy aplikacji użytkownika – automatyzacja eksperymentów oraz zbieranie wyników jest realizowana przez aplikacje uruchomione w emulowanym systemie operacyjnym. Wyklucza to zaburzanie kodu sytemu operacyjnego, co jest jednym z celów niniejszej rozprawy. 3.4.3. Nieinwazyjne śledzenie wykonania Emulator QEMU wspiera działanie w dwóch trybach – wirtualizacji oraz dynamicznej binarnej translacji. W przypadku wirtualizacji możliwe jest wyłacznie ˛ emulowanie architektury zgodnej z architektura˛ systemu emulujacego, ˛ natomiast w przypadku translacji binarnej takiego ograniczenia nie ma (zagadnienie to zostało szerzej opisane w 3.2). Pomimo, że wirtualizacja jest technika˛ szybsza˛ od binarnej translacji, to zastosowanie tej drugiej niesie dodatkowe korzyści zwiazane ˛ ze zwi˛ekszona˛ obserwowalnościa˛ działania emulowanego systemu. Technika monitorowania wykonywanych instrukcji polega na modyfikacji procesu dynamicznej translacji tak, aby wygenerowane bloki kodu emulujace ˛ zachowanie poszczególnych instrukcji przeplatać z procedurami zbierajacymi ˛ dane dotyczace ˛ bieżacego ˛ kontekstu wykonania. Autor jest zaangażowany w rozwój tej techniki, a szczegółowy jej opis można znaleźć w [24, 23]. Dzi˛eki tej metodzie emulator może realizować nast˛epujace ˛ zadania: wyznaczanie pokrycia kodu, obserwacja przetwarzanych danych, określenie zaangażowania instrukcji wykonywanych w przestrzeni użytkownika i jadra ˛ sytemu operacyjnego przy realizacji poszczególnych usług. Nieinwazyjne śledzenie wykonania jest szczególnie użyteczne w kontekście wstrzykiwania bł˛edów, ponieważ nie wymaga uruchamiania żadnego oprogramowania profilujacego ˛ wewnatrz ˛ emulowanego systemu komputerowego. Zapobiega to sytuacji, w której po wstrzykni˛eciu bł˛edu emulowany system ulega awarii, zaburzajac ˛ działanie programu profilujacego ˛ lub uniemożliwiajac ˛ zapisanie wyników jego działania. W zwiazku ˛ z wymienionymi zaletami nieinwazyjnego śledzenia wykonania QEFI zostało wzbogacone o t˛e funkcj˛e. 3.4.4. Wydajność emulacji Wydajnościa˛ emulacji określany jest narzut czasowy przy wykonaniu oprogramowania w środowisku emulatora w porównaniu z wykonaniem na rzeczywistym systemie. Pomiar wydajności w przypadku QEMU jest zadaniem trudnym, ponieważ jest zależny od wielu czynników. W [77] przedstawione sa˛ wyniki pomiarów wydajności emulatorów QEMU i Bochs, w których położono nacisk na badanie wydajności emulacji poszczególnych instrukcji ISA i zarzadzania ˛ pami˛ecia.˛ W [24] autor przeprowadził pomiar wykorzystujac ˛ dost˛epny w QEMU specjalny tryb emulacji pojedynczego procesu systemu operacyjnym GNU/Linux. 54 Tryb ten polega na uruchomieniu programu z użyciem emulowanego procesora, natomiast wywołania systemowe sa˛ przekazywane do rzeczywistego systemu operacyjnego. Pomiary wydajności z [77] i [24], dały narzut odpowiednio 46 (od 0,26s do 12s) i 4,3 (od 4,7s do 20,35s) razy dłuższego działania niż bez emulacji. Oznacza to bardzo istotna˛ zależność wydajności emulacji od wybranego scenariusza poddawanego pomiarom. 3.4.5. Metodyka badań W wyniku prac prowadzonych przez autora nad automatyzacja˛ testów przygotowana została oryginalna metodyka badań wykorzystujacych ˛ emulator systemu komputerowego zaimplementowana w narz˛edziu QEFI. Wst˛epne prace nad QEFI opisane zostały w [23, 25, 26]. Celem metodyki jest przeprowadzanie serii zautomatyzowanych testów, pozwalajacych ˛ zebrać zbiorcze wyniki dotyczace ˛ podatności na bł˛edy testowanego systemu (SUT7 ). Podstawowe poj˛ecia Na potrzeby procesu przeprowadzania automatycznych testów zdefiniowane zostały nast˛epujace ˛ poj˛ecia: — SUT – instancja emulowanego systemu komputerowego. — Scenariusz – seria operacji interakcji z SUT. — Profilowanie – zbieranie informacji o zdarzeniach wyst˛epujacych ˛ w SUT. — Wstrzykni˛ecie bł˛edu – modyfikacja środowiska SUT symulujaca ˛ wystapienie ˛ bł˛edu. — Wynik – dane b˛edace ˛ celem realizacji scenariusza (np. przetworzony plik). — Funkcja oceny wyniku – funkcja wartościujaca ˛ jakościowo lub ilościowo rezultat wykonania scenariusza. — Test – pojedyncze wykonanie scenariusza wraz ze wstrzykni˛eciem bł˛edu. — Dziennik wykonania – zapis interakcji przeprowadzonej z SUT w ramach testu oraz dodatkowych informacji o parametrach wstrzykni˛ecia bł˛edu i danych nieinwazyjnego śledzenia. — Eksperyment – seria testów opartych o ten sam scenariusz różniaca ˛ si˛e wstrzykni˛etym bł˛edem (np. inna zaburzona komórka pami˛eci, inny moment wstrzykni˛ecia bł˛edu). Konfiguracja instancji SUT składa si˛e ze specyfikacji emulowanego systemu komputerowego oraz obrazów nośników pami˛eci masowej8 . Konfiguracja systemu zawiera informacje o architekturze procesora, pojemności pami˛eci RAM, urzadzeniach ˛ komunikacyjnych (np. interfejs sieciowy Ethernet, urzadzenia ˛ USB) oraz urzadzeniach ˛ pami˛eci masowej. Każdy SUT wyposażony jest w co najmniej jedno urzadzenie ˛ pami˛eci 7 Ang. System Under Tests. Obraz nośnika pami˛eci masowej jest to kopia zawartości i struktury danych zapisanych na nośniku w postaci jednego lub wi˛ecej plików. 8 55 masowej – np. emulowany dysk twardy lub karta pami˛eci Compact Flash z zainstalowanym systemem operacyjnym i dodatkowym oprogramowaniem podlegajacym ˛ testom. Scenariusz jest zapisem automatycznej interakcji z SUT. Operacje b˛edace ˛ składowymi scenariusza dziela˛ si˛e na dwa typy: komendy środowiska emulacji oraz operacje angażujace ˛ oprogramowanie działajace ˛ w SUT. Komendy służa˛ sterowaniu emulowanym systemem komputerowym – sa˛ to operacje takie jak podłaczenie ˛ urzadzeń ˛ peryferyjnych (np. pami˛eci masowej USB), wstrzymanie/wznowienie emulacji, wstrzykni˛ecie bł˛edu (patrz algorytm 3.3), czy ustanowienie warunkowego wstrzykni˛ecia bł˛edu. Operacje interakcji z oprogramowaniem sa˛ to dowolne działania korzystajace ˛ z usług SUT – np. nawiazanie ˛ połaczenia ˛ TCP/IP i zgłoszenie żadania ˛ HTTP lub wysłanie komendy przez konsol˛e dost˛epna˛ przez emulowany port szeregowy. Każda odpowiedź SUT jest rejestrowana w dzienniku wykonania i w późniejszym etapie służy ocenieniu dost˛epności poszczególnych usług oraz analizie typów zgłaszanych awarii. SUT może być profilowany pod katem ˛ wyst˛epowania pewnych zdarzeń. Profilowanie realizowane jest przez emulator i polega na wykrywaniu i odnotowywaniu zdefiniowanych akcji wykonanych przez SUT. Przykładowe zdarzenia to wykonanie przez emulowany procesor określonego typu instrukcji lub wykonanie instrukcji spod wskazanego adresu. Wstrzykni˛ecie bł˛edu oznacza modyfikacj˛e środowiska SUT symulujac ˛ a˛ wystapienie ˛ bł˛edu. Dla każdego bł˛edu określone jest urzadzenie, ˛ typ bł˛edu, lokalizacja oraz moment wstrzykni˛ecia. Wszystkie urzadzenia ˛ wspierane przez emulator moga˛ być wzbogacone o funkcj˛e symulacji bł˛edu – np.: pami˛eć RAM, urzadzenia ˛ peryferyjne, rejestry procesora. Dost˛epne typy bł˛edów oparte sa˛ na modelach opisanych w 2.2. Lokalizacja określa przestrzeń, która poddana zostanie zaburzaniu. Przykładowo dla pami˛eci RAM jest to zakres adresów, a dla procesora zbiór rejestrów, niemniej samo zaburzenie dotyczy tylko jednego, losowo wybranego zasobu – pojedynczej komórki pami˛eci lub rejestru. Moment wstrzykni˛ecia bł˛edu może być stały lub warunkowy. W przypadku stałego momentu wstrzykiwania bład ˛ zostanie wprowadzony zawsze na tym samym etapie wykonania scenariusza. Natomiast warunkowe wstrzykni˛ecie zwiazane ˛ jest z wystapieniem ˛ pewnego zdarzenia wyzwalajacego ˛ (np. zgłoszenia przerwania przez jedno z emulowanych urzadzeń ˛ lub wykonania określonej instrukcji przez procesor) oraz sprawdzeniem wyniku funkcji warunku wstrzykni˛ecia. W chwili wystapienia ˛ zdarzenia wyzwalajacego ˛ sprawdzana jest wartość funkcji warunku i w przypadku jego spełnienia uruchamiana jest procedura wstrzykni˛ecia bł˛edu. Kompletny scenariusz wymaga określenia oczekiwanego wyniku pozwalajacego ˛ stwierdzić, czy wstrzykni˛ety bład ˛ miał wpływ na system. Przykładowo wynikiem moga˛ być odpowiedzi działajacego ˛ w SUT serwera HTTP, rezultat próby zalogowania si˛e do systemu poprzez określony kanał komunikacyjny lub brak przekłamań w przetwarzanych przez SUT plikach. Dla otrzymanych wyników określone sa˛ funkcje oceny służace ˛ wartościowaniu efektów 56 wstrzykni˛ecia bł˛edu. Funkcje oceny pozwalaja˛ określić stopień realizacji powierzonego SUT zadania oraz parametrów funkcjonowania systemu. Przykładowe funkcje oceny realizacji zadania: — jakościowa charakterystyka wyniku (np. SUT nie odpowiada na wysyłane żadania), ˛ — ilościowy udział poprawnych danych (np. n z k przetwarzanych przez SUT plików ma poprawna˛ zawartość), — odst˛epstwo wyniku od wyniku referencyjnego (np. dla wyniku b˛edacego ˛ liczba˛ różnica mi˛edzy uzyskanym i oczekiwanym wynikiem, a dla wyniku w postaci ścieżki w grafie różnica w liczbie kraw˛edzi wzgl˛edem oczekiwanej ścieżki). Przykładowe parametry funkcjonowania systemu: — czas potrzebny SUT do wygenerowania wyniku, — obcia˛żenie (np. użyta pami˛eć, wykorzystanie procesora) podczas generowania wyniku, — informacja o wykrytych przez oprogramowanie bł˛edach, — czy i w jakim stopniu wynik został oznaczony jako niepewny z uwagi na wykryte w systemie bł˛edy. Opracowane algorytmy Schemat wykonania scenariusza został przedstawiony w postaci pseudokodu w algorytmie 3.1. Tak skonstruowany scenariusz pozwala na przeprowadzenie pojedynczego testu, którego celem jest zapis wpływu bł˛edu na SUT. Należy wyróżnić trzy główne etapy wykonania scenariusza: działania przygotowawcze (linie 16-18 algorytmu 3.1), wstrzykni˛ecie bł˛edu lub konfiguracja warunkowego wstrzykni˛ecia bł˛edu (linie 19-23) oraz przeprowadzanie operacji majacych ˛ na celu zbadanie, czy system wykonuje poprawnie powierzone zadania (linia 24). Działania przygotowawcze maja˛ na celu wprowadzenie SUT w odpowiedni stan poczatkowy ˛ oraz zebranie dodatkowych danych dotyczacych ˛ uruchomionego systemu – krok ten służy przykładowo oczekiwaniu na rozruch systemu operacyjnego w SUT, zalogowanie si˛e użytkownika przez konsol˛e szeregowa˛ i zebranie informacji o systemie. Wykonanie kroków poszczególnych etapów realizowane jest przez funkcj˛e execSteps. W trakcie wykonania scenariusza komendy emulatora oraz komendy przekazywane do SUT wydawane sa˛ funkcja˛ issueCommand (linie 5,9 algorytmu 3.1). W przypadku emulatora sa˛ to bezpośrednie komendy środowiska emulacji, natomiast komendy SUT moga˛ być dostarczane dowolnym kanałem (np. sieć lub konsola dost˛epna˛ przez port szeregowy). Odpowiedzi zapisywane sa˛ z użyciem funkcji readOutput (linie 6-7,10). Dla komend SUT odczytywane sa˛ dodatkowo komunikaty emulatora (linia 7) ze wzgl˛edu na możliwość generowania przez emulator dodatkowych informacji o przebiegu wykonania SUT (np. wystapienie ˛ zdarzeń wyzwalajacych ˛ warunkowe wstrzykni˛ecie bł˛edu lub informacje pochodzace ˛ z profilowania). Funkcje isSU T Command, getIdleT imeout, getReadT imeout, getChannel służa˛ odczytaniu właściwości pojedynczego kroku scenariusza. 57 Algorytm 3.1 Pseudokod wykonania scenariusza Input: Emulator, SU T, f aultData, initSteps, taskSteps, maxSize Output: executionLog 1: function EXEC S TEPS(steps) 2: log ← ∅; 3: for step in steps do 4: if isSU T Command(step) then 5: issueCommand(SU T, step); 6: log ← log ∪ readOutput(getChannel(step), getIdleT imeout(step), getReadT imeout(step), maxSize); 7: log ← log ∪ readOutput(Emulator, getIdleT imeout(step), getReadT imeout(step), maxSize); 8: else 9: issueCommand(Emulator, step); 10: log ← log ∪ readOutput(Emulator, getIdleT imeout(step), getReadT imeout(step), maxSize); 11: end if 12: end for 13: return log; 14: end function 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: executionLog ← ∅; startEmulator(); executionLog ← executionLog ∪ execSteps(initSteps); if ! isConditionalError(f aultData) then injectImmediateF ault(f aultData); else setupConditionalF aultInjection(f aultData); end if executionLog ← executionLog ∪ execSteps(taskSteps); terminateEmulator() return executionLog; Algorytm 3.2 przedstawia sposób działania funkcji readOutput. Funkcja readOutput służy akumulacji kolejnych linii tekstu w dzienniku wykonania. parametrami: source, idleT imeout, readT imeout oraz maxSize. Wywoływana jest z Parametr source oznacza źródło odczytu danych, czyli wyjście emulatora lub kanał komunikacji z SUT. Parametr idleT imeout oznacza jak długo należy czekać na pojawienie si˛e nowych danych w źródle. Parametr readT imeout służy ograniczeniu maksymalnego czasu zbierania danych przez funkcj˛e readOutput. Natomiast parametr maxSize oznacza maksymalna˛ liczb˛e linii odczytanych ze źródła. Parametry readT imeout oraz maxSize pozwalaja˛ wykryć sytuacj˛e generowania danych w źródle w nieskończonej p˛etli – wystarczajace ˛ do tego celu byłoby zastosowanie tylko jednego z tych parametrów, jednak ze wzgl˛edów praktycznych 58 Algorytm 3.2 Pseudokod funkcji zbierania dzienników wykonania 1: function READ O UTPUT(source, idleT imeout, readT imeout, maxSize) 2: result ← ∅; 3: startT ime ← readCurrentT ime(); 4: loop 5: line ← readLineT imeout(source, idleT imeout); 6: if line == ∅ then 7: result ← result ∪ IdleT imeoutM ark; 8: return result; 9: end if 10: result ← result ∪ line; 11: if |result|== maxSize then 12: result ← result ∪ M axSizeReachedM ark; 13: return result; 14: end if 15: if readCurrentT ime() − startT ime > readT imeout then 16: result ← result ∪ ReadT imeoutM ark; 17: return result; 18: end if 19: end loop 20: end function lepsze jest zastosowanie obu parametrów9 . Funkcja readOutput wykorzystuje wewn˛etrznie funkcj˛e readLineT imeout – odczytuje ona kolejna˛ lini˛e ze źródła, a jeżeli dane nie sa˛ dost˛epne przez określony czas zwracany jest specjalny znacznik braku wyniku (oznaczony symbolem ∅). Wykorzystana jest również funkcja readCurrentT ime, która zwraca aktualny czas. Przyczyna zakończenia działania funkcji jest zaznaczana w zebranym logu w postaci specjalnych znaczników IdleT imeoutM ark (brak nowych danych), M axSizeReachedM ark (osiagni˛ ˛ eto maksymalny rozmiar odpowiedzi) oraz ReadT imeoutM ark (przekroczono czas zbierania odpowiedzi). Natychmiastowe wstrzykni˛ecie bł˛edu (linia 20 algorytmu 3.1) realizowane jest funkcja˛ injectImmediateF ault, która została przedstawiona w algorytmie 3.3. Operacja modyfikacji środowiska SUT przyjmuje parametr f aultData, który zawiera informacje o urzadzeniu, ˛ typie oraz lokalizacji bł˛edu. Wstrzykni˛ecie musi być poprzedzone zatrzymaniem emulacji (funkcja pauseEmulation) oraz wyczyszczeniem danych w pami˛eci podr˛ecznej (cache) emulatora (funkcja f lushCachedData). Operacje te sa˛ konieczne ze wzgl˛edu na wybrany typ emulatora wykorzystujacy ˛ translacj˛e binarna˛ (patrz 3.2), gdzie przetłumaczone bloki kodu sa˛ przechowywane w pami˛eci podr˛ecznej i modyfikacja kodu źródłowego nie spowodowałaby 9 Parametr maxSize pozwala na ograniczenie wielkości dziennika wykonania, natomiast readT imeout pozwala skrócić czas działania funkcji w przypadku generowania nowych danych na źródle co kilkadziesiat ˛ sekund – dla źródła generujacego ˛ nowa˛ lini˛e co 30 sekund i maxSize = 6000 linii czas testu wydłużyłby si˛e do 50 godzin. 59 Algorytm 3.3 Pseudokod funkcji wstrzykni˛ecia bł˛edu 1: function INJECT I MMEDIATE FAULT(f aultData) 2: pauseEmulation(); 3: f lushCachedData(); 4: injectF ault(f aultData); 5: resumeEmulation(); 6: end function Algorytm 3.4 Pseudokod funkcji warunkowego wstrzykni˛ecia bł˛edu 1: f aultInjected ← F ALSE; 2: function CONDITIONAL FAULT I NJECTION C ALLBACK(f aultData) 3: if f aultInjected then 4: return ; 5: end if 6: if checkInjectCondition(f aultData) then 7: injectImmediateF ault(f aultData); 8: f aultInjected ← T RU E; 9: end if 10: end function ponownego ich przetłumaczenia. Po przeprowadzeniu wstrzykni˛ecia bł˛edu proces emulacji jest wznawiany (funkcja resumeEmulation). Warunkowe wstrzykni˛ecie bł˛edu jest operacja˛ dwuetapowa.˛ Polega na implementacji mechanizmu typu callback w emulatorze, który wywołuje zaprogramowane akcje w przypadku wystapienia ˛ określonego zdarzenia b˛edacego ˛ zdarzeniem wyzwalajacym ˛ dla warunkowego wstrzykni˛ecia bł˛edu. W pierwszym etapie ustanawiane jest zdarzenie, które ma powodować wyzwolenie procedury callback – jest to np. odczyt danych z emulowanego urzadzenia ˛ lub wykonanie określonego typu instrukcji przez procesor (linia 22 algorytmu 3.1). Drugim etapem jest wywołanie procedury callback, gdy wystapi ˛ określone zdarzenie. Algorytm 3.4 przedstawia działanie funkcji conditionalF aultInjectionCallback. Funkcja checkInjectCondition może być dowolnie sformułowana. Przykładowo bład ˛ może być wprowadzony z zadanym prawdopodobieństwem – oznacza to możliwość wstrzykni˛ecia bł˛edu przy kolejnych wystapieniach ˛ zdarzenia wyzwalajacego. ˛ Rozwiazanie ˛ to umożliwia zwi˛ekszenie pokrycia przestrzeni bł˛edów (patrz 2.5.2). Możliwe jest również wykorzystanie informacji z profilowania dost˛epnych w emulatorze lub uzależnienie wstrzykni˛ecia od wystapienia ˛ pewnej serii zdarzeń wyzwalajacych. ˛ Weryfikacja, czy SUT poprawnie wykonuje zadania, przeprowadzana jest poprzez wysyłanie kolejnych żadań. ˛ Żadania ˛ te sa˛ ściśle zwiazane ˛ z charakterem oczekiwanych wyników – moga˛ to być operacje zwiazane ˛ z przetwarzaniem plików, komunikacja˛ sieciowa˛ lub obsługa˛ urzadzeń. ˛ Dobór zadań powinien być podyktowany analiza,˛ które komponenty sa˛ celem ewaluacji wrażliwości na bł˛edy. 60 Algorytm 3.5 Pseudokod algorytmu przetwarzania wyników eksperymentu Input: executionLogs, propertyT ests Output: experimentStatistics 1: experimentStatistics ← ∅; 2: for executionLog in executionLogs do 3: testResults ← ∅; 4: for propertyT est in propertyT ests do 5: testResults[propertyT est] = analizeLog(experimentResults, propertyT est); 6: end for 7: experimentStatistics ← experimentStatistics ∪ testResults; 8: end for Pojedyncze wykonanie scenariusza jest nazywane testem, a seria testów różniacych ˛ si˛e parametrami wstrzykni˛etego bł˛edu składa si˛e na eksperyment. Wynikiem przeprowadzenia eksperymentu sa˛ dzienniki wykonania, które poddawane sa˛ analizie. Analiza polega na podsumowaniu nast˛epujacych ˛ cech przeprowadzonych testów: wyznaczenie wartości funkcji oceny, określenie parametrów wstrzykni˛etych bł˛edów, zebranie danych pochodzacych ˛ z profilowania. Badanie pojedynczych cech jest przeprowadzane przez osobna˛ procedur˛e. Algorytm 3.5 przedstawia pseudokod przetwarzania wyników eksperymentu. Procedury sprawdzajace ˛ kolejne cechy dzienników wykonania moga˛ mieć postać dowolnych programów. Procedura przyjmuje na wejściu dziennik wykonania testu, a wynikiem jest wartość badanej cechy. Procedury realizujace ˛ analiz˛e dzienników wykonania w podstawowej implementacji opiera si˛e o mechanizm wyrażeń regularnych, jednak moga˛ to być bardziej zaawansowane automaty (np. badajace ˛ średni czas odpowiedzi SUT). Funkcje oceny realizacji zadania sa˛ charakterystyczne dla każdego scenariusza. Natomiast zestaw procedur przedstawionych poniżej jest współdzielony mi˛edzy eksperymentami: — parametry funkcjonowania systemu: — czy wstrzykni˛ety bład ˛ został zamanifestowany, — czy zlecone zadania zostały wykonane poprawnie, — czy i jaki komunikat bł˛edu został zgłoszony przez system operacyjny, — czy komunikat o bł˛edzie zawierał informacj˛e stack-trace (patrz 2.1.2), — czy system operacyjny był dost˛epny przez cały przebieg eksperymentu, — parametry wstrzykni˛etych bł˛edów: — określenie fizycznego adresu zaburzanej pami˛eci, — określenie wirtualnego adresu zaburzanej pami˛eci10 , — wartość przechowywana w pami˛eci przed zaburzeniem, — wartość przechowywana w pami˛eci po zaburzeniu, — dane pochodzace ˛ z profilowania: 10 O ile informacja ta jest dost˛epna. 61 — liczba wywołań funkcji conditionalF aultInjectionCallback, — liczba wykonań zaburzonych instrukcji kodu11 , — wywołania funkcji alokacji pami˛eci w systemie operacyjnym SUT12 , — lista wywołanych funkcji systemu operacyjnego SUT13 . Do zliczania typów komunikatów systemu przyj˛eto nast˛epujac ˛ a˛ metodyk˛e: dla każdego artefaktu sprawdzany jest dziennik wykonania pod katem ˛ wyst˛epowania komunikatów danego typu bł˛edu (np. Paging request failed). Oznacza to, że jeżeli w pojedynczym dzienniku zapisane sa˛ komunikaty różnego typu to sa˛ one zliczone, natomiast komunikaty tego samego typu nie sa˛ zliczone kilkakrotnie. Przypadki generowania komunikatów w p˛etli można wykrywać poprzez odpowiednio przygotowana˛ procedur˛e. W wyniku automatycznej analizy dzienników wykonania uzyskane sa˛ zbiorcze wyniki pozwalajace ˛ ocenić wpływ danej konfiguracji bł˛edu na SUT. Baza procedur analizujacych ˛ dzienniki wykonania może być rozszerzana stosownie do potrzeb. Warto zaznaczyć, że dane uzyskane w ten sposób moga˛ być poddane procesowi eksploracji danych – opis udanego zastosowania eksploracji danych do danych pochodzacych ˛ z eksperymentów niezawodnościowych można znaleźć w pracach prowadzonych przez Instytut Informatyki Politechniki Warszawskiej [37, 101]. Zaprezentowana metodyka może być rozszerzana o dodatkowe funkcje, takie jak poprzedzenie eksperymentu uruchomieniem pojedynczego testu bez wprowadzania bł˛edu w celu wyznaczenia interesujacego ˛ podzbioru przestrzeni zaburzania (patrz 2.5.2). Uzupełnienie to zostało wykorzystane w 4.5.3, gdzie w poprzedzajacym ˛ teście wyznaczony został zbiór wywołanych funkcji systemu operacyjnego SUT, które były zaburzane podczas właściwego eksperymentu. 3.4.6. Architektura QEFI Metodyka opisana w sekcji 3.4.5 została zaimplementowana w środowisku QEFI. W niniejszej sekcji przedstawiona jest architektura, która pozwoliła na implementacj˛e wszystkich funkcji opisanej metodyki. Założenia b˛edace ˛ podstawa˛ opracowanej architektury to: 1. minimalna ingerencja w oprogramowanie QEMU, 2. rozdzielenie procesu emulacji od sterowania przebiegiem testu, 3. rozdzielenie przeprowadzania testu od analizy wyników, 4. możliwość uruchamiania równolegle wielu instancji testów. Założenie 1 zostało opracowane z myśla˛ o możliwej integracji opracowanych rozszerzeń z oficjalna˛ wersja˛ QEMU – minimalna ingerencja w kod źródłowy zwi˛eksza szanse na przyj˛ecie 11 12 13 Dotyczy eksperymentów zaburzania kodu systemu operacyjnego SUT. Wykorzystane w eksperymencie opisanym w 4.5.3. Dotyczy eksperymentów zaburzania kodu systemu operacyjnego SUT. 62 takiego kodu przez autorów projektu QEMU. Założenie 2 jest rozszerzeniem założenia 1 niosacym ˛ dodatkowe korzyści: uniezależnienie od technologii, w której zostało wykonane QEMU (j˛ezyk C), oraz możliwość zarejestrowania ewentualnej awarii oprogramowania QEMU. Założenie 3 umożliwia rozszerzanie bazy procedur analizujacych ˛ cechy dzienników wykonania bez konieczności ponownego przeprowadzania eksperymentu. Założenie 4 ma na celu umożliwienie skrócenia czasu przeprowadzania eksperymentu poprzez wykorzystanie wieloprocesorowych serwerów. Na podstawie opracowanych założeń przygotowane zostały trzy programy: — Zmodyfikowana na potrzeby QEFI wersja emulatora QEMU, — Nadzorca – oprogramowanie automatyzujace ˛ wykonanie testu, — Analizator – oprogramowanie analizujace ˛ dzienniki wykonania. Test jest przeprowadzany z udziałem instancji QEMU oraz instancji Nadzorcy, gdzie testowany system komputerowy (SUT) jest emulowany przez QEMU. Nadzorca oraz QEMU sa˛ osobnymi procesami w systemie operacyjnym i komunikuja˛ si˛e poprzez sieć protokołem TCP/IP. Założenie 4 realizowane jest poprzez uruchamianie wielu par procesów QEMU i Nadzorca, a sterowane jest to z udziałem skryptów powłoki systemu GNU/Linux. Zebrane przez Nadzorc˛e dzienniki wykonania testów przekazywane sa˛ do Analizatora po przeprowadzeniu eksperymentu w trybie wsadowym. Analizator jest programem w j˛ezyku Python realizujacym ˛ przetwarzanie dzienników pod katem ˛ wyst˛epowania poszczególnych cech zgodnie z algorytmem 3.5. Współpraca wymienionych komponentów przedstawiona jest na rysunku 3.1. Na rysunku komponenty oznaczone kolorem pomarańczowym sa˛ opracowane przez autora. Kolorem niebieskim zaznaczone sa˛ miejsca implementacji algorytmów opisanych w sekcji 3.4.5, kolorem szarym oznaczone jest oryginalne oprogramowanie QEMU, a kolorem zielonym oprogramowanie poddawane testom. Poniżej zamieszczony jest szczegółowy opis opracowanych programów oraz procesu przeprowadzania eksperymentów. Nadzorca Nadzorca jest głównym komponentem realizujacym ˛ automatyczne przeprowadzanie testu na podstawie przygotowanego scenariusza. Jest to osobny proces w systemie operacyjnym, który komunikuje si˛e z SUT poprzez jeden lub wi˛ecej kanałów (połaczenie ˛ 1 z rysunku 3.1): — tunelem do portu szeregowego SUT14 , — poprzez sieć TCP/IP: — bezpośrednie połaczenie ˛ z usługami SUT, 14 Tunel do portu szeregowego działa w sposób nast˛epujacy: ˛ oprogramowanie QEMU uruchamia serwer TCP/IP, gdzie dane przychodzace ˛ sa˛ przekazywane do portu szeregowego emulowanego systemu, a dane wysyłane przez emulowany system sa˛ przekazywane do klientów serwera TCP/IP. 63 Nadzorca Algorytm2) Scenariusz QEMU ) C Sterowanie środowiskiem emulacji P Moduł2 wstrzykiwania2 błędów Algorytm2C Dziennik wykonania Algorytm2h Analizator / Algorytmy2PF2/ h , 9 SUT Z Moduł śledzenia wykonania f Legenda: 222I2Oprogramowanie2QEFI. 222I2Oryginalne2oprogramowanie2QEMU. 222I2Testowane2oprogramowanie. 222I2Miejsce2wykonania2algorytmu. )2I2Wysyłanie2komend2do2SUT2-kanałem2jest2np.2sieć2lub 222222konsola2dostępna2przez2port2szeregowyO.2 C2I2Wysyłanie2komend2do2QEMU2-kanałem2jest2połączenie 222222TCPWIPO.2 P2I2Uruchamianie2procedury2wstrzykiwania2błędów2jako 222222opcja2QEMU.2 /2I2Wstrzyknięcie2błędu2poprzez2modyfikację2środowiska2 222222SUT.2 h2I2Zbieranie2danych2wyjściowych2z2SUT.2 f2I2Śledzenie2zdarzeń.2 Z2I2Wyzwalanie2opóźnionej2procedury2wstrzykiwania2 222222błędów.2 ,2I2Zbieranie2danych2o2wykonaniu. 92I2Przekazanie2dzienników2wykonania2do2analizy2w2 222222trybie2wsadowym.2 Rysunek 3.1: Architektura QEFI 64 — poprzez uruchomienie dodatkowych programów (np. ssh lub wget) skonfigurowanych na interakcj˛e z SUT. Tunel do portu szeregowego jest szczególnym kanałem komunikacji z SUT – systemy operacyjne uruchamiane w emulowanym systemie komputerowym skonfigurowano tak, aby udost˛epnić konsol˛e operatora oraz komunikować wszelkie wykryte bł˛edy przez port szeregowy. Podczas uruchamiania Nadzorca nawiazuje ˛ również połaczenie ˛ TCP/IP konsola˛ sterowania QEMU (połaczenie ˛ 2 z rysunku 3.1). Konsola sterowania udost˛epnia wszelkie operacje majace ˛ zwiazek ˛ z przebiegiem emulacji i wstrzykiwania bł˛edów – np. pauza/wznowienie emulacji, podglad/modyfikacja ˛ zawartości pami˛eci RAM emulowanego systemu, czy konfiguracja warunkowego wstrzykni˛ecia bł˛edu. Dodatkowo na konsoli wypisywane sa˛ informacje pochodzace ˛ z profilowania i procesu wstrzykiwania bł˛edów. Dzienniki wykonania stanowiace ˛ pełen zapis interakcji z SUT oraz emulatorem umieszczane sa˛ w plikach tekstowych. Pliki te sa˛ przedmiotem późniejszej analizy przez Analizator. Modyfikacje QEMU Oprogramowanie QEMU zostało wzbogacone na potrzeby QEFI o dwa dodatkowe moduły: moduł śledzenia wykonania oraz moduł wstrzykiwania bł˛edów. Moduł śledzenia wykonania jest odpowiedzialny za monitorowanie skonfigurowanych przy uruchomieniu QEMU zdarzeń. Przykładowymi zdarzeniami sa: ˛ — wykonanie instrukcji skoku przez emulowany procesor SUT, — wykonanie kodu SUT zaburzonego poprzednio wstrzykni˛eciem bł˛edu, — wywołanie wskazanych funkcji jadra ˛ systemu operacyjnego, — zgłoszenie przerwania przez wskazane urzadzenie, ˛ — wykonanie akcji przez wskazane urzadzenie. ˛ Cz˛eść z wymienionych zdarzeń nie jest dost˛epna do wykorzystania w każdej z konfiguracji SUT – szczegółowy opis wykorzystania poszczególnych zdarzeń wykorzystanych w eksperymentach przedstawiony jest w rozdziale 4. Moduł wstrzykiwania bł˛edów służy modyfikacji środowiska wykonania SUT w sposób, który symuluje wystapienie ˛ bł˛edu. Dowolne z emulowanych przez QEMU urzadzeń ˛ może być wzbogacone o funkcj˛e wstrzykiwania bł˛edów. Moduł wstrzykiwania bł˛edów realizuje zarówno natychmiastowe wstrzykni˛ecie bł˛edu (algorytm 3.3), jak i warunkowe (algorytm 3.4). Diagram sekwencji realizacji warunkowego wstrzykni˛ecia przedstawiony jest na rysunku 3.2. Analizator Analizator przetwarza dzienniki wykonania i realizuje algorytmy oceny w celu przygotowania zbiorczych statystyk kampanii. 15 Wyjściowe dane zapisywane sa˛ w formacie CSV15 Ang. Comma-separated Values. 65 Nadzorca QEMU SUT setupConditionalFaultInjection() issueCommand() obsługa emulowanej funkcji conditionalFaultInjectionCallback() Rysunek 3.2: Diagram sekwencji warunkowego wstrzykni˛ecia bł˛edu pozwalajacym ˛ na wizualizacj˛e oraz dalsza˛ analiz˛e przez operatora z użyciem oprogramowania typu Microsoft Excel, czy pakietu R-project16 . Przeprowadzanie eksperymentów Sposób wykonania pojedynczego testu umożliwia uruchomienie wielu testów jednocześnie. Jest to istotna cecha, dzi˛eki której wykorzystane sa˛ możliwości wieloprocesorowych systemów komputerowych do przeprowadzania eksperymentów na masowa˛ skal˛e. QEFI zostało wyposażone w funkcj˛e uruchamiania wielu instancji testów jednocześnie. Prawidłowe działanie takiej konfiguracji zostało zapewnione poprzez nast˛epujace ˛ decyzje projektowe: — każda para programów Nadzorca/QEMU uruchamiana jest w dedykowanym katalogu roboczym, — każda para programów Nadzorca/QEMU wykorzystuje unikatowe numery portów dla połaczeń ˛ TCP/IP, — liczby służace ˛ do inicjalizacji generatorów liczb pseudolosowych sa˛ przydzielane globalnie każdej instancji Nadzorcy17 , — obrazy dysków twardych emulowanych systemów komputerowych używane sa˛ w trybie migawki, czyli żadna modyfikacja zawartości dysku nie jest zapisywana do pliku obrazu, a jedynie przechowywana w pami˛eci przez czas działania SUT. QEFI z powodzeniem zostało uruchomione na serwerach Instytutu Informatyki Politechniki Warszawskiej, dzi˛eki czemu możliwe było znaczne skrócenie czasu potrzebnego na 16 http://www.r-project.org Generatory liczb pseudolosowych wykorzystywane sa˛ przy wyznaczaniu zaburzanych lokalizacji oraz w funkcji delayedF aultInjectionCallback przedstawionej w algorytmie 3.4. 17 66 przeprowadzanie eksperymentów. Kolejnym etapem zwi˛ekszajacym ˛ możliwości równoległego uruchamiania testów byłoby przystosowanie QEFI do rozproszonych środowisk typu cluster18 oraz grid19 . Instytut Informatyki Politechniki Warszawskiej z powodzeniem opracował rozwiazanie ˛ przeprowadzania eksperymentów SWIFI w środowiskach rozproszonych [99, 100]. Przystosowanie QEFI do takiego trybu pracy wymagałoby opracowania nast˛epujacych ˛ mechanizmów: — konfiguracji środowiska QEFI na w˛ezłach przetwarzania, — dystrybucji środowiska eksperymentu, — zbierania dzienników wykonania przeprowadzonych testów, — automatyzacji działania w˛ezłów przetwarzania. Możliwym rozwiazaniem ˛ problemu konfiguracji w˛ezłów przetwarzania byłoby przygotowanie obrazu maszyny wirtualnej (plik o wielkości około 3GB), który zawierałby przygotowane środowisko QEFI (skompilowane wersje programów Nadzorca oraz QEMU). Obraz należałoby pobrać na w˛ezły przetwarzania i uruchomić maszyn˛e wirtualna.˛ Rozwiazanie ˛ tego typu jest mniej pracochłonne od konfiguracji QEFI na każdym z w˛ezłów osobno, ponieważ maskowane sa˛ różnice poszczególnych w˛ezłów przetwarzania (np. różne systemy operacyjne, inne wersje zainstalowanych bibliotek programistycznych). Dystrybucja środowiska eksperymentu sprowadza si˛e do dystrybucji na w˛ezły przetwarzania trzech plików: obrazu dysku twardego SUT, konfiguracji QEMU dla SUT oraz konfiguracji Nadzorcy. Najwi˛ekszym z wymienionych plików jest obraz dysku SUT – w zależności od konfiguracji może to być od kilkuset MB to kilkunastu GB. Natomiast zbieranie dzienników wykonania może być realizowane poprzez automatyczne wysyłanie ich na dedykowany serwer plików. Oprogramowanie automatyzacji działania w˛ezłów przetwarzania powinno realizować nast˛epujace ˛ zadania: automatyczne pobieranie środowiska eksperymentu, przeprowadzenie eksperymentu oraz wysłanie dzienników wykonania przeprowadzonych testów do wskazanego repozytorium. 3.4.7. Charakterystyka bł˛edów symulowanych w QEFI W zaproponowanej architekturze QEFI możliwe jest symulowanie bł˛edów trwałych, przemijajacych ˛ i migoczacych ˛ modelowanych jako bł˛edy sklejeń, sprz˛eżeń oraz bit-flip. Bł˛edy te moga˛ być wprowadzane do poszczególnych emulowanych urzadzeń, ˛ takich jak pami˛eć RAM, rejestry procesora, czy pami˛eci masowe. Istotna˛ cecha˛ QEFI jest potencjalna możliwość symulowania bł˛edów behawioralnych np. zgłaszanie przez urzadzenie ˛ niemaskowalnych przerwań – bł˛edy tego typu były obserwowane przy zastosowaniu fizycznych zaburzeń pracy układu w [8] (promieniowanie radioaktywne, zwarcie/rozwarcie ścieżek układów, promieniowanie elektromagnetyczne). 18 Przetwarzanie na wielu homogenicznych systemach komputerowych (w˛ezłach) połaczonych ˛ wydajna˛ siecia.˛ 19 Przetwarzanie na wielu heterogenicznych systemach komputerowych (w˛ezłach) połaczonych ˛ siecia.˛ 67 Ze wzgl˛edu na wykorzystanie emulacji procesora nie jest brane pod uwag˛e badanie wpływu bł˛edów na mikroarchitektur˛e procesora – potok instrukcji, układ przewidywania skoków, czy pami˛eć podr˛eczna20 nie sa˛ emulowane w QEMU. Niemniej prowadzone sa˛ prace nad badaniem propagacji bł˛edów fizycznych na model logiczny. W [43] przedstawiono mechanizm wstrzykiwania bł˛edów na poziomie emulatora procesora przygotowanego w j˛ezyku VHDL. Dzi˛eki takiemu podejściu autorzy mogli wpływać na ukryte rejestry procesora, niewidoczne dla interfejsu programistycznego. Uzyskane wyniki pokazuja,˛ że cz˛eść bł˛edów wprowadzonych w ukryte rejestry manifestuje si˛e jako bł˛edy typowe dla pami˛eci (np. bł˛edy sklejeń w rejestrach), a cz˛eść nie manifestuje si˛e jako bł˛edy na poziomie logicznym. Świadczy to o komplementarności obu podejść. QEFI pozwala na efektywne21 przeprowadzanie eksperymentów ukierunkowanych na system jako całość z wykorzystaniem modeli bł˛edów, które sa˛ opracowywane wykorzystujac ˛ emulacj˛e na poziomie mikroarchitektury. Podobne zachowanie wia˛że si˛e z implementacja˛ emulacji urzadzeń, ˛ gdzie QEFI umożliwia wpływanie na protokół komunikacji urzadzenia ˛ i systemu na poziomie logicznym. Rozwiazaniem ˛ tego problemu byłaby integracja niskopoziomowych modeli urzadzeń ˛ w j˛ezyku VHDL (prace zmierzajace ˛ w tym kierunku opisane sa˛ w [93]), niemniej pewna˛ przeszkod˛e stanowi fakt, iż dost˛epność niskopoziomowych specyfikacji wielu urzadzeń ˛ wykorzystywanych komercyjnie jest ograniczona. 3.4.8. Zastosowanie metodyki Przestawiona metodyka jest oryginalnym rozwiazaniem ˛ realizujacym ˛ SWIFI. Dzi˛eki zastosowaniu emulacji możliwe jest badanie wpływu bł˛edów urzadzeń, ˛ pami˛eci oraz procesora na oprogramowanie zarówno systemu operacyjnego, jak i aplikacji użytkownika. Skuteczność zaproponowanej metodyki zależy od nast˛epujacych ˛ elementów: — doboru modeli wstrzykiwanych bł˛edów, — adekwatności profilu wstrzykiwanych bł˛edów w urzadzenia, ˛ — zgodności profilu testowania z profilem wykorzystania testowanego oprogramowania. Sposób wyznaczania modeli bł˛edów został opisany w 3.4.7. Zagadnienie opracowywania profilu bł˛edów najcz˛eściej wyst˛epujacych ˛ w urzadzeniach ˛ zostało przedstawione w [55]. Niestety badania tego typu nie sa˛ przeprowadzane dla urzadzeń ˛ oferowanych konsumentom lub ich wyniki nie sa˛ podawane do publicznej wiadomości. Możliwościa˛ poprawienia tego stanu jest wzbogacenie systemów operacyjnych o próby diagnozowania, czy dana awaria programowa została wywołana bł˛edami urzadzeń ˛ i zbieranie tych danych z udziałem telemetrii. 20 Symulacja bł˛edów w pami˛eci podr˛ecznej jest potencjalnie możliwa niewielkim nakładem pracy, po wzbogaceniu QEMU o jej emulacj˛e. 21 Przykładowo próba modelowania pami˛eci RAM w j˛ezyku VHDL do badania wpływu przekłamań na działanie aplikacji byłaby bardzo kosztowna obliczeniowo. 68 Problem opracowania profilu testowania dla systemów komputerowych typu COTS nie jest trywialny w zwiazku ˛ z szerokim spektrum zastosowań. Możliwe jest jednak określenie krytycznych scenariuszy, czy niebezpiecznych stanów. Przykładem wrażliwego scenariusza jest proces aktualizacji oprogramowania (patrz [85]). Natomiast przykładem niebezpiecznego stanu jest „zawieszenie” si˛e systemu bez możliwości dokonania jakiejkolwiek diagnostyki lub informacji o przyczynie awarii. Prace polegajace ˛ na zwi˛ekszaniu niezawodności powinny być ukierunkowane w pierwszej kolejności na te właśnie aspekty działania systemu, a nast˛epnie pozostałych funkcji zwiazanych ˛ z obsługa˛ żadań ˛ użytkownika. Zastosowanie emulacji wpływa również na sposób zbierania pomiarów czasu wykonania testów. Pomiar czasu testu wykonanego na emulowanym systemie mógłby być odmienny od czasu zmierzonego na rzeczywistym urzadzeniu ˛ ze wzgl˛edu na narzut emulacji22 oraz fakt, że emulator jest zwykłym procesem i podlega wywłaszczeniu – oznacza to, że wi˛eksze obcia˛żenie systemu przeprowadzajacego ˛ eksperyment wpływa na czas emulacji. Niemniej możliwe jest badanie liczby wykonanych instrukcji przez emulowany procesor i szacowanie na tej podstawie czasu wykonania poszczególnych etapów testu. Warto jednak zwrócić uwag˛e na ograniczenia wnioskowania na podstawie liczby wykonanych instrukcji przez emulowany procesor. W rzeczywistych procesorach te same instrukcje moga˛ mieć różny czas wykonania zależny od kontekstu – dost˛epności danych w pami˛eci podr˛ecznej, czy skuteczności działania układu przewidywania skoków. 3.5. Podsumowanie W niniejszym rozdziale przedstawiona została charakterystyka wykorzystania emulatora w badaniu niezawodności oprogramowania wraz z opisem oryginalnej metodyki badawczej i algorytmów zaimplementowanej w systemie QEFI opartym o emulator QEMU. Zaproponowana metodyka wraz z opracowanymi algorytmami oferuje korzyści wzgl˛edem dost˛epnych rozwiazań ˛ w postaci poddawania testom systemu komputerowego jako całości, zwi˛ekszonej kontroli nad eksperymentem i możliwościa˛ nieinwazyjnego śledzenia wykonania. QEFI jest podstawowym narz˛edziem w badaniach opisanych w rozdziałach 4 i 5, gdzie posłużyło poszerzeniu stanu wiedzy o niezawodności różnych konfiguracji systemów komputerowych oraz projektowaniu i ocenie skuteczności nowych mechanizmów zwi˛ekszajacych ˛ niezawodność. 22 Czasy emulacji instrukcji nie odpowiadaja˛ czasom wykonania instrukcji przez rzeczywisty procesor [77]. 69 4. Badania eksperymentalne Zastosowanie QEFI w procesie wstrzykiwania bł˛edów wprowadza nowe możliwości badania niezawodności systemów komputerowych. Opracowano oryginalne scenariusze eksperymentów oparte o metodyk˛e opisana˛ w rozdziale 3, które ukierunkowane sa˛ na badanie różnych architektur sprz˛etowych, systemów operacyjnych, a także poszczególnych komponentów systemu operacyjnego GNU/Linux. Uzyskane wyniki pozwalaja˛ poszerzyć stan wiedzy poprzez porównanie charakterystyk badanych systemów oraz służa˛ identyfikacji krytycznych cz˛eści systemu operacyjnego. Przeprowadzenie eksperymentów opartych o ten sam scenariusz testowy z zastosowaniem SUT wykorzystujacych ˛ różne architektury jednostek przetwarzajacych ˛ pozwala porównać podatność na bł˛edy różnych architektur (poziom ISA). Eksperymenty wykorzystujace ˛ taka˛ sama˛ architektur˛e sprz˛etowa,˛ ale różne systemy operacyjne, pozwalaja˛ ocenić wpływ sposobu implementacji systemu operacyjnego na wrażliwość na bł˛edy. Ostatnia cz˛eść rozdziału poświ˛econa została opisowi eksperymentów ukierunkowanych na badanie wrażliwości systemu operacyjnego GNU/Linux. Zrealizowane zostały eksperymenty symulujace ˛ bł˛edy wyst˛epujace ˛ w różnych urzadzeniach ˛ emulowanych systemów. W szczególności uwaga została poświ˛econa eksperymentom profilowanym na różne typy danych wykorzystywanych przez system operacyjny. Uzyskane wyniki eksperymentów zaburzania kodu, stosu oraz danych alokowanych systemu operacyjnego pozwalaja˛ na określenie zachowania systemu komputerowego w przypadku wystapienia ˛ bł˛edów oraz wyznaczenie wartości metryk opisanych w rozdziale 2. Zastosowanie profilowania pozwoliło również na znaczne zwi˛ekszenie efektywności przeprowadzonych eksperymentów. Zebrane dane stanowia˛ punkt wyjścia dla dalszych rozważań dotyczacych ˛ projektowania mechanizmów zwi˛ekszania niezawodności przedstawionych w rozdziale 5. 4.1. Plan przeprowadzonych eksperymentów Celem przeprowadzonych eksperymentów jest zbadanie wrażliwości na bł˛edy oprogramowania systemów operacyjnych, a nast˛epnie opracowanie nowych mechanizmów zwi˛ekszania niezawodności. Brany pod uwag˛e jest szeroki aspekt zastosowania systemów operacyjnych – różnych implementacji systemów, wykorzystania różnych architektur sprz˛etowych, a także wrażliwości na bł˛edy poszczególnych komponentów systemu. 71 QEFI dzi˛eki swojej architekturze umożliwia przeprowadzanie nowych typów eksperymentów: porównanie architektur sprz˛etowych na poziomie ISA, porównanie różnych implementacji systemów operacyjnych, a także eksperymenty ukierunkowane na szczegółowe badanie niezawodności oprogramowania wskazanego systemu operacyjnego. W celu ilustracji tych możliwości zostały opracowane oryginalne scenariusze eksperymentów. Eksperymenty opisane w niniejszym rozdziale prezentuja˛ możliwości QEFI według nast˛epujacego ˛ schematu: najpierw przedstawione sa˛ eksperymenty służace ˛ całościowemu porównywaniu różnych konfiguracji SUT w obliczu bł˛edu tego samego typu, a nast˛epnie szczegółowym badaniom poddany został wybrany system z wykorzystaniem mechanizmów profilowania oraz zastosowaniem bł˛edów innych typów (bł˛edy symulowane w emulowanych urzadzeniach). ˛ Główne założenie dotyczace ˛ projektowania scenariuszy to wykorzystanie krytycznych usług systemu komputerowego. W szczególności dotyczy to możliwości komunikacji i diagnostyki systemu, a także wykorzystania usług systemu operacyjnego niezb˛ednych do działania aplikacji (np. zarzadzanie ˛ procesami, pami˛eć wirtualna, system plików, wykorzystanie wskazanych urzadzeń). ˛ Przy badaniu niezawodności systemu operacyjnego konieczny jest odpowiedni dobór uruchomionych aplikacji, które korzystaja˛ z jego usług. Warto zauważyć, że nacisk położony jest na sposób interakcji aplikacji z systemem operacyjnym, ponieważ wiele aplikacji użytkownika realizujacych ˛ zupełnie inne funkcje może korzystać z tych samych usług systemu. Przykładowo program wypisujacy ˛ zawartość pliku tekstowego na konsol˛e użytkownika oraz program wyliczajacy ˛ sum˛e md5 zawartości pliku maja˛ zupełnie inna˛ implementacj˛e, inaczej obcia˛żaja˛ procesor, ale oba z nich wykorzystuja˛ przede wszystkim interfejs systemu plików oraz dost˛ep do konsoli użytkownika. Istotny jest również kontekst uruchamiania tych aplikacji – w zależności od lokalizacji przetwarzanego pliku moga˛ być wywoływane procedury systemu operacyjnego odpowiedzialne za dost˛ep do dysku twardego, peryferyjnych urzadzeń ˛ pami˛eci (np. karty Compact Flash, Pendrive USB), czy zasobów sieciowych (przy wykorzystaniu NFS1 ). Podczas opracowywania scenariuszy zostało przyj˛ete założenie, iż eksperymenty ukierunkowane na różne architektury sprz˛etowe oraz implementacje systemów operacyjnych wykorzystuja˛ ten sam scenariusz w celu umożliwienia porównania wyników. Założenie to wynika z ch˛eci określenia wrodzonej podatności na bł˛edy różnych konfiguracji, niemniej wia˛że si˛e z pewnymi ograniczeniami. Opracowany scenariusz musi być możliwy do uruchomienia z minimalnymi modyfikacjami na wszystkich systemach operacyjnych. Dodatkowo w zwiazku ˛ z wykorzystaniem różnych emulowanych architektur sprz˛etowych ograniczona jest możliwość profilowania SUT. Opracowanie mechanizmów profilowania opisanych w 3.4 wymaga ingerencji w oprogramowanie emulatora specyficzne dla emulowanej architektury 1 Ang. Network File System. 72 oraz dogł˛ebnej analizy implementacji systemu operacyjnego działajacego ˛ w SUT. Niemniej scenariusz opisany w 4.2 i wykorzystany w 4.3 i 4.4 pozwala na efektywne porównanie badanych systemów komputerowych bez zastosowania tych mechanizmów – SUT w jego przebiegu realizuje usługi zwiazane ˛ obsługa˛ konsoli operatora, zarzadzaniem ˛ procesami, komunikacja˛ sieciowa˛ oraz systemem plików. Profilowanie zostało zaimplementowane dla systemu działajacego ˛ pod kontrola˛ systemu GNU/Linux na architekturze x86 i wykorzystane w eksperymentach opisanych w 4.5.1, 4.5.3 – implementacja może być również przeniesiona na pozostałe konfiguracje stosownie do potrzeb. Eksperymenty ukierunkowane na badanie zachowania jadra ˛ systemu operacyjnego przy bł˛edach w urzadzeniach ˛ wejścia/wyjścia opisane w 4.5.1 wykorzystuja˛ scenariusze sprofilowane pod katem ˛ wykorzystania urzadzeń. ˛ Dla wstrzykiwania bł˛edów w protokół wymiany danych pomi˛edzy systemem operacyjnym i interfejsem sieciowym wykorzystano ponownie scenariusz opracowany w 4.2, ponieważ wykorzystuje on usługi sieciowe. Natomiast dla eksperymentów wstrzykiwania bł˛edów w urzadzenia ˛ zwiazane ˛ z obsługa˛ USB opracowano dedykowany scenariusz. W eksperymentach opisanych w 4.5.2 zaburzana przestrzeń została zaw˛eżona do statycznego kodu2 , danych tylko do odczytu i danych statycznych (patrz 2.1.2) systemu operacyjnego. W eksperymentach wykorzystano również scenariusz opracowany w 4.2 w celu ilustracji poziomu zwi˛ekszenia wartości współczynnika manifestacji bł˛edów wzgl˛edem eksperymentów przeprowadzonych w 4.2. Eksperymenty zaprezentowane 4.5.3 wykorzystuja˛ mechanizmy profilowania opisane w 3.4 do zaw˛eżenia zaburzanej przestrzeni do kodu systemu operacyjnego wykonywanego3 w scenariuszu, a także stosu i danych alokowanych. scenariusze. Eksperymenty te oparte sa˛ o dwa Pierwszy z nich, to scenariusz opisany w 4.2 – wyniki uzyskane z jego użyciem moga˛ zostać porównane z wynikami eksperymentów opisanymi w 4.2 i 4.5.2 w celu ilustracji zwi˛ekszenia efektywności eksperymentów dzi˛eki zastosowaniu mechanizmów profilowania (poprzez zwi˛ekszenie wartości współczynnika manifestacji bł˛edów). Natomiast drugi scenariusz realizuje testowanie SUT udost˛epniajacego ˛ usług˛e serwera HTTP w celu zbadania efektów bł˛edów w scenariuszu realizowanym w wielu produkcyjnych systemach oraz zestawieniu tych wyników z wynikami uzyskanymi z zastosowaniem pierwszego scenariusza. W przypadku eksperymentów zaburzania pami˛eci RAM modelowano bł˛edy typu bit-flip. Uzasadnione to jest udokumentowanym cz˛estym wyst˛epowaniem tego typu bł˛edu (patrz 2.2.4). W przypadku bł˛edów urzadzeń ˛ również zastosowano bład ˛ typu bit-flip symulujac ˛ wyst˛epowanie zaburzeń w rejestrach tych urzadzeń. ˛ W planie eksperymentów przyj˛eto założenie o zbadaniu efektów wybranego typu bł˛edów w różnych konfiguracjach, niemniej inne typy bł˛edów 2 Kod wykonywany w przestrzeni jadra ˛ systemu operacyjnego, który nie jest cz˛eścia˛ ładowanego modułu (patrz 2.1.2). 3 Dzi˛eki czemu gwarantowana jest aktywacja bł˛edu. 73 (np. bł˛edy w rejestrach procesora, czy bł˛edy zgłaszania niemaskowalnych przerwań) moga˛ stanowić podstaw˛e dalszych badań. 4.2. Profilowanie wrażliwości na bł˛edy badanej architektury sprz˛etowej Podstawowym zagadnieniem zwiazanym ˛ z przeprowadzaniem eksperymentów jest określenie liczby testów wystarczajacej ˛ do określenia wiarygodnej charakterystyki wrażliwości na bł˛edy systemu. W celu wyznaczenia tej liczby dla eksperymentu wstrzykiwania pojedynczego bł˛edu typu bit-flip w pami˛eć RAM emulowanego systemu przeprowadzono eksperyment składajacy ˛ si˛e z 500 000 testów. Nast˛epnie zbadano statystyczna˛ wiarygodność uzyskanych wyników, określono bład ˛ w przypadku zmniejszenia liczby testów w eksperymencie oraz wyznaczono liczb˛e testów dla eksperymentów opisanych w 4.3 i 4.4. Cele poboczne przeprowadzonego eksperymentu to zebranie ogólnej charakterystyki zgłaszanych awarii oraz zbadanie wykorzystania pami˛eci przez system. Konfiguracja eksperymentu Emulowany system komputerowy jest to system x86 działajacy ˛ pod kontrola˛ systemu operacyjnego Debian Lenny z jadrem ˛ GNU/Linux w wersji 2.6.26. Obraz dysku twardego z zainstalowanym systemem pochodzi z oficjalnych repozytoriów projektu Debian4 . SUT ma dost˛ep do zasobów sieciowych poprzez emulowany interfejs Ethernet. Według założeń eksperymentu przekłamana komórka pami˛eci RAM jest wybrana losowo, a moment wstrzykni˛ecia bł˛edu jest stały (patrz 3.4.5) – założenia takie zostały wprowadzone, ponieważ w podstawowej konfiguracji emulator nie ma możliwości określenia przeznaczenia poszczególnych rejonów pami˛eci, ani nie jest wyposażony w dodatkowa˛ instrumentacj˛e pozwalajac ˛ a˛ określić stan emulowanego systemu operacyjnego. Wprowadzenie mechanizmów zbierajacych ˛ wymienione informacje wymaga dodatkowego nakładu pracy. Prace te zostały wykonane dla architektury x86, a ich wynik opisany jest w sekcjach 4.5.2 oraz 4.5.3). Niemniej warto zaznaczyć, że atutami wynikajacymi ˛ z modyfikacji bezpośrednio adresów pami˛eci fizycznej jest możliwość badania podatności na bł˛edy poszczególnych obszarów przestrzeni pami˛eci RAM oraz jednakowa procedura wstrzykiwania bł˛edów niezależnie od tego, czy wybrane komórki pami˛eci zawieraja˛ kod, czy dane emulowanego systemu (tak jak to ma miejsce w 4.5.3). Wada˛ takiego rozwiazania ˛ sa˛ przypadki zaburzania pami˛eci niewykorzystywanej przez system w momencie wstrzykni˛ecia, co powoduje, że bł˛edy nie sa˛ aktywowane. W celu ograniczenia tego efektu do minimum, podj˛eta została decyzja o użyciu najmniejszej ilości pami˛eci, która pozwala na uruchomienie emulowanego systemu komputerowego i przeprowadzenie eksperymentu. Wielkość pami˛eci została wyznaczona poprzez seri˛e prób uruchomienia emulowanego systemu komputerowego z 4 http://people.debian.org/˜aurel32/qemu/i386 74 1 2 3 4 5 6 7 8 [QEMU] Uruchomienie SUT. [ SUT] Zalogowanie si˛ e do systemu administratora przez konsol˛ e dost˛ epna˛ ,→ przez port szeregowy. [QEMU] Wstrzykni˛ ecie pojedynczego bł˛ edu typu bit-flip w losowo wybrana˛ ,→ komórk˛ e pami˛ eci RAM. [ SUT] Pobranie przez sieć pliku z lokalizacji sieciowej za pomoca˛ ,→ programu wget. [ SUT] Wypisanie na konsol˛ e operatora zawartości pobranego pliku. [ SUT] Utworzenie katalogu i przeniesienie do niego pobranego pliku. [ SUT] Ponowne wypisanie na konsol˛ e operatora zawartości pobranego pliku. [QEMU] Wyłaczenie ˛ SUT. Scenariusz QEFI 4.1: Zaburzanie pami˛eci RAM przy obsłudze konsoli operatora, komunikacji sieciowej oraz wykorzystaniu systemu plików różna˛ pojemnościa˛ pami˛eci RAM. W pierwszym kroku sprawdzane było 8 MB pami˛eci, a w każdym nast˛epnym pami˛eć o 8 MB wi˛eksza od wielkości w kroku poprzednim. Dla architektury x86 wymagana ilość pami˛eci została ustalona na 32 MB. Niemniej w celu umożliwienia porównywania wyników eksperymentów opisanych w niniejszym rozdziale (eksperymenty AMD64-GNU/Linux, PowerPC-GNU/Linux, MIPS-GNU/Linux, ARM-GNU/Linux, x86-GNU/Linux, x86-FreeBSD, x86-Minix) wprowadzone zostało dodatkowe założenie, aby wszystkie badane konfiguracje emulowanych systemów były wyposażone w taka˛ sama˛ ilość pami˛eci. Minimalna ilość pami˛eci, która spełnia te wymagania, została wyznaczona na 48 MB – próba ustawienia mniejszej ilości pami˛eci RAM powodowała, że system operacyjny skompilowany na architektur˛e AMD64 nie uruchamiał si˛e. Scenariusz testu5 uruchamianego w ramach eksperymentu składa si˛e z kroków zamieszczonych w scenariuszu 4.1. W powyższym zapisie znacznikami [QEMU] oznaczono komendy środowiska emulacji, natomiast znacznikami [SUT] komendy wysyłane do SUT (patrz 3.4.5, 3.4.6). Zdefiniowany scenariusz oprócz podstawowych usług systemu operacyjnego takich jak zarzadzanie ˛ procesami czy pami˛ecia˛ wykorzystuje dodatkowo nast˛epujace ˛ usługi: obsług˛e konsoli operatora, uruchamianie nowych procesów, stos sieciowy oraz system plików. Wyniki Artefaktami przeprowadzenia eksperymentu sa˛ dzienniki wykonania, które zgodnie z metodyka˛ (patrz 3.4.5) zostały poddane analizie. Badanie cech dzienników wykonano poprzez dopasowywanie wyrażeń regularnych na plikach b˛edacych ˛ zapisem przebiegu każdego eksperymentu. Określenie, czy zadanie zostało wykonane poprawnie polega na sprawdzeniu, czy dwukrotnie została wypisana na konsol˛e operatora zawartość pobranego pliku (odpowiedzi SUT w krokach 5 i 7 scenariusza 4.1). Komunikaty jadra ˛ systemu operacyjnego sa˛ wykrywane 5 W dalszej cz˛eści rozprawy poj˛ecia „scenariusz testu” oraz „scenariusz eksperymentu” stosowane sa˛ zamiennie i odnosza˛ si˛e do serii kroków interakcji z SUT zgodnie z definicja˛ zamieszczona˛ w 3.4.5. 75 dzi˛eki specjalnemu znacznikowi, który poprzedza wszelkie tego typu wiadomości wypisywane na konsol˛e operatora6 . Rozstrzygni˛ecie, czy system operacyjny pozostał dost˛epny polega na sprawdzeniu wyrażeniem regularnym, czy po kolejnych komendach wydawanych przez emulowanego administratora pojawiał si˛e znak zach˛ety7 . Czas wykonania pojedynczego testu wynosi od 3 do 4 minut w zależności od wydajności maszyny przeprowadzajacej ˛ eksperyment. Wi˛ekszość czasu poświ˛econego na test przypada na rozruch emulowanego systemu komputerowego (krok 1 w scenariuszu 4.1) – około 2 minut. Pozostały czas jest podzielony na okresy oczekiwania na odpowiedź systemu po wydanej komendzie. Czas wykonania eksperymentu składajacego ˛ si˛e z 500 000 iteracji testów to około 30 dni, przy czym wykorzystywane były maszyny o nast˛epujacych ˛ konfiguracjach: 4 x AMD Opteron 16C 6276 2.33GHz (64 procesory logiczne), 320 GB RAM; 2 x Intel Xeon CPU E5-2630 2.30GHz (24 procesory logiczne), 32 GB RAM. W przeprowadzonym eksperymencie bł˛edy zamanifestowały si˛e w 0,58% testów (jest to wartość współczynnika Fs ). Dokładność tego współczynnika zależna jest od liczby przeprowadzonych testów i możliwe jest określenie przedziału ufności. W tym celu można przedstawić eksperyment jako ciag ˛ prób Bernoulliego z parametrem p. Zgodnie z teoria˛ statystyczna˛ (na podstawie [66]) przedział ufności dla obserwowanego parametru p̂ i dokładności α wyrażony jest wzorem: Wzór 4.2.1. s [p̂ − zα/2 s p(1 − p) p(1 − p) ; p̂ + zα/2 ] N N ,gdzie p – parametr rozkładu Bernoulliego, p̂ – obserwowana wartość parametru p, α – dokładność oszacowania ufności, zα/2 – kwantyl rz˛edu 1 − α/2 standaryzowanego rozkładu normalnego, N – liczba prób. Dla α = 0, 05, czyli przedziałowi o ufności 95% wartość zα/2 wynosi 1,96. Pewnym problemem jest zależność wzoru 4.2.1 od nieznanej wartości parametru p. Niemniej można zastosować nierówność, że dla 0 ≤ p ≤ 1 zachodzi p(1 − p) ≤ 1 . 4 Przy podstawieniu wyznaczonych wartości przedział ufności wynosi [p̂ − 0, 001386; p̂ + 0, 001386]. Niemniej oszacowanie to jest zawyżone w przypadku, gdy wartość parametru p jest z zakresu 0 ≤ p ≤ 6 Znacznik ten składa si˛e ma nast˛epujacy ˛ format: „[znacznik czasowy wystapienia ˛ komunikatu]”. Przykład komunikatów opatrzonych takim zancznikiem znajduje si˛e na listingu 4.3 w liniach 2-34. 7 Znak konsoli operatora informujacy ˛ o gotowości przyj˛ecia kolejnej komendy. 76 0,0020 0,0010 ● ● ● ● ●● ●● ●●● ●●●● ●●●●●● ● ●● ●● ●● ●● ●● ●● ●● ●●● ●●● ●●● ●●● ● 0 Zakres przedzialu 95% ufnosci ● 50000 150000 250000 350000 450000 Liczba testów Rysunek 4.1: Bład ˛ wzgl˛edny w zależności od liczby testów w eksperymencie 0, 01, gdyż wtedy zachodzi nierówność p(1 − p) ≤ 0, 0099, co z kolei pozwala wyznaczyć zakres ufności na [p̂ − 0, 000276; p̂ + 0, 000276]. Z uwagi na długi czas przeprowadzania eksperymentu przygotowana została analiza majaca ˛ na celu określenie z ilu testów może składać si˛e eksperyment, aby zachować zbliżony poziom manifestacji bł˛edów jednocześnie minimalizujac ˛ czas potrzebny do przeprowadzenia testów. Na rysunku 4.1 przedstawiony jest wykres rozpi˛etości zakresu przedziału ufności w przy założeniu p̂ = 0, 0058 (wartość ta została wybrana jako najdokładniejszy dost˛epny pomiar współczynnika manifestacji bł˛edów) dla różnej liczby testów (N ) według wzoru 4.2.1. Na podstawie wykresu wybrana została liczba 50 000 testów w eksperymencie z uwagi na akceptowalny czas przeprowadzenia takiego eksperymentu (około 3 dni) oraz zakres przedziału ufności 95% na poziomie p̂ ± 0, 00066 (0,066 p.p.). W dalszej cz˛eści niniejszego podrozdziału wyniki przeprowadzonego eksperymentu 500 000 testów zostały przedstawione jako 10 iteracji eksperymentu składajacego ˛ si˛e 50 000 testów w celu zobrazowania różnic pomi˛edzy kolejnymi próbkami. Dodatkowo liczba 50 000 testów w eksperymencie została przyj˛eta w testach opisanych w podrozdziałach 4.3 oraz 4.4, co umożliwia porównywanie uzyskanych wyników. Wyniki przedstawiajace ˛ odsetek wstrzykni˛etych bł˛edów, które zostały zamanifestowane (współczynnik Fs ) w poszczególnych iteracjach eksperymentu, zostały zamieszczone na rysunku 4.2. Kolorem zielonym zaznaczono odsetek testów, w których wynik zadania realizowanego w scenariuszu był prawidłowy, natomiast kolorem czerwonym odsetek testów zakończonych nieprawidłowym wynikiem zadania – według kategorii manifestacji bł˛edu 77 0.8 0.6 0.4 0.0 0.2 Testy % PU + PS NU + NS 1 2 3 4 5 6 7 8 9 10 Rysunek 4.2: Wartość współczynnika Fs dla różnych iteracji eksperymentu badanej architektury sprz˛etowej opisanej w 2.5.2 wartości te sa˛ wyrażone jako Ps + Pu i Ns + Nu . Procentowy udział poszczególnych kategorii manifestacji bł˛edu został przedstawiony na rysunku 4.3. Przykłady typów manifestacji zostały przedstawione w dalszej cz˛eści niniejszego podrozdziału. Dost˛epność systemu przy nieprawidłowym wyniku końcowym (dla kategorii manifestacji Nu i Ns ) została przedstawiona na rysunku 4.4 z zastosowaniem kategorii dost˛epności systemu opisanych w 2.5.2. W przypadku testów, w których pojawiły si˛e komunikaty jadra ˛ systemu operacyjnego, przeprowadzono analiz˛e typów bł˛edów zgodnie z metodyka˛ opisana˛ w 3.4.5. Zestawienie procentowych udziałów różnych typów bł˛edów przedstawiono w tabeli 4.1. Rysunek 4.5 przedstawia współczynnik manifestacji bł˛edów w pami˛eci fizycznej dla obszarów pami˛eci wielkości 1 MB. Współczynnik ten wyrażony jest jako procent testów, podczas których zamanifestowany został bład, ˛ w stosunku do wszystkich testów wstrzykni˛ecia bł˛edu w dany obszar pami˛eci. Przykładowo dla iteracji 1 można odczytać, że w przedziale adresów fizycznych od 0 do 1048576 (1 MB) 7% wstrzykni˛etych bł˛edów spowodowało zamanifestowanie bł˛edu. tbhp Przykłady manifestacji bł˛edów Poniżej przedstawione sa˛ zaobserwowane w dziennikach wykonania różne typy manifestacji bł˛edów: Pu , Nu , Ns . Typ Ps został pomini˛ety, ponieważ różni si˛e on od Ns jedynie uzyskaniem prawidłowego wyniku, pomimo pojawienia si˛e komunikatów systemu operacyjnego. 78 100 80 60 40 0 20 Testy % PU PS NU NS 1 2 3 4 5 6 7 8 9 10 60 40 DU DS NDU NDS 0 20 Testy % 80 100 Rysunek 4.3: Rozkład typów zamanifestowanych bł˛edów w różnych iteracjach eksperymentu badanej architektury sprz˛etowej 1 2 3 4 5 6 7 8 9 10 Rysunek 4.4: Dost˛epność systemu operacyjnego w różnych iteracjach eksperymentu badanej architektury sprz˛etowej 79 10 5 Testy % 10 0 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 5 5 5 5 5 5 5 5 5 0 Testy % 1 10 0 Testy % 2 10 0 Testy % 3 10 0 Testy % 4 10 0 Testy % 5 10 0 Testy % 6 10 0 Testy % 7 10 0 Testy % 8 10 0 Testy % 9 10 4 MB Rysunek 4.5: Współczynnik Fs / MB pami˛eci fizycznej dla różnych iteracji eksperymentu badanej architektury sprz˛etowej 80 Komunikat [%] 1 2 3 4 5 6 7 Paging request failed 27,12 24,86 23,84 29,54 26,21 25,1 23,13 Segfault 21,02 23,74 24,15 21 20,71 25,1 19,93 Null dreference 10,85 14,53 12,07 11,39 13,27 14,12 12,81 Null dereference 0 6,44 4,47 4,33 3,56 4,53 7,45 4,63 Panic in interrupt 8,81 8,1 8,36 12,46 13,92 7,06 7,12 General protection 7,46 9,78 9,6 9,25 10,36 10,59 8,19 Bad PC value 3,73 5,03 8,05 3,2 7,77 3,53 7,83 Panic - kill init 3,39 3,35 3,1 4,27 2,91 1,96 4,27 Undefined instruction 2,03 3,63 6,5 6,76 8,41 4,31 6,76 Double fault 1,36 1,12 1,24 0,71 0,65 0,39 1,42 Bad page state 0,68 1,96 1,86 1,42 0,97 2,75 1,07 8 23,91 26,71 13,04 4,97 9,94 6,83 6,52 5,28 7,14 0,93 1,86 9 27,02 17,19 12,28 7,02 9,82 9,82 7,37 3,51 7,37 3,86 3,16 10 28,3 22,64 13,21 5,35 8,81 8,49 5,35 3,77 5,03 2,2 2,83 Tabela 4.1: Udział komunikatów zgłaszanych przez system operacyjny w różnych iteracjach eksperymentu 1 2 3 4 debian-i386:~# wget --progress=dot 194.29.167.156:2000 --%s-- 2013-02-24 07:48:40 Connecting to 194.29.167.156:2000... connected. HTTP request sent, awaiting response... 200 OK Listing 4.1: Przykład Pu Na listingu 4.1 przedstawiono zaobserwowana˛ manifestacj˛e bł˛edu polegajac ˛ a˛ na zmianie komunikatów prezentowanych użytkownikowi, co nie miało wpływu na wykonanie przez SUT powierzonego zadania (Pu ). Nieprawidłowości znajduja˛ si˛e w linii 2, gdzie wyst˛epuje znacznik %s oraz data. W eksperymentach, w których bład ˛ si˛e nie manifestuje linia wypisywana na tym etapie wykonania scenariusza ma postać: „-2013-03-26 03:46:12http://194.29.167.156:2000/”, czyli wystapiły ˛ dwie zmiany: — w miejscu wypisywania daty pojawił si˛e znacznik %s, — w miejscu wypisywania docelowego adresu URL wypisana została data. Obrazuje to jak bł˛edy wyst˛epujace ˛ w systemie moga˛ mieć pozornie nieszkodliwe efekty. W tym przypadku wynik powierzonego zadania nie zależał od przekłamanej linii, jednak łatwo wyobrazić sobie przypadek, gdy zmiana formatu wypisywanych danych może mieć negatywny wpływ na inne programy korzystajace ˛ z tych danych. 1 2 debian-i386:~# rm tmp/index.html rm: relocation error: rm: symbol sc0<vdcR+G9E0_e, version GLIBC_2.0 not ,→ defined in file libc.so.6 with link time reference Listing 4.2: Przykład Nu Listing 4.2 przedstawia manifestacj˛e typu Nu , która powoduje niewykryta˛ przez system sytuacj˛e awaryjna.˛ Wprowadzone zaburzenie spowodowało, że nie jest możliwe uruchomienie 81 żadnego programu wykorzystujacego ˛ standardowa˛ bibliotek˛e j˛ezyka C (libc), ponieważ uszkodzenie zaburzyło proces ładowania tej biblioteki współdzielonej (patrz 2.1.2). Awaria tego typu powoduje brak możliwości uruchomienia jakiegokolwiek nowego procesu w systemie. Listing 4.3 przedstawia manifestacj˛e typu Ns , w której jadro ˛ systemu operacyjnego zgłosiło sytuacj˛e awaryjna.˛ Jest to typowy dla systemu GNU/Linux komunikat, w którym zawarte sa˛ mi˛edzy innymi nast˛epujace ˛ informacje: — opis typu awarii (linia 2), — identyfikator procesora, który wykonywał zadanie ulegajace ˛ awarii (linia 5), — lista modułów załadowanych do jadra ˛ systemu operacyjnego (linia 6), — identyfikator procesu ulegajacego ˛ awarii i informacja o wersji jadra ˛ systemu operacyjnego (linia 8), — zawartości rejestrów procesora (linie 9-13), — informacje o procesie/watku ˛ systemu, na rzecz którego wykonywany był kod wywołujacy ˛ awari˛e (linia 14), — zawartość stosu (linie 15-17), — stos wywołań funkcji stack-trace (linie 19-30), — zrzut pami˛eci zawierajacej ˛ instrukcje wykonywane przez procesor (linia 32). Opis zgłaszanych komunikatów Komunikaty najcz˛eściej zgłaszane przez system operacyjny wymienione w tabeli 4.1 maja˛ nast˛epujace ˛ znaczenie: Paging request failed Próba odwołania si˛e przez kod wykonywany w przestrzeni jadra ˛ systemu operacyjnego do pami˛eci, która nie została wcześniej zaalokowana (patrz 2.1.2). Segfault Jest to komunikat analogiczny do Paging request failed, z ta˛ różnica,˛ że program wykonujacy ˛ nieprawidłowe odwołanie uruchomiony był w przestrzeni użytkownika (patrz 2.1.2). Null dereference Próba dereferencji wskaźnika majacego ˛ wartość 0. Null dereference 0 Komunikat ten jest analogiczny do komunikatu Null dereference, gdzie sam wskaźnik również jest przechowywany pod adresem 0. Panic in interrupt Wystapienie ˛ bł˛edu w trakcie wykonywania procedury obsługi przerwań (patrz 2.1.2). General protection Komunikat ten zgłaszany jest przy wszelkich naruszeniach zasad ochrony zdefiniowanych w procesorze. Oprócz nieprawidłowego dost˛epu do pami˛eci (np. pisanie do pami˛eci read-only, próba wykonania kodu ze strony nie majacej ˛ uprawnień wykonania) jest to także próba wykonania instrukcji uprzywilejowanych. Bad PC value Rejestr wskaźnika instrukcji ma niedozwolona˛ wartość (wykaz niedozwolonych wartości można znaleźć w [56]). 82 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 debian-i386:~# wget --progress=dot 194.29.167.156:2000 [1471925.388302] BUG: unable to handle kernel NULL pointer dereference at ,→ 00000282 [1471925.394970] IP: [<c227b080>] [1471925.397151] *pde = 00000000 [1471925.399116] Oops: 0000 [#1] SMP [1471925.400822] Modules linked in: loop button serio_raw parport_pc ,→ parport snd_pcsp psmouse snd_pcm snd_timer i2c_piix4 snd soundcore ,→ i2c_core snd_page_alloc evdev ext3 jbd mbcache ata_generic ,→ ide_cd_mod cdrom ide_disk libata scsi_mod dock ide_pci_generic piix ,→ ide_core e1000 floppy thermal processor fan thermal_sys [1471925.400822] [1471925.400822] Pid: 2028, comm: bash Not tainted (2.6.26-2-686 #1) [1471925.400822] EIP: 0060:[<c227b080>] EFLAGS: 00000282 CPU: 0 [1471925.400822] EIP is at 0xc227b080 [1471925.400822] EAX: 00000282 EBX: c0117357 ECX: 0000000a EDX: 00000002 [1471925.400822] ESI: c1046a40 EDI: b7000000 EBP: c1065580 ESP: c21e3e1c [1471925.400822] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 [1471925.400822] Process bash (pid: 2028, ti=c21e2000 task=c24584a0 ,→ task.ti=c21e2000) [1471925.400822] Stack: 08000000 c0163c45 00046a40 c1000000 00000000 ,→ 08356000 c21e3ea4 08356000 [1471925.400822] 00000000 00000001 bfae4000 c227bbf8 c2dc6b74 ,→ c2dc6b5c 08355fff c18416fc [1471925.400822] c18416fc c18416fc 08048000 c0164bc3 00000000 ,→ b73e3000 00000000 c21e3ea4 [1471925.400822] Call Trace: [1471925.400822] [<c0163c45>] free_pgd_range+0x15e/0x174 [1471925.400822] [<c0164bc3>] free_pgtables+0x86/0x93 [1471925.400822] [<c0165b9a>] exit_mmap+0x7f/0xd3 [1471925.400822] [<c012078e>] mmput+0x20/0x7e [1471925.400822] [<c0178751>] flush_old_exec+0x3e3/0x495 [1471925.400822] [<c019b55c>] load_elf_binary+0x310/0x1082 [1471925.400822] [<c016471c>] get_user_pages+0x2a0/0x334 [1471925.400822] [<c0177b3e>] copy_strings+0x169/0x173 [1471925.400822] [<c0177c03>] search_binary_handler+0x8f/0x1a4 [1471925.400822] [<c0178d58>] do_execve+0x138/0x1c6 [1471925.400822] [<c010213b>] sys_execve+0x2a/0x4a [1471925.400822] [<c0103857>] sysenter_past_esp+0x78/0xb1 [1471925.400822] ======================= [1471925.400822] Code: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ,→ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ,→ 00 00 00 <00> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ,→ 00 00 [1471925.400822] EIP: [<c227b080>] 0xc227b080 SS:ESP 0068:c21e3e1c [1471925.472978] ---[ end trace 1cb41acd1be81ded ]--- Listing 4.3: Przykład Ns 83 Panic - kill init Bł˛edy, które wystapiły ˛ spowodowały zakończenie procesu init – tj. przodka wszystkich procesów uruchomionych w systemie operacyjnym (patrz 2.1.2). Undefined instruction Próba wykonania instrukcji, która nie jest prawidłowa˛ instrukcja˛ zdefiniowana˛ w ISA. Double fault Wystapienie ˛ bł˛edu podwójnego, czyli zgłoszenie bł˛edu przez procesor w trakcie wykonania procedury obsługi innego bł˛edu. Bad page state Wykryto bład ˛ w strukturach danych odpowiedzialnych za zarzadzanie ˛ stronami pami˛eci wirtualnej (patrz 2.1.2). Wnioski Z analizy rysunku 4.3 wynika, że około 10-15% testów z zamanifestowanymi bł˛edami zakończyło si˛e uzyskaniem poprawnego wyniku (Ps + Pu ), a system operacyjny wykrywa obecność bł˛edu w około 75% przypadków (Ps + Ns ). Warto również zauważyć, że spośród testów zakończonych nieprawidłowym wynikiem (dost˛epność systemu przy nieprawidłowym wyniku przedstawiona jest na rysunku 4.4) ponad 60% cechuje brak dost˛epności systemu (N DU + N DS ), co uniemożliwia dalsza˛ interakcj˛e z systemem w celach diagnostycznych. Dodatkowo analiza tabeli 4.1 pozwala stwierdzić, że najcz˛eściej zgłaszane komunikaty przez system sa˛ zwiazane ˛ z bł˛edami pami˛eci (komunikaty Segfault, Paging request failed, Null dereference oraz Null dereference 0). Analiza zakresów adresów fizycznych, które powoduja˛ manifestacj˛e bł˛edów (rysunek 4.5), wskazuje wyraźnie, że niektóre obszary sa˛ kilkakrotnie bardziej podatne na wystapienie ˛ bł˛edu. Oznacza to, że różne rodzaje danych składowanych w pami˛eci (kod, stos, przetwarzane dane) maja˛ inny stopień podatności na bł˛edy. Jest to cenna obserwacja, ponieważ uzupełniona o informacj˛e jakiego typu dane były składowane w tych obszarach pami˛eci stanowi wskazówk˛e dla projektantów systemów komputerowych o podwyższonej odporności na bł˛edy. Dzi˛eki tej wiedzy, można obniżyć koszty produkcji systemu umieszczajac ˛ tylko dane pewnego rodzaju w droższej pami˛eci RAM wyposażonej w system ECC. Niemniej zastosowanie takiego rozwiazania ˛ wymaga wsparcia systemu operacyjnego. Długi czas pojedynczego eksperymentu jest wada˛ obecnej implementacji. Niemniej możliwe jest w przyszłości przyśpieszenie testu poprzez wykorzystanie opcji migawki stanu emulatora. Rozwiazanie ˛ takie polega na przygotowaniu migawki systemu przed wstrzykni˛eciem bł˛edu i uruchamianie kolejnych instancji eksperymentu z wykorzystaniem tych danych – pozwoliłoby to na wyeliminowanie z eksperymentu czasu potrzebnego na rozruch emulowanego systemu operacyjnego, czyli czas potrzebny na przeprowadzenie pojedynczego testu potencjalnie może być zredukowany z 4 do 2 minut. Wybrana metoda wstrzykiwania bł˛edów bezpośrednio w pami˛eć fizyczna˛ cechuje si˛e niskim poziomem manifestacji bł˛edów. Dodatkowym problemem wynikajacym ˛ ze sposobu implementacji QEMU sa˛ trudności w sprawdzeniu, czy dane spod zaburzonego adresu 84 fizycznego zostały aktywowane, co pozwoliłoby na wyznaczenie współczynnika naturalnej odporności I zgodnie z definicja˛ przedstawiona˛ w sekcji 2.5.2. Rozwiazanie ˛ tych problemów wia˛że si˛e z wykonaniem dodatkowych prac specyficznych dla konkretnej architektury emulowanego systemu – prace te zostały wykonane i ich wyniki opisano w sekcji 4.5.3. 4.3. Porównanie wrażliwości na bł˛edy różnych architektur sprz˛etowych Projektowanie systemów komputerowych o zwi˛ekszonej odporności na bł˛edy z zastosowaniem elementów COTS wymaga metodyki oceny wybranych elementów systemu. Podstawowym komponentem systemu komputerowego jest procesor. Wszelkie dane pozwalajace ˛ porównać jednostki przetwarzajace ˛ stanowia˛ cenny wkład przy wyborze najlepszej architektury. W literaturze można znaleźć niewiele opracowań zawierajacych ˛ takie porównania. Według autora najciekawsze eksperymenty można znaleźć w [48] oraz [21], gdzie autorzy opracowali system wstrzykiwania bł˛edów w przestrzeń systemu operacyjnego przy użyciu ładowanego modułu. Taka konfiguracja wstrzykiwania bł˛edów wymaga jednak osobnych maszyn do przeprowadzania eksperymentów i zbierania wyników. Powoduje to problemy przy skalowaniu środowiska testowego, przez co autorzy w [48] porównali zaledwie dwie platformy sprz˛etowe pracujace ˛ pod kontrola˛ tej samej wersji systemu operacyjnego opartego o jadro ˛ GNU/Linux. W przypadku [21] porównane sa˛ różne systemy operacyjne, jednak wszystkie uruchomione na różnych platformach sprz˛etowych. Utrudnia to wnioskowanie o cechach niezawodności samych systemów operacyjnych lub poszczególnych architektur, a dodatkowo wymaga przygotowania ładowanych modułów wstrzykujacych ˛ osobno dla każdego systemu operacyjnego. Zastosowanie QEFI umożliwia badanie czy poszczególne ISA naturalnie sprzyjaja˛ wi˛ekszej niezawodności w obliczu bł˛edów pami˛eci RAM ograniczajac ˛ trudności, które dotycza˛ metodyk opisanych w [48] i [21]. Zastosowanie emulacji pozwoliło na przeprowadzenie eksperymentów bez wykorzystania rzeczywistych urzadzeń ˛ (dzi˛eki czemu przetestowano wi˛eksza˛ liczb˛e architektur), a także wyeliminowało konieczność opracowywania dedykowanego oprogramowania wstrzykiwania bł˛edów na każda˛ z architektur. W niniejszym podrozdziale opisany jest eksperyment, którego celem było porównanie zachowania różnych architektur sprz˛etowych w obliczu pojedynczego bł˛edu typu bit-flip w pami˛eci RAM. Konfiguracja eksperymentu Badaniom poddane zostały nast˛epujace ˛ architektury: AMD64, ARM, MIPS, PowerPC oraz x86. W celu zminimalizowania różnic wynikajacych ˛ z oprogramowania uruchomionego na emulowanych systemach, wszystkie konfiguracje działały pod kontrola˛ systemu operacyjnego Debian Lenny z jadrem ˛ GNU/Linux w wersji 2.6.26. Obrazy dysków twardych z instalacjami 85 systemu operacyjnego dla różnych architektur zostały pobrane ze stron projektu Debian8 . Wszystkie instalacje zawieraja˛ oprogramowanie w tych samych wersjach i sa˛ w stanie, który jest osiagni˛ ˛ ety zaraz po zakończeniu procesu instalacji systemu operacyjnego. Dzi˛eki spójnym wersjom oprogramowania scenariusz testowy jest identyczny ze scenariuszem przedstawionym w podrozdziale 4.2. Dla każdej architektury przeprowadzono eksperyment składajacy ˛ si˛e z 50 000 testów – uzasadnienie takiej liczby testów zostało przedstawione w podrozdziale 4.2. Wyjatkiem ˛ jest architektura x86, która jest zbiorczym wynikiem 500 000 testów otrzymanych przy opracowywaniu eksperymentów z podrozdziału 4.2, z uwagi na fakt, iż jest to najdokładniejszy pomiar. Wyniki Sposób analizy dzienników wykonania jest taki sam jak dla eksperymentu opisanego w podrozdziale 4.2. Na rysunku 4.6 przedstawiony jest współczynnik manifestacji bł˛edu (Fs ) dla każdej z architektur. Procentowy udział poszczególnych kategorii manifestacji bł˛edu został przedstawiony na rysunku 4.7. Dost˛epność systemu dla testów, w których wynik przeprowadzenia scenariusza był nieprawidłowy zobrazowano na rysunku 4.8. Rysunek 4.9 przedstawia współczynnik manifestacji bł˛edów w pami˛eci fizycznej dla obszarów pami˛eci wielkości 1 MB. Tabela 4.2 zawiera rozkład typów komunikatów jadra ˛ systemu operacyjnego. Opis zgłaszanych komunikatów Cz˛eść komunikatów najcz˛eściej zgłaszanych przez system operacyjny została opisana w podrozdziale 4.2 na stronie 82. Poniżej znajduje si˛e opis pozostałych komunikatów, uwzgl˛ednionych w zestawieniu: Unaligned access Komunikat ten jest zgłaszany na architekturze MIPS i oznacza prób˛e odczytania instrukcji spod niewyrównanego adresu. Reserved instruction Próba wykonania instrukcji zarezerwowanej dla trybu jadra ˛ systemu operacyjnego w trybie użytkownika. Kernel bug detected Jest to komunikat oznaczajacy ˛ wystapienie ˛ bł˛edu podczas wykonywania kodu o nieokreślonym typie9 w przestrzeni jadra ˛ dla architektury MIPS. Exception in kernel mode Jest analogicznym komunikatem do Kernel bug detected dla architektury PowerPC. Sched while atomic Wywołanie planera zadań w trakcie wykonania sekcji krytycznej. EXT FS error Komunikat bł˛edu systemu plików EXT3. I/O error Komunikat bł˛edu zwiazanego ˛ z operacjami wejścia/wyjścia. 8 http://people.debian.org/˜aurel32/qemu/ Analiza kodu źródłowego systemu GNU/Linux dla architektury MIPS wykazała, że tylko cz˛eść bł˛edów ma zdefiniowane komunikaty (np. Paging request failed). Jeżeli bład ˛ nie ma dedykowanego komunikatu zgłaszany jest komunikat Kernel bug detected. 9 86 0.8 0.6 0.4 0.0 0.2 Testy % PU + PS NU + NS AMD64 PowerPC MIPS ARM x86 60 40 PU PS NU NS 0 20 Testy % 80 100 Rysunek 4.6: Wartość współczynnika Fs dla różnych architektur AMD64 PowerPC MIPS ARM x86 Rysunek 4.7: Rozkład typów zamanifestowanych bł˛edów na różnych architekturach 87 100 80 60 0 20 40 Testy % DU DS NDU NDS AMD64 PowerPC MIPS ARM x86 5 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 5 10 4 10 5 10 5 0 5 10 0 Testy % Testy % AMD64 PowerPC 0 Testy % MIPS 0 Testy % ARM 0 Testy % x86 10 Rysunek 4.8: Dost˛epność systemu operacyjnego na różnych architekturach MB Rysunek 4.9: Współczynnik Fs / MB pami˛eci fizycznej dla różnych architektur 88 Komunikat % Bad page state Bad PC value Null dereference Null dereference 0 Paging request failed Sched while atomic Double fault Exception in kernel mode EXT FS error General protection I/O error Kernel bug detected Page allocation failure Panic in interrupt Panic - kill init Reserverd instruction Segfault Unaligned access Undefined instruction Unclassified Tabela 4.2: sprz˛etowych AMD64 2,63 0 14,8 5,26 27,63 0,33 1,32 0 0 26,32 0 0 0 0 5,92 0 19,41 0 11,51 2,63 PowerPC 3,61 0 0 0 53,01 2,41 0 37,95 0 0 0 0 0,6 21,08 11,45 0 0 0 0 6,02 MIPS 4,11 0 0 0 49,32 0 0 0 0 0 0 10,96 0 20,55 8,9 17,81 0 19,86 0 7,53 ARM 2,22 0 30,37 21,48 45,93 0,74 0 0 0 0 0 0 0,74 12,59 13,33 0 0 0 12,59 1,48 x86 2,43 7,74 16,83 6,87 34,04 0,3 1,83 0 0,43 11,87 0,17 0 0 12,43 4,74 0 29,35 0 7,61 1,39 Komunikaty systemu operacyjnego zgłaszane na rożnych architekturach Page allocation failure Kounikat wyst˛epujacy ˛ na architekturach ARM i PowerPC, oznaczajacy ˛ wyczerpanie dost˛epnej pami˛eci operacyjnej. Komunikaty systemu operacyjnego, które nie zostały przypisane do żadnej z wymienionych kategori zgrupowane jako komunikaty typu „Unclassified”. Wnioski Zastosowanie emulatora systemu komputerowego pozwoliło na porównanie podatności na bł˛edy kilku architektur sprz˛etowych bez konieczności posiadania fizycznych urzadzeń. ˛ Dodatkowo wstrzykiwanie bł˛edu na poziomie emulatora znacznie upraszcza proces konfiguracji eksperymentu w porównaniu do zastosowania wstrzykiwania bł˛edu z użyciem ładowanych modułów systemu operacyjnego, które wymagaja˛ osobnej kompilacji na każda˛ z docelowych platform (podejście takie zastosowano w [48], gdzie porównano tylko dwie platformy: x86 i PowerPC). Platforma, która osiagn˛ ˛ eła najwi˛ekszy współczynnik manifestacji bł˛edu to AMD64 (na podstawie rysunku 4.6). Zachowanie takie może wynikać z faktu, że AMD64 jest jedyna˛ platforma˛ w zestawieniu, która działa na 64 bitowych adresach pami˛eci. Cecha ta wpływa na zwi˛ekszenie wykorzystywanej pami˛eci. Zostało to potwierdzone poprzez zebranie informacji o ilości wolnej pami˛eci w każdym z emulowanych systemów komputerowych. Po uruchomieniu 89 systemu operacyjnego na systemie opartym o architektur˛e AMD64 było dost˛epnych wyłacznie ˛ 10 MB dost˛epnej pami˛eci, podczas gdy na pozostałych systemach było to około 20MB. Interesujac ˛ a˛ obserwacja˛ jest brak korelacji mi˛edzy manifestacja˛ bł˛edów architektur CISC (x86 i AMD64) i RISC (PowerPC, MIPS, ARM). O ile różnica w odsetku manifestacji bł˛edów platform CISC może być wyjaśniona rozmiarami wykorzystywanych adresów pami˛eci, to w przypadku pozostałych architektur trudno jest stwierdzić jednoznacznie przyczyn˛e różnic i wymagałoby to dalszych badań. Niemniej przeprowadzone testy potwierdzaja˛ tendencj˛e wi˛ekszego odsetku manifestacji bł˛edów na platformie PowerPC wzgl˛edem platformy x86, co zostało opisane również w [48]. Niezależnie od architektury, dla testów zakończonych nieprawidłowym wynikiem, w około 50% przypadków system staje si˛e niedost˛epny (rysunek 4.8). Zebrane dane dowodza,˛ że na wszystkich emulowanych systemach pojawienie si˛e bł˛edu typu bit-flip, jeżeli jest zamanifestowany, w 85-90% przypadków skutkuje nieprawidłowym wykonaniem powierzonego zadania. Dodatkowo istotna˛ informacja˛ jest to, że jadro ˛ systemu operacyjnego wykrywa bład ˛ w znacznym stopniu (Ps + Ns z rysunku 4.7). Na platformach z rodziny RISC jest to około 45% zamanifestowanych bł˛edów, natomiast na platformach x86 i AMD64 odpowiednio 65% i 75%. Jest to przesłanka do tego, aby podjać ˛ badania skupiajace ˛ si˛e na diagnozowaniu przyczyny awarii przez system operacyjny i podj˛eciu działań naprawczych o ile jest to możliwe. Dodatkowa˛ wskazówk˛e dotyczac ˛ a˛ kierunku dalszych badań niesie analiza tabeli 4.2, gdzie na wszystkich platformach komunikat Paging request failed jest najcz˛eściej zgłaszany przez system operacyjny. Przeprowadzone badanie podatności różnych architektur systemów operacyjnych dostarcza interesujacych ˛ danych uzupełniajac ˛ stan wiedzy, jednak istotna˛ kwestia˛ jest niski współczynnik eksperymentów, które zakończyły si˛e manifestacja˛ bł˛edu. Jest to ucia˛żliwe ze wzgl˛edu na uruchamianie wielu eksperymentów, które nie przynosza˛ żadnych wartościowych wyników. Rozwiazaniem ˛ jest tworzenie eksperymentów sprofilowanych na różne cz˛eści systemu operacyjnego. Dzi˛eki takiemu podejściu oprócz zwi˛ekszenia poziomu manifestacji bł˛edu możliwe jest wyznaczenie lokalizacji w pami˛eci fizycznej poszczególnych cz˛eści systemu operacyjnego. Badania przeprowadzone zgodnie z tymi wytycznymi zostały opisane w sekcjach 4.5.2 i 4.5.3. 4.4. Porównanie wrażliwości różnych systemów operacyjnych W [21] można znaleźć porównanie wrażliwości na bł˛edy różnych systemów operacyjnych, ale nie jest ono w pełni satysfakcjonujace, ˛ ponieważ systemy operacyjne były uruchamiane na różnych architekturach sprz˛etowych. W eksperymencie opisanym poniżej zestawiono wyniki zaburzania pami˛eci systemów działajacych ˛ pod kontrola: ˛ GNU/Linux, kFreeBSD oraz 90 Minix działajacych ˛ na jednej architekturze sprz˛etowej. Dzi˛eki temu zbadano, czy systemy wykorzystujace ˛ mikrojadro ˛ lub jadro ˛ monolityczne (patrz 2.1.2), badź ˛ różne implementacje systemów operacyjnych opartych o jadro ˛ monolityczne różnia˛ si˛e pod wzgl˛edem podatności na bł˛edy. Konfiguracja eksperymentu Badaniom zostały poddane nast˛epujace ˛ systemy operacyjne: Debian Lenny oparty o jadro ˛ GNU/Linux w wersji 2.6.26, Debian Squeeze oparty o jadro ˛ kFreeBSD w wersji 7.2 oraz Minix w wersji 3.2. Obraz systemu opartego o jadro ˛ kFreeBSD został pobrany ze stron projektu Debian10 , natomiast stworzenie obrazu systemu Minix wymagało przeprowadzenia procesu instalacji systemu w nowo utworzonej instancji emulowanego systemu komputerowego. Wybór tych systemów operacyjnych jest uzasadniony nast˛epujacymi ˛ czynnikami: — wszystkie systemy działaja˛ na architekturze x86, — zestawienie systemów GNU/Linux oraz kFreeBSD pozwoli porównać podatność na bł˛edy różnych implementacji systemów opartych o architektur˛e jadra ˛ monolitycznego (patrz 2.1.2), — właczenie ˛ do zestawienia systemu Minix opartego o architektur˛e mikrojadra ˛ pozwoli porównać jego podatność na bł˛edy wzgl˛edem systemów opartych o architektur˛e jadra ˛ monolitycznego. Scenariusz testu w ramach eksperymentu jest identyczny ze scenariuszem przeprowadzonym w eksperymencie opisanym w podrozdziale 4.2 z wyjatkiem ˛ systemu Minix, gdzie zamiast programu wget został użyty program curl o podobnym działaniu. Było to spowodowane brakiem kompilacji programu wget dla systemu Minix. Znaczacym ˛ utrudnieniem jest fakt, że system Minix jest systemem ciagle ˛ rozwijanym i nie było możliwe skonfigurowanie testowanej wersji systemu tak, aby komunikaty jadra ˛ systemu operacyjnego były wypisywane na konsol˛e operatora dost˛epna˛ przez port szeregowy. Powoduje to, że niemożliwe było wyznaczenie procentowego udziału bł˛edów, które zamanifestowały si˛e komunikatami jadra ˛ systemu operacyjnego dla tego systemu, niemniej jednak możliwe jest zebranie informacji o rezultacie wykonywanego zadania oraz dost˛epności systemu. Konfiguracja typu bł˛edu, momentu wstrzykni˛ecia bł˛edu oraz rozmiaru pami˛eci RAM jest identyczna z eksperymentem przeprowadzonym dla różnych architektur sprz˛etowych (patrz 4.3). Dzi˛eki temu wyniki dla systemu operacyjnego Debian Lenny opartego na GNU/Linux sa˛ rezultatami uzyskanymi w eksperymencie opisanym w podrozdziale 4.2. Tak jak w przypadku porównania różnych architektur sprz˛etowych przeprowadzono 50 000 testów w pojedynczym eksperymencie. 10 http://people.debian.org/˜aurel32/qemu/kfreebsd-i386 91 0.8 0.6 0.4 0.0 0.2 Testy % PU + PS NU + NS kFreeBSD GNU/Linux Minix Rysunek 4.10: Wartość współczynnika Fs dla różnych systemów operacyjnych Wyniki Wyniki przedstawiajace ˛ odsetek eksperymentów zakończonych zamanifestowaniem bł˛edu (współczynnik Fs ) zostały zamieszczone na rysunku 4.10. Klasyfikacja wyników procentowych udziałów typu manifestacji bł˛edu według klasyfikacji opisanej w 2.5.2 jest przedstawiona na rysunku 4.11. Dost˛epność systemu dla testów, w których wynik przeprowadzenia scenariusza był nieprawidłowy zobrazowano na rysunku 4.12. Rysunek 4.13 przedstawia współczynnik manifestacji bł˛edów w pami˛eci fizycznej dla obszarów pami˛eci wielkości 1 MB. Natomiast tabela 4.3 zawiera rozkład najcz˛eściej zgłaszanych komunikatów systemu operacyjnego. Wnioski Wstrzykiwanie bł˛edów w oparciu o emulator systemu komputerowego pozwoliło na równie łatwe porównanie systemów operacyjnych jak w przypadku architektur komputerowych. Nie było konieczne tworzenie osobnych mechanizmów wstrzykiwania bł˛edu dla każdej platformy. Zestawienie procentowe zamanifestowanych bł˛edów (rysunek 4.10) wyraźnie pokazuje dwie tendencje: zarówno implementacja, jak i architektura mikrojadra/j ˛ adra ˛ monolitycznego systemu operacyjnego maja˛ wpływ na stopień wrażliwości na wstrzykni˛ete bł˛edy. System oparty o jadro ˛ kFreeBSD nie tylko cz˛eściej manifestował bł˛edy, ale też wynik końcowy rzadziej był prawidłowy (tylko 5% wyników w porównaniu z 12% dla GNU/Linux) i system w wi˛ekszej liczbie przypadków stawał si˛e niedost˛epny (rysunki 4.11, 4.12). Zdecydowanie wyróżnia si˛e system Minix, któremu najcz˛eściej udało si˛e wykonać powierzone zadanie. 92 100 80 60 40 0 20 Testy % PU PS NU NS kFreeBSD GNU/Linux Minix 60 20 40 DU DS NDU NDS 0 Testy % 80 100 Rysunek 4.11: Rozkład typów zamanifestowanych bł˛edów w systemach operacyjnych kFreeBSD GNU/Linux Minix Rysunek 4.12: Dost˛epność systemów operacyjnych 93 10 5 0 Testy % Minix 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 4 8 12 16 20 24 28 32 36 40 44 5 10 8 0 5 10 0 Testy % Testy % kFreeBSD GNU/Linux 4 MB Rysunek 4.13: Współczynnik Fs / MB pami˛eci fizycznej dla różnych systemów operacyjnych Komunikat % Bad page state Bad PC value Null dereference Null dereference 0 Paging request failed Sched while atomic Double fault EXT FS error General protection I/O error Panic in interrupt Panic - kill init Privileged instruction Segfault Undefined instruction Unclassified kFreeBSD 0,84 0 0 0 79,83 0 4,2 0 2,52 0 0 0 2,52 0 0 10,08 GNU/Linux 2,43 7,74 16,83 6,87 34,04 0,3 1,83 0,43 11,87 0,17 12,43 4,74 0 29,35 7,61 1,39 Tabela 4.3: Komunikaty o bł˛edach zgłaszane przez systemy operacyjne 94 Prawdopodobnie wynika to z faktu, że system Minix jest projektowany pod katem ˛ zwi˛ekszonej odporności na bł˛edy [52, 53, 54]. Wśród mechanizmów, które zwi˛ekszaja˛ tolerancj˛e na bł˛edy jest zredukowany rozmiar kodu wykonywanego w przestrzeni jadra ˛ systemu operacyjnego, a także koncepcja reinkarnacji usług systemu operacyjnego w przypadku awarii. Koncepcja ta polega na ponownym uruchomieniu usług (np. obsługi stosu sieciowego), które uległy awarii, w sposób przezroczysty dla użytkownika (maskowanie bł˛edów). Niestety sprawność tych mechanizmów nie mogła zostać sprawdzona w opisanym eksperymencie z uwagi na trudności ze skonfigurowaniem systemu Minix tak, aby komunikaty jadra ˛ systemu operacyjnego były wypisywane na konsol˛e operatora podłaczon ˛ a˛ przez port szeregowy. Analiza podatności zakresów pami˛eci fizycznej (rysunek 4.13) pozwala stwierdzić, że każdy z systemów ma inna˛ charakterystyk˛e podatności na bł˛edy. Systemy GNU/Linux oraz kFreeBSD maja˛ zbliżone charakterystyki, jednak kFreeBSD wykazuje znacznie wi˛eksza˛ podatność w niskich adresach pami˛eci fizycznej. Natomiast w przypadku Minix nie wyst˛epuja˛ rejony o znacznie podwyższonej podatności, przy czym należy podkreślić, że dla tego systemu przedstawione sa˛ wyłacznie ˛ wyniki dotyczace ˛ testów zakończonych nieprawidłowym wynikiem z uwagi na trudności w konfiguracji systemu Minix do wydruku komunikatów systemu komputerowego przez konsol˛e dost˛epna˛ przez port szeregowy. Interesujace ˛ jest zróżnicowanie komunikatów zgłaszanych przez GNU/Linux w porównaniu do kFreeBSD, gdzie wi˛ekszość wstrzykni˛eć bł˛edów manifestuje si˛e jako Paging request failed. Świadczy to o lepszej jakości oprogramowania GNU/Linux. Komunikaty te stanowia˛ cenna˛ wskazówk˛e przy diagnozowaniu awrii systemu i podejmowaniu procedur naprawczych. Pomimo dobrych wyników systemu Minix warto zaznaczyć, że system ten jest systemem eksperymentalnym. Świadcza˛ o tym problemy konfiguracyjne oraz niedost˛epność oprogramowania. GNU/Linux jest dojrzałym systemem używanym produkcyjnie i wszelkie rozwiazania ˛ zwi˛ekszajace ˛ jego niezawodność moga˛ mieć szerokie grono odbiorców oraz poszerzyć zastosowania tego systemu o dziedziny wymagajace ˛ zwi˛ekszonej niezawodności. 4.5. Eksperymenty ukierunkowane na jadro ˛ systemu operacyjnego W poprzednich podrozdziałach zostały przedstawione eksperymenty porównujace ˛ zachowanie różnych systemów operacyjnych oraz wybranego systemu operacyjnego w wersjach na różne platformy sprz˛etowe. Eksperymenty te pozwalaja˛ obserwować ogólne cechy tych konfiguracji, jednak istnieje potrzeba gł˛ebszej analizy w celu identyfikacji krytycznych komponentów. Wyznaczenie składowych, które sa˛ szczególnie podatne na bł˛edy, jest kluczowa˛ informacja˛ przy projektowaniu rozwiazań ˛ zapobiegajacych ˛ awariom. W niniejszym podrozdziale przedstawione sa˛ eksperymenty ukierunkowane na badanie niezawodności poszczególnych komponentów systemu operacyjnego. Zbadany został wpływ 95 bł˛ednie działajacych ˛ urzadzeń ˛ oraz bł˛edów pami˛eci w zależności od danych, które zostały zaburzone. Uzyskane wyniki skonfrontowano z wynikami eksperymentów przeprowadzonych innymi metodami, których opis można znaleźć w literaturze. 4.5.1. Bł˛edy urzadze ˛ ń wejścia/wyjścia Tworzenie oprogramowania obsługujacego ˛ urzadzenia ˛ wejścia/wyjścia jest zadaniem bardzo wymagajacym. ˛ Programiści najcz˛eściej dysponuja˛ ograniczonymi możliwościami śledzenia wykonania kodu i wiele scenariuszy testowych jest przygotowywanych w oparciu o specyfikacj˛e. W celu zbadania możliwości jakie daje użycie emulatora systemu komputerowego przy badaniu niezawodności oprogramowania sterowników urzadzeń ˛ wejścia/wyjścia przeprowadzono trzy eksperymenty. Obejmowały one przekłamania typu bit-flip w danych przekazywanych od urzadzenia ˛ do systemu operacyjnego. Zbadane zostały nast˛epujace ˛ przypadki: — wstrzykni˛ecie w dane pobrane z pami˛eci typu USB MSD11 , — wstrzykni˛ecie w zawartość rejestrów kontrolera USB typu UHCI12 udost˛epnionych systemowi operacyjnemu, — wstrzykni˛ecie w deskryptor odebranego pakietu interfejsu sieciowego karty e1000. Scenariusze eksperymentów opartych o USB obrazuja˛ podatność na bł˛edy wyst˛epujace ˛ na dwóch warstwach współpracy urzadzenia ˛ wejścia/wyjścia z systemem operacyjnym. W przypadku wstrzykni˛ecia bł˛edu w dane pobrane z pami˛eci USB MSD bład ˛ wyst˛epuje na zewn˛etrznym urzadzeniu ˛ (np. popularne urzadzenie ˛ typu pendrive), natomiast zaburzanie działania kontrolera USB jest symulacja˛ bł˛edu wyst˛epujacego ˛ w jednym z urzadzeń ˛ stanowiacych ˛ integralna˛ cz˛eść systemu komputerowego. W przypadku badania interfejsu sieciowego podj˛eta została próba rozszerzenia eksperymentów znanych z literatury polegajacych ˛ na zakłócaniu pakietów przychodzacych ˛ z sieci. Przykładowy opis takiego eksperymentu przeprowadzonego w Instytucie Informatyki Politechniki Warszawskiej można znaleźć w [38], gdzie przy użyciu mechanizmu netfilter/iptables13 zintegrowanego z systemem operacyjnym wprowadzano zmiany w zawartość pakietów. Eksperyment przeprowadzony z użyciem QEFI pozwolił natomiast zbadać protokół wymiany danych na poziomie interfejsu mi˛edzy urzadzeniem ˛ a systemem operacyjnym, czyli symulowane było uszkodzenie urzadzenia, ˛ a nie kanału przesyłu tak jak w przypadku eksperymentów znanych z literatury. 11 12 13 Ang. Mass Storage Device. Ang. Universal Host Controller Interface. http://www.netfilter.org 96 1 2 3 4 5 6 7 [QEFI] Uruchomienie SUT. [ SUT] Zalogowanie si˛ e do systemu administratora przez konsol˛ e dost˛ epna˛ ,→ przez port szeregowy. [QEFI] Podłaczenie ˛ do SUT urzadzenia ˛ USB MSD. [ SUT] Podłaczenie ˛ USB MSD w systemie operacyjnym SUT. [QEFI] Konfiguracja opóźnionego wstrzykni˛ ecia bł˛ edu wyzwalanego ,→ prawdopodobieństwem. [ SUT] Wyliczenie wartości funkcji skrótu md5 pliku znajdujacego ˛ si˛ e na ,→ urzadzeniu. ˛ [QEFI] Wyłaczenie ˛ SUT. Scenariusz QEFI 4.2: Scenariusz testowania USB MSD Konfiguracja eksperymentu Wszystkie eksperymenty wykorzystywały system Debian Squeeze oparty o jadro ˛ GNU/Linux w wersji 2.6.32. Dla każdego scenariusza testowego przeprowadzonych zostało 10 000 testów – zgodnie z wzorem 4.2.1 dla tej liczby testów przedział ufności można oszacować na ±0, 0098 p.p., co przy znaczaco ˛ mniejszej przestrzeni zaburzanych danych pozwala skutecznie porównywać uzyskane współczynniki manifestacji bł˛edów. Scenariusz testowy dla eksperymentów urzadzenia ˛ USB MSD oraz kontrolera USB składa si˛e z kroków przedstawionych w scenariuszu 4.2. Eksperyment testujacy ˛ interfejs sieciowy był zbliżony do eksperymentów opisanych w podrozdziale 4.3. Jedyna˛ różnica˛ wzgl˛edem Scenariusza QEFI 4.1 jest zmiana parametrów wstrzykiwania bł˛edu, który był wyzwalany warunkowo z pewnym prawdopodobieństwem (patrz 3.4.5). Wyniki Na rysunku 4.14 przedstawiony jest odsetek bł˛edów, które zostały zamanifestowane (współczynnik Fs ) w każdym z eksperymentów. Rysunek 4.15 zawiera zestawienie typów bł˛edów zgłoszonych przez system operacyjny, a szczegółowy wykaz komunikatów systemu operacyjnego zamieszczony jest w tabeli 4.4. W tabeli pomini˛ety został wykaz komunikatów systemu operacyjnego dla scenariusza USB MSD, ponieważ wystapił ˛ tylko jeden typ komunikatu – Access beyond the device. Dost˛epność systemu dla testów, w których wynik przeprowadzenia scenariusza był nieprawidłowy zobrazowano na rysunku 4.16. Wnioski Poziom manifestacji bł˛edów (rysunek 4.15) jest diametralnie różny dla każdego z przedstawionych scenariuszy testowych. Najwi˛ecej przekłamań zostało zamanifestowanych w scenariuszu USB MSD, ponieważ w zdecydowanej wi˛ekszości zaburzenia w odczytywanych danych powodowały zmian˛e wartości funkcji skrótu md5 w kroku 6. scenariusza (99,2% przypadków spośród zamanifestowanych bł˛edów). Interesujace ˛ jest również, że blisko 80% 97 100 80 60 40 0 20 Testy % PU + PS NU + NS USB MSD USB UHCI e1000 60 40 PU PS NU NS 0 20 Testy % 80 100 Rysunek 4.14: Wartość współczynnika Fs dla bł˛edów urzadzeń ˛ wejścia/wyjścia USB MSD Rysunek 4.15: wejścia/wyjścia USB UHCI e1000 Rozkład typów zamanifestowanych bł˛edów dla bł˛edów urzadzeń ˛ 98 100 80 60 40 0 20 Testy % DU DS NDU NDS USB MSD USB UHCI e1000 Rysunek 4.16: Dost˛epność systemu operacyjnego przy bł˛edach urzadzeń ˛ wejścia/wyjścia Komunikat % Controller process error EXT FS error General protection I/O error Panic in interrupt Undefined instruction Reset USB device USB UHCI 14,24 4,32 0 7,58 0 0 91,21 e1000 0 0 1,07 0 100 100 0 Tabela 4.4: Komunikaty systemu operacyjnego zgłaszane przy bł˛edach urzadzeń ˛ wejścia/wyjścia 99 bł˛edów zgłoszonych w eksperymencie testujacym ˛ kontroler USB nie zamanifestowało si˛e żadnym komunikatem systemu operacyjnego, a powodowały one zawieszenie si˛e emulowanego systemu komputerowego (rysunek 4.16/N DS + N DU ). W przypadku komunikatów jadra ˛ dla eksperymentu testujacego ˛ interfejs sieciowy komunikaty Panic in interrupt oraz Undefined instruction maja˛ równy udział procentowy, ponieważ komunikaty te zawsze wyst˛epowały razem. Przedstawione eksperymenty obrazuja˛ możliwości jakie stwarza wykorzystanie emulatora systemu komputerowego przy testowaniu oprogramowania obsługujacego ˛ urzadzenia ˛ wejścia/wyjścia. Wykazały one, że zaburzenia w różnych punktach wymiany danych mi˛edzy urzadzeniem ˛ wejścia/wyjścia a systemem operacyjnym przynosza˛ znaczaco ˛ inne efekty. Widoczne jest to szczególnie przy porównaniu eksperymentów USB MSD oraz kontrolera USB. W przypadku pami˛eci masowej bład ˛ manifestował si˛e prawie w 100% eksperymentów i oznaczał przekłamanie w przetwarzanych danych. Jest to sytuacja, która może być stosunkowo łatwo wychwycona, jeżeli użytkownik posiada wyniki funkcji skrótu i dokonuje weryfikacji zawartości plików znajdujacych ˛ si˛e na urzadzeniu ˛ pami˛eci masowej. Natomiast zaburzanie kontrolera USB manifestowało si˛e rzadziej, jednak skutki były znacznie bardziej dotkliwe – najcz˛eściej było to zawieszenie si˛e systemu. Warto zaznaczyć, że z dużym prawdopodobieństwem wyniki eksperymentu USB MSD zmieniłyby si˛e, jeżeli scenariusz testowy obejmowałby wi˛ecej operacji na plikach (np. tworzenie, usuwanie plików i katalogów) – spodziewany byłby wtedy wi˛ekszy udział komunikatów systemu operacyjnego o wykrytych nieprawidłowościach w systemie plików. Analiza wyników zaburzania interfejsu sieciowego wykazała, że przekłamania w deskryptorach pakietów przychodzacych ˛ z sieci wywołuja˛ bardzo niewiele awarii. Jednak pomimo niewielkiej wartości współczynnika manifestacji bł˛edów (5%) dla eksperymentu e1000, prawie 90% testów z zamanifestowanym bł˛edem powodowało niedost˛epność systemu operacyjnego. Niski współczynnik manifestacji zwiazany ˛ jest najprawdopodobniej z mechanizmem retry wbudowanym w protokół TCP/IP. W przypadku uszkodzenia deskryptora pakietu w sposób zaburzajacy ˛ dane (czyli np. zmiana wartości wskaźnika wskazujacego ˛ na bufor z danymi) skutkowało to wyliczeniem sum kontrolnych o nieprawidłowych wartościach i powtórzeniem komunikacji. 4.5.2. Zaburzanie kodu, danych statycznych i danych tylko do odczytu systemu operacyjnego W podrozdziale 4.2 wykazano potrzeb˛e zebrania informacji o tym jakiego typu dane sa˛ zaburzane oraz zwi˛ekszenia efektywności eksperymentów. W niniejszej sekcji przedstawiono wynik wst˛epnych prac nad tymi zagadnieniami z użyciem statycznej analizy zawartości pami˛eci RAM. 100 Jadro ˛ systemu operacyjnego GNU/Linux w wirtualnym systemie plików (VFS14 ) udost˛epnia w poddrzewie /proc/ informacje o uruchomionych procesach oraz dodatkowe informacje zwiazane ˛ ze środowiskiem wykonania. W wersji jadra ˛ dla architektury x86 dost˛epny jest plik /proc/iomem, który zawiera informacj˛e o odwzorowaniu różnych komponentów systemu komputerowego (np. pami˛eci RAM/ROM, Video RAM/ROM, szyny PCI, etc.) w fizycznej przestrzeni adresowej. Ponadto dost˛epna jest tam informacja o zakresach adresów fizycznych, w których znajduja˛ si˛e kod, dane statyczne oraz dane tylko do odczytu obrazu jadra ˛ systemu operacyjnego. W niniejszej sekcji przedstawione sa˛ wyniki eksperymentów ukierunkowanych na zaburzanie pojedynczego bitu w wymienionych segmentach systemu operacyjnego. Zaburzanie tych danych może być wykonywane dzi˛eki działaniom przygotowawczym opisanym w metodyce (patrz 3.4.5) służacym ˛ konfiguracji wstrzykiwania bł˛edów. Konfiguracja eksperymentu Konfiguracja eksperymentu była identyczna z eksperymentem przeprowadzonym w podrozdziale 4.2 z wyjatkiem ˛ zastosowania systemu operacyjnego Debian Squeeze opartego o jadro ˛ GNU/Linux w wersji 2.6.32 oraz wstrzykiwania bł˛edu w jeden z wyznaczonych zakresów pami˛eci fizycznej. Dla każdego zakresu uruchomiono 10 000 testów. Mniejsza liczba testów zwiazana ˛ jest z zaburzaniem znacznie mniejszego obszaru danych (najwi˛ekszy z badanych obszarów, obraz jadra ˛ systemu operacyjnego, zajmuje około 2 MB pami˛eci, co stanowi 1 24 pami˛eci RAM, dla której przeprowadzano 50 000 eksperymentów w podrozdziale 4.2). Wyniki Podobnie jak w poprzednich eksperymentach sporzadzone ˛ zostały wykresy: procentowego udziału zamanifestowanych bł˛edów (współczynnik Fs ) w ramach eksperymentów (rysunek 4.17), typów manifestowanych bł˛edów (rysunek 4.18), dost˛epności systemu dla testów zakończonych nieprawidłowym wynikiem (rysunek 4.19) oraz typów komunikatów systemu operacyjnego (tabela 4.5). Rysunek 4.20 przedstawia umiejscowienie w pami˛eci fizycznej zaburzanych danych. Wnioski Analiza wyników eksperymentów jednoznacznie wskazuje na wi˛eksza˛ podatność na bł˛edy sekcji zawierajacej ˛ kod systemu operacyjnego w porównaniu z sekcjami danych statycznych i danych tylko do odczytu. Zaburzanie wymienionych sekcji danych manifestuje si˛e bł˛edem w znikomym odsetku przeprowadzonych eksperymentów. Wynika to z faktu, że ilość przetwarzanych instrukcji kodu jest znacznie wi˛eksza, niż danych statycznych i danych tylko do odczytu. 14 Ang. Virtual File System. 101 6 5 4 3 0 1 2 Testy % PU + PS NU + NS Kod statyczny Dane statyczne Dane tylko do odczytu 60 20 40 PU PS NU NS 0 Testy % 80 100 Rysunek 4.17: Wartość współczynnika Fs dla segmentów systemu operacyjnego Kod statyczny Dane statyczne Dane tylko do odczytu Rysunek 4.18: Rozkład bł˛edów dla segmentów systemu operacyjnego 102 100 80 60 40 0 20 Testy % DU DS NDU NDS Kod statyczny Dane statyczne Dane tylko do odczytu Rysunek 4.19: Dost˛epność systemu operacyjnego przy bł˛edach w segmentach systemu operacyjnego Komunikat % Bad page state Bad PC value Null dereference Null dereference 0 Paging request failed Sched while atomic General protection Panic in interrupt Panic - kill init Segfault Stack protector Undefined instruction Unclassified Kod statyczny 0,51 13,64 31,06 10,86 47,22 3,03 12,12 18,43 8,84 2,02 0,25 7,32 2,02 Dane statyczne 0 3,57 17,86 3,57 78,57 0 64,29 57,14 0 0 0 0 0 Dane tylko do odczytu 0 29,41 29,41 5,88 70,59 0 23,53 23,53 23,53 0 0 0 0 Tabela 4.5: Komunikaty o bł˛edach zgłaszane przy zaburzaniu segmentów systemu operacyjnego Dane tylko do odczytu Dane statyczne Kod jądra 0 4 8 12 16 20 24 28 32 36 40 44 Pamięć fizyczna MB Rysunek 4.20: Lokalizacja w pami˛eci fizycznej segmentów systemu operacyjnego 103 Wspólnym mianownikiem wszystkich eksperymentów jest znaczny (powyżej 30%) udział bł˛edu Paging request failed zgłaszanego przez system operacyjny. Jest to zachowanie podobne do efektów zaobserwowanych podczas wstrzykiwania bł˛edu w losowo wybrane miejsce pami˛eci (tabela 4.1). Sugeruje to możliwości wychwytywania bł˛edów poprzez sprawdzanie, czy zgłoszenie przez system operacyjny tego typu komunikatu zwiazane ˛ jest z wyst˛epowaniem bł˛edu w systemie. Zagadnienie to jest dalej rozpatrywane w rozdziale 5. Dzi˛eki zaw˛eżeniu zakresu zaburzanych adresów możliwe było zwi˛ekszenie efektywności przeprowadzonych testów. Ponieważ miejsce załadowania obrazu jadra ˛ systemu operacyjnego w pami˛eci fizycznej jest stałe, to porównanie rysunków 4.20 oraz 4.9 pozwala wyjaśnić wi˛eksza˛ podatność na bł˛edy zakresu pami˛eci fizycznej od 16 do 18 MB. Niemniej dla pełnego wyjaśnienia rejonów o podwyższonej podatności na bł˛edy z rysunku 4.9 potrzebne sa˛ dalsze badania. Informacja,˛ której nie dostarcza przedstawiony eksperyment jest podatność na bł˛edy pozostałych danych wykorzystywanych w przestrzeni jadra ˛ systemu operacyjnego – kodu załadowanych modułów, stosu oraz danych alokowanych dynamicznie. Braki te uzupełnione sa˛ eksperymentami opisanymi w sekcji w 4.5.3. 4.5.3. Zastosowanie profilowania do zaburzania kodu, stosu oraz danych alokowanych systemu operacyjnego Eksperymenty zaburzajace ˛ pami˛eć RAM przedstawione do tej pory wymagały minimalnej ingerencji w środowisko emulatora. Niemniej uzyskane w nich rezultaty nie sa˛ pełne, ponieważ brakowało w nich informacji o zaburzanych danych (patrz 4.2) lub zaburzany był kod systemu operacyjnego, niezależnie od tego, czy kod ten był wykonywany w przebiegu scenariusza (patrz 4.5.2). Istotnym problemem jest również niska efektywność przeprowadzanych eksperymentów, gdzie maksymalny odsetek zamanifestowanych bł˛edów wynosił zaledwie 5% dla zaburzania rejonu pami˛eci zawierajacego ˛ kod systemu operacyjnego. W celu rozwiazania ˛ wymienionych problemów podj˛ete zostały działania polegajace ˛ na wzbogaceniu środowiska emulatora QEMU o autorskie mechanizmy pozwalajace ˛ profilować i zaburzać zarówno kod, stos, a także dane alokowane przez system operacyjny. Wprowadzone zmiany polegaja˛ na modyfikacji procesu binarnej translacji opisanej w podrozdziale 3.2 oraz sekcji 3.4.3. Opracowany został zintegrowany z QEMU moduł śledzenia wykonania (patrz 3.4.6). Śledzenie każdego z wymienionych typów danych wymagało zastosowania innych technik, które sa˛ opisane w dalszej cz˛eści rozdziału. Dzi˛eki zastosowaniu profilowania osiagni˛ ˛ eto duża˛ efektywność przeprowadzanych eksperymentów w sensie współczynnika manifestacji wstrzykni˛etych bł˛edów. Eksperymenty opisane poniżej maja˛ na celu wyznaczenie charakterystyki niezawodności systemu operacyjnego przy różnych obcia˛żeniach. Wykorzystano dwa scenariusze testowe. Pierwszy z nich to scenariusz opisany w 4.2. Wyniki uzyskane w eksperymencie pozwalaja˛ 104 na ocen˛e zysku z zastosowania profilowania wzgl˛edem eksperymentów przeprowadzonych w 4.2 oraz 4.5.2. Natomiast drugi scenariusz wzorowany jest na cz˛estym zastosowaniu systemu komputerowego jako serwera HTTP. Profilowanie i zaburzanie kodu systemu operacyjnego Poprawa efektywności zaburzania kodu systemu operacyjnego zwiazana ˛ jest z wyznaczeniem funkcji, które sa˛ wywoływane w trakcie przebiegu scenariusza testowego. Jednym z możliwych rozwiazań ˛ byłoby skorzystanie z mechanizmów profilowania dost˛epnych w jadrze ˛ systemu GNU/Linux. Alternatywna˛ opcja˛ było zastosowanie nieinwazyjnego śledzenia opracowanego przez autora i opisanego w [24]. Technika ta polega na nagraniu adresów docelowych skoków wykonanych przez procesor pracujacy ˛ w trybie jadra ˛ systemu operacyjnego (w celu odfiltrowania skoków wykonywanych przez programy użytkownika) oraz na ich podstawie wyznaczenie wykonywanych funkcji z pomoca˛ informacji zawartych w pliku /proc/kallsyms15 . Podczas przeprowadzanych eksperymentów wybrana została metoda nieinwazyjna, ponieważ jest to metoda dokładna16 i w czasie profilowania nie angażuje w żaden sposób badanego systemu operacyjnego. Zastosowanie profilowania powoduje konieczność jednokrotnego uruchomienia eksperymentu bez wstrzykni˛ecia bł˛edu w celu wyznaczenia zbioru funkcji jadra ˛ wykorzystywanych podczas zadanego scenariusza testowego. nast˛epnie do określenia zakresów zaburzanej pami˛eci. Zebrane informacje służa˛ Reasumujac, ˛ wykorzystanie profilowania w eksperymencie wia˛że si˛e z nast˛epujacymi ˛ czynnościami: 1. modyfikacja scenariusza o krok odczytujacy ˛ zawartość pliku /proc/kallsyms, 2. przeprowadzenie pojedynczego testu bez wstrzykiwania bł˛edu i zebranie informacji o funkcjach wykonanych w przestrzeni systemu operacyjnego17 , 3. podczas przeprowadzania testów ze wstrzykiwaniem bł˛edu: a) losowe wybranie funkcji systemu operacyjnego, która jest celem zaburzenia, b) wyznaczenie zakresu pami˛eci, pod którym znajduje si˛e docelowa funkcja18 , c) wykorzystanie wyznaczonego zakresu jako parametru procedury wstrzykiwania bł˛edu. Dodatkowym mechanizmem, który został wprowadzony do translacji binarnej, jest wykrywanie liczby wykonań zaburzonej instrukcji. Modyfikacja ta polega na umieszczeniu w buforze translacji binarnej procedury pozostawiajacej ˛ ślad w dzienniku eksperymentu. 15 Plik /proc/kallsyms udost˛epnia list˛e wszystkich funkcji systemu operacyjnego zawartych w statycznym obrazie jadra ˛ oraz modułach wraz z ich adresami w wirtualnej przestrzeni adresowej. 16 Standardowe mechanizmy profilowania (np. oprofile) systemu GNU/Linux polegaja˛ na zbieraniu próbek co pewien określony interwał czasu, przez co zbierane sa˛ informacje o cz˛esto wykonywanych procedurach, ale nie o wszystkich procedurach wykonanych podczas profilowania. 17 Wyznaczenie zbioru wykonanych funkcji odbywa si˛e poprzez dopasowanie nagranych technika˛ nieinwazyjnego śledzenia adresów instrukcji do funkcji systemu operacyjnego, do których te funkcje należa.˛ 18 Wyznaczenie to odbywa si˛e na podstawie odczytanej zawartości pliku /proc/kallsyms w danym teście, ponieważ funkcje zdefiniowane w ładowanych modułach moga˛ być załadowane w inne rejony pami˛eci dla każdego testu. 105 Dodawana procedura jest zawsze umieszczana bezpośrednio przed kodem emulujacym ˛ zmieniona˛ instrukcj˛e. Zebrane dzi˛eki temu dane pozwalaja˛ stwierdzić ile razy wykonana była przekłamana instrukcja i powiazać ˛ te wyniki z informacjami o manifestacji bł˛edów. Zaburzanie stosu systemu operacyjnego Zaburzenie stosu watków ˛ wykonania w przestrzeni systemu operacyjnego jest zadaniem, które wymaga dynamicznego wyznaczania docelowych adresów wstrzykni˛eć bł˛edów. Jest to spowodowane faktem, że stos jest struktura˛ cz˛esto modyfikowana.˛ Próba dwuetapowego wstrzykni˛ecia, jak to miało miejsce w przypadku kodu, może być nieskuteczna w zwiazku ˛ ze zwini˛eciem stosu w odst˛epie czasu mi˛edzy wyznaczeniem zaburzanej przestrzeni, a faktycznym wstrzykni˛eciem. W przeprowadzonych eksperymentach wykorzystano możliwość modyfikacji procesu translacji binarnej. Podobnie jak w przypadku profilowania kodu przed każda˛ instrukcja˛ skoku w przestrzeni jadra ˛ wykonywana jest specjalna procedura. Niemniej zamiast zbierania informacji o adresie docelowym skoku przed wykonaniem instrukcji wywołania procedury call zaburzana jest pami˛eć stosu w zakresie n bajtów poczawszy ˛ od wierzchołka stosu (czyli od adresu zawartego w rejestrze ESP19 . Moment wstrzykni˛ecia jest wybierany warunkowo według zadanego prawdopodobieństwa (patrz 3.4.5). Zaburzanie danych alokowanych Wyznaczenie adresów danych alokowanych w przestrzeni jadra ˛ systemu operacyjnego jest zadaniem wymagajacym ˛ dogł˛ebnej znajomości badanego systemu operacyjnego. System GNU/Linux dysponuje kilkoma mechanizmami przydziału pami˛eci (patrz 2.1.2). mi˛edzy innymi kmalloc, kmem_cache oraz vmalloc. Sa˛ to Każdy z tych mechanizmów jest zoptymalizowany do innego scenariusza użycia: kmalloc służy do alokacji małych porcji pami˛eci ogólnego przeznaczenia (najefektywniej buforów o rozmiarze mniejszym niż pojedyncza strona pami˛eci, czyli 4096 bajtów), kmem_cache wyspecjalizowany jest w przechowywaniu obiektów jednego typu o tym samym rozmiarze (np. w˛ezłów struktur drzewiastych), natomiast vmalloc pozwala alokować duże i w miar˛e możliwości ciagłe ˛ (w sensie fizycznej przestrzeni adresowej) obszary pami˛eci. W przeprowadzonych eksperymentach skupiono si˛e na zaburzaniu pami˛eci alokowanej z użyciem mechanizmu kmalloc, ponieważ jest to najbardziej ogólny z wymienionych mechanizmów alokacji. Zaproponowana˛ metod˛e można rozszerzyć na pozostałe strategie alokacji. Procedura wstrzykni˛ecia bł˛edu w pami˛eć alokowana˛ wymaga dynamicznego śledzenia, gdzie w przestrzeni adresowej znajduje si˛e ten typ pami˛eci. Dodatkowo bardzo istotne jest również monitorowanie dost˛epu do wyznaczonych rejonów, ponieważ wstrzykni˛ecie w 19 Ang. Extended Stack Pointer – rejestr zawierajacy ˛ wskaźnik stosu w architekturach z rodziny x86. 106 momencie alokacji powoduje zaburzenie pami˛eci, która jeszcze nie została wypełniona danymi do przetworzenia, co czyni taka˛ operacj˛e bezcelowa.˛ W celu zbierania informacji o alokowanej pami˛eci zastosowano strategi˛e zbliżona˛ do sposobu działania przedstawionego przy zaburzaniu stosu. W odróżnieniu od wspomnianego mechanizmu punktem zastosowania wstrzykni˛etej procedury nie sa˛ instrukcje wywołań wszystkich funkcji wykonywanych w przestrzeni jadra, ˛ a jedynie instrukcje wywołań funkcji trace_kmalloc oraz kfree. Funkcja trace_kmalock jest wywoływana zawsze na końcu działania procedury przydziału pami˛eci (funkcja kmalloc) w celu poinformowania wewn˛etrznych mechanizmów jadra ˛ GNU/Linux o fakcie przydziału pami˛eci (m.in. w celu zbierania statystyk o fragmentacji). Funkcja ta została wybrana, ponieważ jej argumentami sa˛ zarówno parametry wywołania kmalloc (rozmiar alokowanego bufora) oraz jej rezultat (adres przydzielonego bufora). W analogiczny sposób monitorowana jest funkcja kfree, która odpowiedzialna jest za zwolnienie poprzednio przydzielonej pami˛eci. Dzi˛eki informacjom zebranym w ten sposób możliwe jest przechowywanie w środowisku emulatora pełnej informacji o pami˛eci przydzielonej wewnatrz ˛ emulowanego systemu operacyjnego bez ingerencji w jego działanie. W celu zapewnienia, że zaburzone dane sa˛ wykorzystywane przez system operacyjny, moment wstrzykni˛ecia został ściśle powiazany ˛ z odczytem tych danych. Zrealizowane to zostało poprzez zmodyfikowanie wewn˛etrznych procedur QEMU odpowiedzialnych za odczyt emulowanej pami˛eci w ten sposób, aby przed dost˛epem do danych wykonane było sprawdzenie, czy odczytywany adres znajduje si˛e w puli pami˛eci wyznaczonej przez mechanizm śledzenia. Jeżeli adres należy do puli, to nast˛epuje zaburzenie odczytywanych danych z zadanym prawdopodobieństwem (patrz 3.4.5). Konfiguracje eksperymentów W ramach przeprowadzonych eksperymentów wykorzystano scenariusz 4.1 (patrz 4.2) oraz scenariusz 4.3. Pozostałe parametry konfiguracji eksperymentów były identyczne z konfiguracja˛ zastosowana˛ w eksperymencie opisanym w 4.2 z wyjatkiem ˛ zastosowania systemu operacyjnego Debian Squeeze opartego o jadro ˛ GNU/Linux w wersji 2.6.32 oraz konfiguracja˛ momentu wstrzykni˛ecia bł˛edu charakterystyczna˛ dla zaburzanych danych. Scenariusz 4.3 imituje wystapienie ˛ bł˛edu w systemie realizujacym ˛ usług˛e serwera HTTP, gdzie po próbie pobrania dokumentu z serwera emulowany administrator loguje si˛e do systemu protokołem SSH20 w celu zbadania logów serwera oraz systemu operacyjnego. W przypadku scenariusza 4.3 wynik uznany jest za prawidłowy, jeżeli udało si˛e poprawnie pobrać dokument z serwera HTTP (krok 5). Jeżeli odpowiedź serwera jest prawidłowa, to test jest przerywany. W przeciwnym przypadku symulowane jest podj˛ecie akcji diagnostycznej przez administratora 20 Ang. Secure Shell. Popularna usługa realizujaca ˛ zdalny, szyfrowany dost˛ep do konsoli systemu. 107 1 2 3 4 5 6 7 8 9 [QEMU] Uruchomienie SUT. [ SUT] Zalogowanie si˛ e do systemu administratora przez konsol˛ e dost˛ epna˛ ,→ przez port szeregowy. [ SUT] Wypisanie zawartości pliku /proc/kallsyms na konsol˛ e. [QEMU] Wstrzykni˛ ecie pojedynczego bł˛ edu typu bit-flip w kod systemu ,→ operacyjnego lub konfiguracja warunkowego wstrzykni˛ ecia bł˛ edu. [ SUT] Nawiazanie ˛ połaczenia ˛ TCP/IP przez Nadzorc˛ e na port 80 SUT i ,→ wysłanie żadania ˛ HTTP z zastosowaniem programu wget. [ SUT] Jeżeli odpowiedź serwera jest różna od referencyjnej, to ,→ nawiazanie ˛ połaczenia ˛ TCP/IP przez Nadzorc˛ e na port 22 SUT i ,→ zalogowanie si˛ e protokołem SSH do SUT na konto administratora. [ SUT] W ramach sesji SSH wylistowanie zawartości logów serwera HTTP. [ SUT] W ramach sesji SSH wylistowanie zawartości logów systemu ,→ operacyjnego. [QEMU] Wyłaczenie ˛ SUT. Scenariusz QEFI 4.3: Zaburzanie pami˛eci RAM przy realizowaniu usługi serwera HTTP systemu (linie 7-9). System uznany jest za dost˛epny, jeżeli udało si˛e nawiazać ˛ połaczenie ˛ SSH oraz wypisać zawartość plików z logami (linie 8 i 9). Kod był zaburzany w stałym momencie eksperymentu wykorzystujac ˛ informacje z profilowania oraz działań przygotowawczych (linia 3) pozwalajacych ˛ określić miejsce załadowania poszczególnych funkcji systemu operacyjnego. Wstrzykiwanie w stos było wyzwalane warunkowo poprzez wykonanie przez emulowany procesor instrukcji ret21 , a bład ˛ był wstrzykni˛ety z prawdopodobieństwem 1:10 000 w zakresie 64 bajtów od wartości przechowywanej w rejestrze ESP. W przypadku danych alokowanych informacje o alokacjach były zbierane od momentu zalogowania si˛e administratora systemu, natomiast symulacja bł˛edu sterowana była warunkiem odczytu tej pami˛eci – wstrzykni˛ecie bł˛edu nast˛epowało z prawdopodobieństwem 1:1 000. Dla każdego typu zaburzanych danych zostało przeprowadzone 10 000 iteracji eksperymentu. Wyniki Dla obu serii eksperymentów (oznaczonych cyframi rzymskimi: I – scenariusz 4.1; II – scenariusz 4.3) przygotowane zostało zestawienie wartości współczynnika Fs zamanifestowanych bł˛edów (rysunek 4.21), typów zamanifestowanych bł˛edów (rysunek 4.22), dost˛epności systemu dla testów zakończonych nieprawidłowym wynikiem (rysunek 4.23) oraz rozkładu typów komunikatów jadra ˛ systemu operacyjnego (tabela 4.6). Tak jak w przypadku zaburzania danych systemu operacyjnego z 4.5.2 zostało przygotowane graficzne przedstawienie lokalizacji zaburzanych danych dla scenariusza 4.1 (rysunek 4.24). Sporzadzone ˛ eksperymentów. zostały wykresy obrazujace ˛ dodatkowe cechy przeprowadzonych Na rysunku 4.25 przedstawiono rozkład procentowy testów z zamanifestowanym bł˛edem w zależności od liczby ile razy wykonana została zaburzona 21 Instrukcja powrotu z wywołania procedury. 108 80 60 40 0 20 Testy % PU + PS NU + NS Kod I Stos I Dane I Kod II Stos II Dane II 60 20 40 PU PS NU NS 0 Testy % 80 100 Rysunek 4.21: Wartość współczynnika Fs dla różnych typów danych Kod I Stos I Dane I Kod II Stos II Dane II Rysunek 4.22: Rozkład typów bł˛edów dla różnych typów danych 109 100 80 60 40 0 20 Testy % DU DS NDU NDS Kod I Stos I Dane I Kod II Stos II Dane II Rysunek 4.23: Dost˛epność systemu operacyjnego przy bł˛edach w różnych typach danych Komunikat % Bad page state Bad PC value Null dereference Null dereference 0 Paging request failed Sched while atomic Double fault EXT FS error General protection I/O error Page alocation failure Panic in interrupt Panic - kill init Segfault Stack protector Undefined instruction Unclassified Kod I 0,41 14,92 29,42 11,56 50,03 3,34 0 0 17,71 0 0,03 19,37 8,49 0,85 0,42 9,03 2,31 Stos I 0,49 23,5 23,84 10,43 52,7 0,3 0,6 0 21,99 0 0,04 28,86 0,04 1,17 0 7,74 6,16 Dane I 0 7,27 12,57 4,94 43,26 0,09 0 0 1,46 0 0 4,44 0 10,11 0 8,55 30 Kod II 0,31 13,73 29,12 11,18 49,51 4,33 0 0,68 24,74 0,35 0,02 40,45 4,55 0,88 0,42 8,96 3,87 Stos II 0,17 16,1 22,26 8,94 57 3,88 0 0,25 17,37 0,08 0,08 70,32 0 0,17 0,42 7,08 2,95 Dane II 0 9,41 19,91 3,33 55,61 0,07 0 0 20,49 0 0 93,63 0 0 0 15,93 5,79 Tabela 4.6: Komunikaty o bł˛edach zgłaszane przy zaburzaniu różnych typów danych systemu Dane alokowane Stos Kod 0 4 8 12 16 20 24 28 32 36 40 Pamięć fizyczna MB Rysunek 4.24: Lokalizacja w pami˛eci fizycznej zaburzanych danych 110 44 10 20 30 40 50 Kod II 0 Testy % Kod I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Liczba wykonań wykonan Rysunek 4.25: Liczba wykonań zaburzonego kodu instrukcja kodu (tj. instrukcja, która na skutek wstrzykni˛ecia bł˛edu zmieniła swoja˛ semantyk˛e lub parametry). Przykładowo można na nim odczytać, że spośród testów, w których bład ˛ został zamanifestowany, w 45% przypadków zaburzona instrukcja została wykonana tylko jeden raz dla eksperymentu I. Na rysunku 4.26 przedstawiono zależność pomi˛edzy lokalizacja˛ wstrzykni˛ecia bł˛edu a miejscem wystapienia ˛ awarii wykrytej przez system operacyjny – miejsce zamanifestowania bł˛edu wyznaczone zostało na podstawie analizy komunikatów systemu operacyjnego zawierajacych ˛ stack-trace awarii (patrz 2.1.2, 3.4.5, 4.2). Wykres opracowano na podstawie odpowiednio 58% i 89% testów eksperymentów zaburzania kodu I i II z zamanifestowanym bł˛edem – dzienniki wykonania tych testów zawierały komunikaty zawierajace ˛ stack-trace, w którym wyst˛epowała zaburzana funkcja. Na wykresie uwzgl˛edniono również informacje o liczbie wykonań zaburzonej instrukcji. Przykładowo można z niego odczytać, że w 13% przypadków dla scenariusza 4.1 zaburzony bajt był pierwszym bajtem instrukcji, która spowodowała wygenerowanie raportu o awarii (odległość 0), z czego w 7% przypadków zaburzona instrukcja była wykonana tylko raz. Rysunek 4.27 przedstawia zależność pomi˛edzy zaburzeniem konkretnego bitu w bajcie, a spowodowaniem zamanifestowania bł˛edu. Na rysunku 4.28 zobrazowana jest relacja mi˛edzy odległościa˛ zaburzonego bajtu od wartości rejestru ESP, a spowodowaniem zamanifestowania bł˛edu. Z analizy artefaktów eksperymentów zaburzenia kodu wynika, że współczynnik naturalnej odporności na bł˛edy dla eksperymentów zaburzania kodu I i II wynosi odpowiednio I = 31% i I = 42%. Wartości te wyznaczaja˛ współczynnik naturalnej odporności na bł˛edy dla bł˛edu typu bit-flip w kodzie systemu operacyjnego dla zbadanych scenariuszy. 111 Liczba=wykonanń=>=1 −4 2 4 6 8 10 2 4 6 8 10 10 0 5 Testy=% Kod II 15 Liczba=wykonanń===1 −10 −8 −6 −2 0 10 0 5 Testy=% Kod I 15 Odlegl −10 −8 −6 −4 −2 0 Odlegl [B] Rysunek 4.26: Odległość mi˛edzy zaburzana˛ instrukcja,˛ a miejscem manifestacji bł˛edu Kod II 40 20 0 Testy % 60 Kod I 1 2 4 8 10 20 40 Maska Rysunek 4.27: Maska zaburzonego bitu, a manifestacja bł˛edu 112 80 Stos II 50 0 25 Testy % 75 100 Stos I −56 −48 −40 −32 −24 −16 −8 0 [B] Rysunek 4.28: Wstrzykiwanie bł˛edu w stos, a manifestacja bł˛edu Wnioski Zastosowanie technik śledzenia wykonania spowodowało znaczny wzrost efektywności eksperymentów testowych – od 5% zamanifestowanych bł˛edów dla statycznego wyznaczenia kodu jadra ˛ systemu operacyjnego (patrz 4.5.2) do 70% zamanifestowanych bł˛edów dla zaburzania kodu wyznaczonego metoda˛ profilowania. Dodatkowo dzi˛eki zastosowanym technikom analizowane sa˛ jedynie aktywowane bł˛edy. Sporzadzone ˛ zestawienie lokalizacji zaburzanych danych w pami˛eci fizycznej (rysunek 4.24) pozwala stwierdzić, że dane alokowane, stosy oraz kod ładowanych modułów znajduja˛ si˛e w losowych miejscach pami˛eci fizycznej. Wyniki te pozwalaja˛ zinterpretować w pełni wykres podatności na bład ˛ w przestrzeni adresów fizycznych (rysunek 4.9). Zwi˛ekszona wrażliwość na bł˛edy w niskich adresach przestrzeni fizycznej spowodowana jest faktem, że alokacja pami˛eci przez jadro ˛ systemu cz˛esto wykorzystuje ten region. Podatność w zakresach 16-18MB pami˛eci fizycznej wynika z zaburzania kodu jadra ˛ systemu, a pozostała pami˛eć losowo zawiera dane wykorzystywane podczas scenariusza testowego. Przeprowadzone badania wskazuja˛ na wyraźne różnice w podatności na bł˛edy poszczególnych typów danych (rysunek 4.21). Zaburzanie kodu powoduje zamanifestowanie bł˛edu w najwi˛ekszej liczbie przypadków (69% i 58% testów). Warto zauważyć, że ponad 90% bł˛edów generuje niepoprawny wynik dla eksperymentu I, a w przypadku eksperymentu II nie zaobserwowano manifestacji bł˛edu przy wygenerowaniu poprawnego wyniku scenariusza. Brak obserwacji prawidłowych wyników dla eksperymentu II wynika z przyj˛etego scenariusza, gdzie uznanie wyniku za prawidłowy wia˛że si˛e jedynie z analiza˛ odpowiedzi serwera HTTP 113 działajacego ˛ w SUT. Oznacza to, że przykładowo współczynnik naturalnej odporności na bł˛edy jest ściśle zwiazany ˛ z zadaniami realizowanymi przez system i obserwowanymi wynikami działania systemu. Dodatkowo potwierdza to analiza dost˛epności systemu operacyjnego (rysunek 4.23) – w przypadku eksperymentu II system w wi˛ekszości testów stawał si˛e niedost˛epny. Warto zwrócić uwag˛e na podobieństwo tabel 4.5/Kod statyczny (strona 103) i 4.6/Kod I oraz rysunków 4.18/Kod statyczny (strona 102) i 4.22 Kod I, które potwierdza zachowanie charakterystyki manifestowania bł˛edu przy uzyskaniu znacznie wi˛ekszej liczby raportów o bł˛edach. Bardzo istotne okazało si˛e wprowadzenie mechanizmu wykrywania, czy zaburzona instrukcja została wykonana. Pozwoliło to uzyskać współczynnik naturalnej odporności na bł˛edy (patrz 2.5.2), który został wyznaczony na I = 31-42%. Prowadzi to do pytania, jak zmodyfikowane zostało działanie realizowanych przez ten kod algorytmów i czy zaburzenie ma istotny wpływ na działanie systemu operacyjnego również w przypadku realizacji innych usług systemu operacyjnego. Istotna˛ obserwacja˛ jest odkrycie, że w blisko 45% iteracji eksperymentów zakończonych manifestacja˛ bł˛edu zaburzona instrukcja została wykonana tylko raz. Informacja ta połaczona ˛ z danymi uzyskanymi z rysunku 4.26, gdzie 55% lokalizacji manifestacji bł˛edu było położone w bezpośrednim sasiedztwie ˛ (od -1 do 4 bajtów) zaburzanych instrukcji pozwala wnioskować o niewielkim odst˛epie czasu pomi˛edzy wykonaniem nieprawidłowej instrukcji a zamanifestowaniem bł˛edu. Ponadto widoczna na rysunku 4.27 tendencja, że zaburzanie wyższych bitów bajtu cz˛eściej powoduje manifestacj˛e bł˛edu jest zgodna z wynikami prac prowadzonych w Instytucie Informatyki Politechniki Warszawskiej (patrz [41, 42]). Wstrzykiwanie bł˛edów w dane alokowane powoduje zamanifestowanie bł˛edu na poziomie 38% i 12%, czyniac ˛ ten rodzaj danych drugim pod wzgl˛edem wrażliwości na bł˛edy. Warto zaznaczyć, że wprowadzenie bł˛edu odbywało si˛e zaraz przed odczytem, czyli w każdym przypadku zmienione dane przetwarzane były przez system operacyjny. Dane przechowywane na stosie wykazuja˛ si˛e współczynnikiem podatności na zaburzenie wysokości około 29% i 12%. Przedstawiona na rysunku 4.28 tendencja do znacznie cz˛estszego manifestowania bł˛edów przy zaburzaniu adresów w odległości 4 bajtów od adresu przechowywanego w rejestrze ESP wynika z wybranego momentu wstrzykni˛ecia – zawsze podczas zaburzania pod tymi adresami znajduje si˛e adres powrotny wywoływania funkcji. Dane odłożone wcześniej na stosie maja˛ zbliżony współczynnik manifestacji bł˛edu. Wyniki uzyskane wskutek zaburzania różnych typów danych sa˛ zbieżne z wynikami uzyskanymi w eksperymentach przeprowadzonych w [48], gdzie wstrzykiwanie bł˛edu oparte było o ładowany moduł jadra ˛ systemu operacyjnego. 114 4.6. Podsumowanie W niniejszym rozdziale przedstawione zostały eksperymenty b˛edace ˛ zastosowaniem metodyki opisanej w rozdziale 3. scenariuszy testów. Podj˛eta została próba opracowania reprezentatywnych Przeprowadzone eksperymenty wykazały praktyczne zastosowanie metodyki umożliwiajac ˛ uzupełnienie stanu wiedzy o nowe informacje – porównanie wrażliwości na bł˛edy architektur sprz˛etowych (4.3), systemów operacyjnych (4.4), poszczególnych typów danych wykorzystywanych przez system operacyjny (4.5.2, 4.5.3) oraz na bł˛edy wyst˛epujace ˛ w różnych urzadzeniach ˛ systemu komputerowego (4.5.1). Przedstawiono szeroki przekrój eksperymentów i możliwe jest poszerzanie spektrum badań o dodatkowe modele bł˛edów i zaburzane urzadzenia. ˛ Reasumujac, ˛ atuty opracowanej metodyki wzgl˛edem rozwiazań ˛ znanych z literatury to: — możliwość porównania wielu architektur sprz˛etowych bez konieczności opracowywania dodatkowego oprogramowania, — możliwość porównania implementacji wielu systemów operacyjnych bez konieczności opracowywania dodatkowego oprogramowania, — możliwość zbadania wrażliwości na bł˛edy obszarów pami˛eci fizycznej, — badanie niezawodności systemu operacyjnego bez konieczności modyfikacji badanego oprogramowania, — opracowana technika nieinwazyjnego śledzenia wykonania, — zaburzanie pracy urzadzeń ˛ na poziomie komunikacji z systemem operacyjnym. Dodatkowym atutem metodyki jest możliwość przeprowadzania eksperymentów na szeroka˛ skal˛e z zastosowaniem wielu maszyn do przeprowadzania obliczeń, co jest zaleta˛ w porównaniu do rozwiazań ˛ wykorzystujacych ˛ rzeczywiste systemy komputerowe. Pozwala to na przeprowadzanie długookresowych testów ukierunkowanych na różne komponenty systemu operacyjnego. Dzi˛eki przeprowadzonym eksperymentom można stwierdzić, że zarówno wykorzystana architektura ISA, jak i zainstalowany system operacyjny maja˛ wpływ na poziom manifestacji bł˛edów. Badania ukierunkowane na różne komponenty systemu operacyjnego maja˛ szczególne znaczenie, ponieważ pozwoliły określić, które z komponentów sa˛ najbardziej wrażliwe na bł˛edy, co stanowi podstaw˛e rozważań opisanych w rozdziale 5. 115 5. Mechanizmy wykrywania i obsługi bł˛edów Rozdział poświ˛econy jest zagadnieniu projektowania i wykorzystania mechanizmów zwi˛ekszania niezawodności oprogramowania. Przedstawiono w nim oryginalne metody detekcji i obsługi bł˛edów wraz z dyskusja˛ nad ich skutecznościa.˛ Zaproponowane zostały nast˛epujace ˛ metody zwi˛ekszania niezawodności: periodyczna weryfikacja spójności kodu jadra ˛ systemu operacyjnego, metoda obsługi przerwań pozwalajaca ˛ na podj˛ecie procedur naprawczych przed wystapieniem ˛ awarii, algorytm brudnych zasobów stanowiacy ˛ rozszerzenie metody obsługi przerwań oraz metod˛e ochrony danych przechowywanych na stosie. Dodatkowo przeprowadzono dyskusj˛e nad wykorzystaniem mechanizmów ochrony danych oraz zastosowaniem QEFI do optymalizacji niezawodności oprogramowania systemów operacyjnych. 5.1. Mechanizmy zwi˛ekszajace ˛ niezawodność w systemie operacyjnym Podstawowe mechanizmy zwi˛ekszania niezawodności zostały opisane w podrozdziale 2.3. Poniżej przedstawiono opis wykorzystania mechanizmów izolacji, redundancji, detekcji i odtwarzalności w systemie operacyjnym. Podział zadań na procesy w systemach operacyjnych jest implementacja˛ idei izolacji. Dzi˛eki odseparowaniu przestrzeni pami˛eci poszczególnych procesów awaria jednego procesu nie wpływa na pozostałe procesy działajace ˛ w systemie. Awaria procesu jest wywoływana wykonaniem niedozwolonej operacji – np. odwołaniem do nieprawidłowego obszaru pami˛eci, próba˛ wykonania nieprawidłowej instrukcji1 lub wykonaniem nieprawidłowej operacji (np. dzielenie przez 0). Opisane sytuacje sa˛ zgłaszane jako wyjatki ˛ – w przypadku nieprawidłowego dost˛epu do pami˛eci wyjatek ˛ zgłasza kontroler MMU, natomiast w pozostałych przypadkach wyjatki ˛ sa˛ generowane przez sam procesor. Zadaniem systemu operacyjnego jest zakończenie działania procesu i udost˛epnienie informacji o okolicznościach awarii. Wpływa to na ograniczenie propagacji bł˛edów, ponieważ proces wykonujacy ˛ nieprawidłowe operacje zostaje zatrzymany, uniemożliwiajac ˛ generowanie bł˛ednych wyników. Niemniej warto zaznaczyć, że w takim scenariuszu system komputerowy przestaje spełniać swoje zadanie z uwagi na zaprzestanie wykonywania uruchomionych w 1 Np. instrukcji niezdefiniowanej dla danej architektury lub wymagajacej ˛ wyższego poziomu uprawnień niż aktualny poziom zdefiniowany dla procesu. 117 nim programów. Mechanizm ten został opracowany w szczególności dla ochrony przed bł˛edami programistycznymi, niemniej wymienione typy awarii sa˛ również obserwowane przy symulowanych bł˛edach sprz˛etowych (patrz rozdział 4). Skuteczność techniki izolacji spowodowała, że jest ona coraz cz˛eściej wykorzystywana na gruncie aplikacji. Jednym z najciekawszych wdrożeń tej techniki jest współczesna architektura przegladarek ˛ internetowych (patrz [91]), gdzie poszczególne zadania przetwarzania stron internetowych (pobieranie zasobów, renderowanie strony, obsługa wtyczek) sa˛ delegowane do dedykowanych procesów. Przykładowo wtyczki przegladarek ˛ internetowych sa˛ dynamicznymi bibliotekami (patrz 2.1.2) tworzonymi przez zewn˛etrznych dostawców, a twórcy przegladarki ˛ nie maja˛ wpływu na jakość tego oprogramowania – niemniej pragna˛ zabezpieczyć si˛e przed sytuacja,˛ gdy awaria spowodowana bł˛edem kodu wtyczki powoduje awari˛e całego programu przegladarki. ˛ Dzi˛eki przeniesieniu wykonania kodu wtyczki do osobnego procesu, w przypadku awarii, aplikacja przegladarki ˛ nie ulega zatrzymaniu – jedynie fragment strony obsługiwany przez wtyczk˛e nie jest wyświetlany. Przykładem zbliżonego modelu izolacji na gruncie systemów operacyjnych jest koncepcja mikrojadra ˛ (np. system Minix [52, 53, 54]), gdzie poszczególne usługi systemu operacyjnego (np. implementacja systemów plików, obsługa urzadzeń) ˛ sa˛ oddelegowane do osobnych procesów podlegajacych ˛ mechanizmowi reinkarnacji w przypadku awarii. Wdrożenie podobnych mechanizmów do jadra ˛ monolitycznego jakim jest GNU/Linux byłoby szczególnie trudne ze wzgl˛edu na inny model architektury i wymagałoby gruntownych zamian kodu źródłowego. Redundancja może być zastosowana zarówno do danych jak i do kodu programu. Polega ona na umieszczeniu dodatkowej informacji, która ułatwia określenie czy pierwotna informacja nie uległa przekłamaniu. W przypadku danych sa˛ to dodatkowe kopie, sumy kontrolne, kody korekcji bł˛edów lub inne informacje specjalizowane dla danego typu danych. W przypadku kodu może to być alternatywna implementacja tego samego algorytmu realizowanego przez pierwotny kod lub algorytmu dajacego ˛ zbliżony wynik końcowy. W systemach operacyjnych redundancja jest stosowana najcz˛eściej dla danych, które sa˛ przekazywane na zewnatrz ˛ systemu (np. obliczanie sum kontrolnych do pakietów sieciowych), jednak dane wewn˛etrzne zazwyczaj sa˛ optymalizowane pod katem ˛ wykorzystywanego miejsca i wydajności przetwarzania. Natomiast kod systemu operacyjnego bardzo rzadko jest redundantny – wynika to z konieczności zapewnienia dużej wydajności systemu operacyjnego. Mechanizmy detekcji w dużej mierze korzystaja˛ z izolacji oraz redundancji jako podstaw wykrywania bł˛edów. Naruszenie granic izolacji lub niezgodność danych z danymi kontrolnymi jest podstawa˛ do stwierdzenia obecności bł˛edu w systemie. Niemniej detekcja korzysta także i z innych metod wykrywania bł˛edów. Przykładem sa˛ asercje, czyli niezmienniki, których naruszenie oznacza nieprawidłowe działanie systemu. Asercje moga˛ być definiowane przez programist˛e, ale moga˛ być także odkrywane automatycznie na podstawie 118 obserwacji działajacego ˛ systemu (patrz [50]). Inna˛ metoda˛ detekcji jest monitorowanie cech systemu takich jak przepływ danych, czas reakcji systemu (performance monitor), lub zgłaszane zdarzenia (event monitor) – sa˛ to najcz˛eściej rozwiazania ˛ bazujace ˛ na analizie dzienników systemowych. Instytut Informatyki Politechniki Warszawskiej ma doświadczenie w projektowaniu mechanizmów opartych o asercje jak i analiz˛e dzienników systemu (patrz [71, 82, 83]). Detekcja jest szczególnie istotna w przypadku, gdy aktywacja bł˛edu nie zakończy si˛e awaria,˛ a jedynie nieprawidłowym działaniem systemu. Sytuacja taka jest niepożadana, ˛ ponieważ bład ˛ może istnieć w systemie operacyjnym niezauważony przed dłuższy czas zaburzajac ˛ generowane wyniki jednej lub grupy aplikacji. Zastosowanie mechanizmów detekcji w systemach operacyjnych zazwyczaj wia˛że si˛e z detekcja˛ bł˛edów w procesach użytkownika lub danych zewn˛etrznych, a wykrywanie bł˛edów wewn˛etrznych ograniczone jest do asercji przygotowanych przez programistów. Odtwarzalność jest to cecha pozwalajaca ˛ na wznowienie działania systemu po awarii lub wykryciu bł˛edu. Może to być osiagni˛ ˛ ete poprzez podj˛ecie działań naprawczych lub przywrócenie systemu do zapisanego poprzednio prawidłowego stanu. Możliwość zapami˛etywania migawek działajacego ˛ systemu operacyjnego wraz z uruchomionymi programami jest popularna˛ funkcja˛ systemów wirtualizacji. Obecnie wiele projektów skupionych jest na stworzeniu analogicznych systemów dla aplikacji użytkownika2 oraz wzbogaceniu jadra ˛ systemu GNU/Linux o mechanizmy tego typu (patrz [45]). Zadaniem znacznie trudniejszym niż odtworzenie ostatniego prawidłowego stanu aplikacji jest podj˛ecie próby naprawienia awarii, ponieważ nie jest wiadome jak długo bład ˛ istniał w systemie i jak wiele wprowadził odst˛epstw od prawidłowego działania systemu. 5.2. Ogólne założenia Celem pracy jest poprawa niezawodności istniejacego ˛ systemu operacyjnego. Mechanizmy wykrywania i obsługi bł˛edów musza˛ spełniać szereg wymagań. Podstawowe wymagania funkcjonalne to: detekcja bł˛edów, zapobieganie awariom, realizacja procedur naprawczych. Poprzez detekcj˛e bł˛edów rozumiana jest funkcja pozwalajaca ˛ na określenie, czy w systemie wystapił ˛ bład ˛ – niezależnie od tego, czy bład ˛ został już aktywowany i spowodował awari˛e, czy został jedynie wykryty. W przypadku, gdy bład ˛ został wykryty, ale nie spowodował awarii oczekuje si˛e od mechanizmów niezawodnościowych podj˛ecia działań zapobiegawczych zanim bład ˛ zostanie aktywowany. Natomiast w przypadku wystapienia ˛ awarii konieczna jest próba określenia, czy awaria została spowodowana bł˛edem sprz˛etowym i ewentualne wykonanie procedur naprawczych majacych ˛ na celu unikni˛ecie zgłaszania awarii. Celem wymienionych wymagań jest podtrzymanie pracy systemu oraz poinformowanie użytkownika o wykryciu 2 Np. http://criu.org/ 119 ewentualnych awarii sprz˛etu. Dopuszczalne jest czasowe generowanie nieprawidłowych wyników – mechanizmy wyższego poziomu powinny zapewnić tolerowanie tego typu sytuacji. Wymagania niefunkcjonalne, które zostały określone dla rozwiazań ˛ przygotowanych w niniejszej pracy, to: akceptowalne zużycie zasobów oraz możliwość integracji z istniejacym ˛ oprogramowaniem systemu GNU/Linux. Poziom akceptowalnego zużycia zasobów jest indywidualnie określany dla każdego systemu i cz˛esto jest on zależny od zakładanego poziomu niezawodności. Natomiast wymaganie minimalnego nakładu pracy potrzebnego do integracji jest zwiazane ˛ z praktycznym aspektem wykorzystania danego mechanizmu. Rozwiazania ˛ wymagajace ˛ wielu modyfikacji istniejacego ˛ oprogramowania moga˛ zostać uznane za zbyt ryzykowne do wdrożenia. Warto zaznaczyć, że projektant mechanizmów niezawodnościowych ma znacznie wi˛ecej swobody podczas przygotowania nowych systemów, gdzie mechanizmy te moga˛ zostać uwzgl˛ednione w architekturze systemu. 5.3. Identyfikacja krytycznych komponentów W celu usystematyzowania problemu zwi˛ekszania niezawodności oprogramowania konieczne jest zidentyfikowanie krytycznych komponentów, które sa˛ kluczowe dla prawidłowego działania systemu. Wskazanie i optymalizacja ich w pierwszej kolejności pozwoli na skuteczna˛ popraw˛e poziomu niezawodności systemów komputerowych. Zgodnie z analizami przeprowadzonymi w sekcji 4.5.3 można stwierdzić, że najistotniejsze z punktu widzenia poprawnego działania systemu jest prawidłowe działanie kodu systemu operacyjnego. Wynika to z dwóch faktów: jest on najbardziej wrażliwy na zaburzenia oraz tylko prawidłowe działanie kodu umożliwia poprawna˛ obsług˛e bł˛edów danych. Dodatkowo detekcja, czy kod został zaburzony w sposób trwały (np. poprzez uszkodzenie komórek pami˛eci RAM) jest zadaniem stosunkowo prostym – kod systemu operacyjnego jest najcz˛eściej ładowany z pliku i źródło to może posłużyć do weryfikacji obrazu kodu znajdujacego ˛ si˛e w pami˛eci. Jednak w przypadku aktywowania bł˛edów kodu przeprowadzenie udanej procedury naprawczej może być trudne lub wr˛ecz niewykonalne. Warto zaznaczyć, że przy wprowadzaniu mechanizmów zwi˛ekszania niezawodności konieczne jest również zapewnienie spójności kodu implementujacego ˛ te mechanizmy (zagadnienie to zostało szerzej opisane w 5.5). Dane składowane na stosie oraz dane alokowane sa˛ mniej podatne na zaburzenia niż kod systemu operacyjnego (patrz 4.5.3). Niemniej ochrona stosu, ze wzgl˛edu na różnorodność i duża˛ zmienność składowanych danych jest zadaniem trudnym. Dane przechowywane na stosie sa˛ niejednorodne – oprócz ramek stosu moga˛ tam być przechowywane tymczasowe bufory, pośrednie wyniki obliczeń, wartości rejestrów, argumenty wywołań funkcji oraz wartości zwracane przez funkcje. Istotny jest fakt, że dane składowane na stosie sa˛ ważne tylko i wyłacznie ˛ przez czas wykonania bieżacej ˛ procedury. Dodatkowo brak jest 120 referencyjnego obrazu tych danych, a obliczanie sum kontrolnych stanu stosu przy wywołaniach kolejnych procedur nie może być zastosowane ze wzgl˛edu na możliwość modyfikacji danych znajdujacych ˛ si˛e na stosie przez wywoływana˛ procedur˛e (mechanizm ten polega na przekazaniu do procedury parametru b˛edacego ˛ adresem bufora znajdujacego ˛ si˛e na stosie). Natomiast dane przechowywane w pami˛eci alokowanej charakteryzuja˛ si˛e określona˛ struktura˛ – najcz˛eściej zorganizowane sa˛ one w struktury danych (np. listy, drzewa, kolejki). Należy wyróżnić dane wewn˛etrzne i zewn˛etrzne. Dane zewn˛etrzne sa˛ to dane, których źródło pochodzenia znajduje si˛e poza pami˛ecia˛ komputera – np. dane otrzymane przy transmisji sieciowej, odczycie dysku twardego, czy obraz zarejestrowany zewn˛etrzna˛ kamera.˛ Natomiast dane wewn˛etrzne sa˛ tworzone w pami˛eci systemu w celu prawidłowego działania i realizacji usług – np. wewn˛etrzna lista procesów uruchomionych w systemie, struktury systemu plików, robocze struktury danych wykorzystywane przy zarzadzaniu ˛ zadaniami. Dane zewn˛etrzne sa˛ cz˛eściej poddawane sprawdzeniom pod wzgl˛edem poprawności i zaburzanie ich jest wykrywane przez system – np. zaburzanie pakietów danych odbieranych z sieci powoduje jedynie uruchomienie mechanizmów retransmisji (patrz [38]). Z kolei dane wewn˛etrzne najcz˛eściej nie sa˛ wzbogacone w dodatkowe informacje pozwalajace ˛ na weryfikacj˛e ich poprawności w przypadku awarii. W celu zwi˛ekszania niezawodności konieczne jest usprawnienie poprawnego wykonania kodu. Osiagni˛ ˛ ecie tego celu warunkuje prawidłowo działajacy ˛ stos. Dzi˛eki zwi˛ekszeniu niezawodności działania tych komponentów możliwe jest skuteczne zastosowanie mechanizmów ochrony danych. 5.4. Założenia dotyczace ˛ projektowanych mechanizmów zwi˛ekszania niezawodności Bł˛edy pami˛eci moga˛ być zjawiskiem przemijalnym, incydentalna˛ zmiana˛ wartości danych lub być efektem trwałego uszkodzenia sprz˛etu (szerszy opis w rozdziale 2). Najskuteczniejsza˛ strategia˛ obsługi awarii powstałych na skutek bł˛edów pami˛eci jest odtworzenie systemu do wcześniej zapisanego stanu (checkpointing – patrz 2.3). Niemniej rozwiazanie ˛ tego typu powoduje utrat˛e cz˛eści obliczeń, a czas potrzebny na przeprowadzenie procedury odtwarzania może być nieakceptowalny. Dodatkowym ograniczeniem sa˛ trudności w implementacji techniki checkpointing dla systemu operacyjnego – najcz˛eściej wykonywana jest kopia zapasowa systemu operacyjnego działajacego ˛ wewnatrz ˛ maszyny wirtualnej, co z kolei polega na niezawodnym działaniu systemu b˛edacego ˛ gospodarzem maszyny wirtualnej (szerzej opisane w 2.3). Mechanizmy zaproponowane w podrozdziałach 5.5 oraz 5.6 pozwalaja˛ na szybsze przeprowadzenie procedury naprawczej niż mechanizm checkpointing kosztem potencjalnego, 121 czasowego generowania przez system nieprawidłowych wyników. Celem nadrz˛ednym projektowanych mechanizmów jest unikni˛ecie awarii systemu powodujacych ˛ jego niedost˛epność. W przypadku wystapienia ˛ awarii, pomimo działań podj˛etych przez zaproponowane przez autora mechanizmy, konieczne jest zastosowanie innych mechanizmów niezawodnościowych – np. opisany checkpointing. Natomiast w sytuacji generowania niepoprawnych wyników konieczne jest zastosowanie mechanizmów umożliwiajacych ˛ ich tolerowanie. Rozwiazania ˛ przedstawione w podrozdziałach 5.5 i 5.6 poświ˛econe sa˛ bł˛edom, których skutki sa˛ obserwowalne przy wi˛ecej niż pojedynczym odczycie danych, czyli bł˛edy zmiany wartości i trwałe uszkodzenia. Bł˛edy migoczace ˛ nie sa˛ rozważane z uwagi na brak możliwości określenia pierwotnej przyczyny ewentualnej awarii. Przykładowo przekłamanie przy odczycie komórki pami˛eci zawierajacej ˛ adres skoku wykonanego przez procesor uniemożliwia przeprowadzenie analizy jaki kod został wykonany w wyniku zaburzenia. Należy zwrócić uwag˛e na konieczność detekcji, czy zaburzona komórka pami˛eci jest jest trwale uszkodzona. W takim przypadku wymagane jest wyłaczenie ˛ niesprawnego obszaru pami˛eci z użycia. Procedura wyłaczenia ˛ jest zależna od rodzaju danych, który był przechowywany. Jeżeli był to kod systemu operacyjnego, to konieczna jest próba przeniesienia kodu z uszkodzonego miejsca pami˛eci. Jednym z możliwych rozwiazań ˛ jest załadowanie poprawnego kodu z referencyjnego obrazu jadra ˛ i aktualizacja instrukcji skoku w uszkodzone miejsce, tak aby adresy skoku wskazywały nowe miejsce. W przypadku danych systemu operacyjnego procedura odtworzenia i przeniesienia danych w inny obszar pami˛eci jest zadaniem, które wymaga znajomości struktury odtwarzanych danych. Dodatkowym wymaganiem jest, aby informacja o uszkodzonych rejonach pami˛eci była zapisana i odtworzona po ponownym uruchomieniu systemu na tym samym sprz˛ecie. Warto zaznaczyć, że jadro ˛ GNU/Linux jest wyposażone w funkcj˛e „omijania” niektórych banków pami˛eci3 , jednak metoda ta ma pewne ograniczenia. Po pierwsze wyłaczony ˛ obszar musi być wskazany przy ładowaniu jadra ˛ systemu. Po drugie implementacja polega na oznaczeniu danego obszaru jako wykorzystany w mechanizmie alokacji, przez co nie zostanie on zaalokowany ponownie – o ile metoda ta działa w wi˛ekszości przypadków, to nie może ona posłużyć do wyłaczenia ˛ obszarów pami˛eci, gdzie ładowane jest jadro ˛ systemu operacyjnego GNU/Linux (adres ładowania jest definiowany podczas kompilacji jadra). ˛ 5.5. Zapewnienie spójności kodu wykonywalnego W niniejszym podrozdziale przedstawiony jest sposób zapewnienia spójności kodu jadra ˛ systemu operacyjnego polegajacy ˛ na periodycznym sprawdzeniu załadowanego w pami˛eci 3 https://www.kernel.org/doc/Documentation/bad_memory.txt 122 RAM obrazu systemu. Metoda ta jest implementacja˛ idei zapobiegania awariom i uzupełnia ona rozwiazania ˛ przedstawione w podrozdziale 5.6, które polegaja˛ na obsłudze sytuacji awaryjnych. Zastosowanie rozwiazań ˛ okresowego sprawdzania spójności jest konieczne w celu przeciwdziałania istnieniu w systemie nieaktywowanych bł˛edów oraz wykrywaniu bł˛edów aktywowanych, które nie spowodowały awarii. Szczególnie istotna˛ kwestia˛ jest możliwość akumulacji bł˛edów w kodzie, który nie jest wykonywany podczas prawidłowej pracy systemu – np. kod obsługi sytuacji wyjatkowych ˛ lub niewykorzystywanych usług. Możliwy jest scenariusz, gdzie bł˛edy zakumulowane w kodzie obsługi sytuacji wyjatkowej ˛ uniemożliwiaja˛ przeprowadzenie procedury obsługi, co z kolei skutkuje awaria˛ systemu przy wystapieniu ˛ sytuacji wyjatkowej. ˛ Próba˛ przeciwdziałania takiej sytuacji jest wykorzystanie okna czasowego od wystapienia ˛ bł˛edu do wykonania zaburzonego kodu w celu przeprowadzenia procedury usuni˛ecia bł˛edu przed jego aktywowaniem. Sprawdzanie spójności kodu istotne jest również w przypadku bł˛edów, które zostały aktywowane. Jak wykazano w eksperymentach przeprowadzonych w sekcji 4.5.3 współczynnik tolerancji dla bł˛edów typu bit-flip w kodzie systemu operacyjnego wynosi nawet 31%. Bł˛edy te mogły spowodować różnego typu odst˛epstwa od prawidłowego działania systemu. Stwierdzenie ich obecności jest istotne przy ocenie zaufania do wygenerowanych przez system wyników. Dodatkowa˛ kwestia˛ jest zapewnienie poprawności kodu realizujacego ˛ okresowe sprawdzanie spójności kodu jadra ˛ systemu operacyjnego, ponieważ w przypadku wystapienia ˛ bł˛edu w tym kodzie może on nie realizować swojej funkcji lub sygnalizować fałszywe alarmy. Możliwym scenariuszem jest zastosowanie kilku oddzielnych instancji mechanizmu okresowego sprawdzania spójności kodu uruchamianych naprzemiennie. Dzi˛eki takiemu rozwiazaniu ˛ zwi˛ekszane jest prawdopodobieństwo wykrycia bł˛edu przed aktywacja,˛ chociaż prawdopodobieństwo aktywacji bł˛edu nie jest wyeliminowane. Implementacja programowego zapewniania spójności kodu jest alternatywa˛ dla mechanizmów sprz˛etowych – np. pami˛eci ECC (patrz 2.2.4). Niemniej zastosowanie pami˛eci ECC wia˛że si˛e z wi˛ekszym kosztem systemu. Architektura W celu realizacji okresowego sprawdzania spójności kodu jadra ˛ systemu operacyjnego przygotowany został moduł jadra ˛ systemu GNU/Linux. Rozwiazanie ˛ to zostało wybrane w zwiazku ˛ z założeniem minimalnego kosztu integracji mechanizmów niezawodnościowych z istniejac ˛ a˛ implementacja˛ systemu operacyjnego (opisane w podrozdziale 5.2). Moduł jadra ˛ może być załadowany w dowolnym momencie działania systemu i realizuje on nast˛epujace ˛ funkcje: 123 — wykonanie kopii zapasowej statycznego obrazu kodu jadra ˛ 4 w momencie załadowania modułu, — okresowe porównywanie obrazu kodu i wykonanej kopii zapasowej, — w przypadku wykrycia bł˛edu kod jadra ˛ systemu operacyjnego jest odtwarzany z kopii zapasowej. Eksperymentalna weryfikacja Zaproponowana metoda została zweryfikowana eksperymentalnie. Scenariusz polegał na dwukrotnym uruchomieniu instancji QEMU emulujacej ˛ system GNU/Linux. Przy pierwszym uruchomieniu wprowadzono losowy bład ˛ w procedurze tcp_v4_rcv5 . Nast˛epnie uruchomiono program wget, który poprzez wywołanie usług sieciowych systemu operacyjnego aktywował wprowadzony bład, ˛ co z kolei spowodowało awari˛e. Zapis przeprowadzonej interakcji z systemem został umieszczony na listingu 5.1. 1 2 3 4 5 6 7 8 9 10 root@debian-i386:~# wget www.pw.edu.pl --2013-04-11 18:27:59-- http://www.pw.edu.pl/ Resolving www.pw.edu.pl... 194.29.151.5 Connecting to www.pw.edu.pl|194.29.151.5|:80... [ 87.748803] BUG: unable to handle kernel paging request at e4de8b58 [ 87.749016] IP: [<c1206d9f>] tcp_v4_rcv+0x35/0x5a2 [ 87.749016] *pde = 00000000 [ 87.749016] Thread overran stack, or stack corrupted [ 87.749016] Oops: 0000 [#1] SMP ... Listing 5.1: Przykład interakcji po wstrzykni˛eciu bł˛edu. Podczas drugiego uruchomienia wstrzykni˛ecie takiego samego bł˛edu poprzedzono załadowaniem opracowanego modułu. Zapis interakcji z systemem został umieszczony na listingu 5.2. Zastosowanie modułu sprawdzajacego ˛ spójność kodu spowodowało wykrycie i naprawienie bł˛edu. W liniach 2-3 widoczny jest komunikat zgłaszany przez opracowany moduł o wykryciu bł˛edu oraz odtworzeniu obrazu kodu jadra ˛ systemu z kopii zapasowej. Dzi˛eki przeprowadzeniu operacji odtworzenia obrazu kodu możliwe było pobranie pliku przez sieć programem wget. Wnioski Przedstawiona metoda jest najprostszym mechanizmem zapewniania spójności kodu jadra ˛ systemu operacyjnego i została zaproponowana w celu sprawdzenia możliwości implementacji tego typu mechanizmu w systemie operacyjnym GNU/Linux oraz wyznaczenia dalszych kierunków badań. Dzi˛eki okresowemu sprawdzaniu spójności obrazu kodu jadra ˛ możliwe 4 Statyczny obraz kodu jadra ˛ systemu operacyjnego nie zawiera w sobie kodu załadowanych modułów. Funkcja tcp_v4_rcv wykorzystywana jest przez system GNU/Linux podczas odbierania pakietów sieci TCP/IP. 5 124 1 2 3 4 5 6 7 8 9 10 root@debian-i386:~# [ 95.439364] FixModule - found code image integrity error at c1206d7a. [ 95.439924] FixModule - restoring from backup... success. root@debian-i386:~# wget www.pw.edu.pl --2013-05-11 18:31:48-- http://www.pw.edu.pl/ Resolving www.pw.edu.pl... 194.29.151.5 Connecting to www.pw.edu.pl|194.29.151.5|:80... connected. HTTP request sent, awaiting response... 200 OK Length: unspecified [text/html] Saving to: "index.html" 11 12 [ <=> ] 35,790 --.-K/s in 0.02s 13 14 2013-05-11 18:31:49 (1.77 MB/s) - "index.html" saved [35790] Listing 5.2: Przebieg interakcji po wstrzykni˛eciu bł˛edu i sprawdzeniu spójności kodu. jest zwi˛ekszenie wartości współczynnika detekcji bł˛edów, a także tolerancji bł˛edów – niestety określenie czy wykryty ta˛ metoda˛ bład ˛ był aktywowany jest niemożliwe. Zagadnienie to oraz wyznaczenie optymalnej cz˛estości przeprowadzania sprawdzenia spójności wymaga dalszych badań. W przypadku docelowej implementacji, w celu zwi˛ekszenia niezawodności, należałoby rozważyć uzupełnienie kopii zapasowej danych kodami korekcji bł˛edów i sumami kontrolnymi, co pozwoliłoby na zapewnienie spójności także danych służacych ˛ do naprawy uszkodzonego obrazu jadra. ˛ Istotnym rozszerzeniem zaproponowanej metody byłoby również uwzgl˛ednienie w chronionym obszarze kodu ładownych modułów jadra ˛ systemu operacyjnego, a także kodu aplikacji użytkownika. 5.6. Procedury naprawcze Zapewnienie spójności kodu opisane w podrozdziale 5.5 jest skuteczne jedynie w przypadku bł˛edów nieaktywowanych lub aktywowanych, ale maskowanych. Uzupełnieniem tej metody sa˛ procedury naprawcze, które pozwalaja˛ na obsług˛e sytuacji wyjatkowych ˛ wywołanych przez bł˛edy. W podrozdziale opisane sa˛ oryginalne metody pozwalajace ˛ na osiagni˛ ˛ ecie wi˛ekszego poziomu niezawodności systemów komputerowych. 5.6.1. Metoda obsługi przerwań procesora dla kodu systemu operacyjnego Analiza wyników eksperymentów zaburzania kodu, stosu i danych opisanych w sekcji 4.5.3 pozwala stwierdzić, że znaczna cz˛eść wstrzykni˛etych bł˛edów powoduje awarie niedozwolonego dost˛epu do pami˛eci („Paging request failed”). Obserwacja ta jest podstawa˛ badań nad metodami zwi˛ekszania niezawodności przedstawionymi w niniejszym podrozdziale. 125 W celu opracowania mechanizmu obsługi awarii „Paging request failed” poddano analizie scenariusz jej wyst˛epowania. Składa si˛e on z nast˛epujacych ˛ etapów: — aktywacja bł˛edu poprzez wykonanie zaburzonych instrukcji, — odwołanie do niedost˛epnej pami˛eci, — jednostka MMU zgłasza przerwanie sygnalizujace ˛ nieprawidłowy dost˛ep do pami˛eci, — sterowanie przekazane jest do systemu operacyjnego, którego zadaniem jest obsługa przerwania. System operacyjny sprawdza, czy żadany ˛ adres docelowy jest dost˛epny dla zadania b˛edacego ˛ źródłem przerwania – sytuacja taka może mieć miejsce w przypadku dost˛epności danych na partycji wymiany pami˛eci wirtualnej. W tym przypadku dane sa˛ pobierane z partycji wymiany do pami˛eci RAM, obsługa przerwania jest zakończona, a zadanie jest wznawiane od instrukcji, która spowodowała przerwanie. Jeżeli dane sa˛ niedost˛epne, zadanie zostaje zakończone w trybie awaryjnym – powoduje to zgłoszenie awarii „Paging request failed” dla zadań wykonywanych w trybie jadra ˛ systemu oraz „Segfault” dla zadań wykonywanych w trybie nieuprzywilejowanym (aplikacje użytkownika). Dzi˛eki przeprowadzonym badaniom nad liczba˛ wykonań zaburzonej instrukcji kodu oraz odległościa˛ mi˛edzy zaburzana˛ instrukcja˛ i instrukcja,˛ której wykonanie wywołuje awari˛e (rysunki 4.25 i 4.26) można stwierdzić, że znaczna grupa wstrzykni˛etych bł˛edów powoduje awari˛e już przy wykonaniu pierwszej zaburzonej instrukcji. Połaczenie ˛ tego faktu z możliwościa˛ modyfikacji procedury obsługi przerwania zgłoszonego przez MMU jest podstawa˛ opracowania oryginalnej metody zwi˛ekszania niezawodności. Metoda ta polega na wykonaniu sprawdzenia kodu, który zgłosił przerwanie, pod katem ˛ obecności bł˛edu i ewentualne podj˛ecie procedury naprawczej. Architektura Przygotowane rozwiazanie ˛ jest modułem naprawczym, który podobnie jak moduł opisany w podrozdziale 5.5 wykonuje kopi˛e statycznego kodu jadra ˛ w celu wykorzystania jej do odtwarzania zaburzonego obrazu. Odtwarzanie jest wykonywane w momencie zgłoszenia przerwania, które powodowałoby awari˛e. Podstawowa wersja zaproponowanej metody modyfikuje kod obsługi przerwania zgłoszonego przez MMU tak, aby realizował on algorytm zilustrowany na rysunku 5.1. W domyślnej konfiguracji jadra ˛ nie jest możliwe modyfikowanie procedur obsługi przerwań. W celu przechwycenia sterowania przed zgłoszeniem awarii konieczne było zmodyfikowanie kodu jadra ˛ w ten sposób, aby zgłoszenie awarii było uzależnione od wywołania pewnej funkcji F zwracajacej ˛ wartość logiczna.˛ W zależności od wartości zwracanej przez funkcj˛e F procedura obsługi przerwania zgłasza awari˛e (dla wyniku TRUE funkcji F ) lub wznawia wykonanie zadania (dla wyniku FALSE). W implementacji umieszczonej w kodzie jadra ˛ systemu operacyjnego funkcja F zawsze zwraca wartość TRUE, co oznacza zachowanie niezmienione wzgl˛edem domyślnej implementacji. 126 W momencie załadowania opracowanego modułu naprawczego wywołania funkcji F sa˛ przechwytywane przez moduł naprawczy z wykorzystaniem mechanizmu kprobes6 . Mechanizm kprobes pozwala na przechwycenie wywołań określonej funkcji poprzez podmienienie pierwszych instrukcji funkcji na instrukcj˛e skoku do procedur zdefiniowanych przez użytkownika kprobes. W ten sposób możliwe jest przekazanie sterowania do modułu naprawczego zamiast wykonania funkcji F . Dodatkowym rozszerzeniem tej metody jest przekazywanie do funkcji F parametrów kontekstu procedury obsługi przerwania – w szczególności wskaźnika do struktury danych opisujacych ˛ zadanie, które jest źródłem przerwania. Struktura ta zawiera wartości rejestrów procesora w momencie zgłoszenia przerwania przez zadanie, flagi uprzywilejowania zadania (zadanie wykonywane w przestrzeni jadra ˛ systemu operacyjnego lub przestrzeni użytkownika) oraz informacje o pami˛eci wykorzystywanej przez zadanie. W oryginalnej implementacji funkcji F parametr ten nie jest wykorzystywany, jednak dane te sa˛ konieczne dla prawidłowego działania modułu naprawczego. Moduł naprawczy działa w nast˛epujacy ˛ sposób: w oparciu o informacje o stanie zadania wykonywane jest sprawdzenie spójności kodu wykonywanej przez zadanie funkcji wzgl˛edem referencyjnego obrazu. W przypadku wykrycia bł˛edu, moduł odtwarza prawidłowy kod funkcji oraz wstrzykuje wartość FALSE jako wartość zwracana˛ przez przechwycona˛ funkcj˛e F , co powoduje zablokowanie zgłoszenia awarii i wznowienie działania zadania w miejscu zgłoszenia przerwania. Przepływ sterowania pomi˛edzy różnymi komponentami został przedstawiony na rysunku 5.2. W przypadku, gdy moduł naprawczy przeprowadzi procedur˛e odtworzenia kodu funkcji, jednak instrukcja powodujaca ˛ zgłoszenie przerwania nie jest zaburzona˛ instrukcja,˛ wznowienie działania spowoduje ponowne zgłoszenie przerwania – w tym przypadku moduł nie wykryje zaburzenia kodu i zwróci wartość TRUE powodujac ˛ zgłoszenie awarii. Natomiast w przypadku, gdy zaburzona instrukcja jest źródłem przerwania, przeprowadzenie naprawy umożliwia dalsze wykonanie kodu zadania oraz unikni˛ecie awarii. Po przeprowadzeniu analiz pozostałych awarii zgłaszanych przez system operacyjny opisanych na stronie 82 zaobserwowano, że wiele z nich jest również wyzwalanych nieudana˛ obsługa˛ przerwania. Wykorzystano ten fakt do przygotowania drugiej wersji modułu, która oprócz modyfikacji przerwań zgłoszonych przez MMU modyfikowała także procedury obsługi pozostałych przerwań. Konfiguracja eksperymentu W celu zweryfikowania skuteczności zaproponowanej metody przygotowano eksperyment identyczny z eksperymentem zaburzania kodu opisanym sekcji 4.5.3 dla każdego z opisanych w 6 http://sourceware.org/systemtap/kprobes/ 127 ProceduraNobsługiN przerwaniaNMMU Tak DomyśnaNprocedura obsługiNprzerwania WznowienieNdziałania zadania CzyNmożnaN obsłużyć przerwanie? Naprawa koduNzadania Nie SprawdzenieNspójności koduNzadania Tak CzyNwykryto błąd? Nie AwaryjneNzakończenie działaniaNzadania Rysunek 5.1: Algorytm obsługi przerwania System operacyjny Zadanie zgłoszenie przerwania procesora Moduł naprawczy przechwycenie obsługi z użyciem kprobes rezultat procedury naprawczej wznowienie lub zakończenie zadania Rysunek 5.2: Przepływ sterowania procedury obsługi przerwania 128 80 60 40 0 20 Testy % PU + PS NU + NS Kod I RM v.1 I RM v.2 I Kod II RM v.1 II RM v.2 II Rysunek 5.3: Porównanie manifestacji bł˛edów dla różnych wersji modułu naprawczego nim scenariuszy. Jedyna˛ różnica˛ było załadowanie modułów naprawczych przed wykonaniem scenariusza testowego. Uzyskane wyniki obu wersji modułów zostały porównane z wynikami uzyskanymi w sekcji 4.5.3. Wyniki Na rysunkach 5.3, 5.4, 5.5 i w tabeli 5.1 przyj˛eto nast˛epujace ˛ oznaczenie eksperymentów: „Kod I/II” sa˛ to powtórzone wyniki eksperymentów opisanych w sekcji 4.5.3, „RM v.1 I/II” sa˛ to eksperymenty wykorzystujace ˛ moduł naprawczy realizujacy ˛ obsług˛e przerwań nieprawidłowego dost˛epu do pami˛eci, natomiast „RM v.2 I/II” sa˛ to eksperymenty wykorzystujace ˛ moduł naprawczy obsługujacy ˛ wszystkie rodzaje przerwań. Odsetek zamanifestowanych bł˛edów dla przeprowadzonych eksperymentów został przedstawiony na rysunku 5.3. Na rysunku 5.4 zobrazowany jest rozkład poszczególnych typów manifestacji, przy czym wprowadzono nast˛epujace ˛ oznaczenia nowych typów manifestacji bł˛edów: — PR – prawidłowy wynik działania systemu, wykryto komunikat o przeprowadzeniu procedury naprawczej przez moduł, — NRT – nieprawidłowy wynik działania systemu, wykryto komunikat o wyzwoleniu procedury naprawczej przez moduł, jednak zaburzenie nie zostało wykryte w obr˛ebie funkcji zgłaszajacej ˛ przerwanie, — NRD – nieprawidłowy wynik działania systemu, wykryto komunikat o przeprowadzeniu procedury naprawczej przez moduł. 129 100 80 60 40 0 20 Testy % PU PS PR NU NRD NRT NS Kod I RM v.1 I RM v.2 I Kod II RM v.1 II RM v.2 II 60 40 DU DS NDU NDS 0 20 Testy % 80 100 Rysunek 5.4: Rozkład typów bł˛edów dla różnych wersji modułu naprawczego Kod I RM v.1 I RM v.2 I Kod II RM v.1 II RM v.2 II Rysunek 5.5: Dost˛epność systemu operacyjnego dla różnych wersji modułu naprawczego 130 Komunikat % Bad page state Bad PC value Null dereference Null dereference 0 Paging request failed Sched while atomic EXT FS error General protection I/O error Page alocation failure Panic in interrupt Panic - kill init Segfault Stack protector Undefined instruction Recovery Done Recovery Triggered Unclassified Kod I 0,41 14,92 29,42 11,56 50,03 3,34 0 17,71 0 0,03 19,37 8,49 0,85 0,42 9,03 0 0 2,31 RM v.1 I 0,36 13,52 22,68 9,58 39,53 2,5 0,6 14,77 0,24 0,06 16,78 5,31 0,68 0,32 9,22 29,82 78 4,23 RM v.2 I 0,25 13,76 23,47 9,56 37,71 2,04 0,29 12,02 0,27 0 16,58 5,37 0,86 0,61 7,95 37 89,68 5,2 Kod II 0,31 13,73 29,12 11,18 49,51 4,33 0,68 24,74 0,35 0,02 40,45 4,55 0,88 0,42 8,96 0 0 3,87 RM v.1 II 0,26 16,98 27,28 10,99 42,05 3,85 0,85 24,26 0,55 0,07 41,57 2,66 1,4 0,57 11,21 14,72 69,14 7,76 RM v.2 II 0,13 18,26 28,58 12,26 44,66 3,88 0,93 21,18 0,75 0,05 38,82 3,21 1,32 0,36 6,72 17,84 59,84 10,6 Tabela 5.1: Udział komunikatów zgłaszanych przez system operacyjny dla różnych wersji modułu naprawczego Rysunek 5.5 obrazuje dost˛epność systemu dla każdej z przeprowadzonych kampanii. W tabeli 5.1 przedstawiony jest rozkład typów zgłoszonych komunikatów wraz z uwzgl˛ednieniem komunikatów „Recovery Triggered” i „Recovery Done” oznaczajacych ˛ odpowiednio wyzwolenie procedury naprawczej oraz przeprowadzenie odtwarzania w trakcie działania tej procedury. Wnioski Dzi˛eki zastosowaniu zaproponowanej metody zwi˛ekszono liczb˛e testów, w których uzyskano prawidłowy wynik powierzonego zadania. Z wykresu 5.3 można odczytać, że w przypadku obsługi przerwań zgłaszanych przez MMU zwi˛ekszono liczb˛e prawidłowych wyników o około 10 p.p., a dzi˛eki obsłudze pozostałych przerwań uzyskano dodatkowe 5 p.p. w przypadku obu badanych scenariuszy eksperymentów. Wartość współczynnika detekcji bł˛edów Fd (patrz 2.5.2) można odczytać jako suma PR + NRD z wykresu 5.4, co z kolei umożliwia wyznaczenie wartości współczynnika naprawy bł˛edów Fr na 46% oraz 55% dla obu modułów naprawczych w scenariuszu I. Dla scenariusza II nie było możliwe określenie ilości komunikatów PR z uwagi na charakter tego scenariusza (szerzej w 4.5.3). Zaproponowana metoda zwi˛ekszania niezawodności nie gwarantuje przywrócenia prawidłowego stanu systemu operacyjnego, niemniej zmniejszone jest zagrożenie wystapienia ˛ awarii uniemożliwiajacej ˛ prac˛e systemu. Przywrócenie prawidłowej pracy systemu jest pewne wyłacznie ˛ w przypadku, gdy pierwsze 131 wykonanie zaburzonego kodu wyzwoli awari˛e. Dodatkowo analiza rysunku 5.5 pozwala stwierdzić, że zastosowanie modułu naprawczego nie wpłyn˛eło znaczaco ˛ na charakterystyk˛e dost˛epności systemu w przypadku nieprawidłowej pracy systemu – wynika z tego, że moduł naprawczy w równym stopniu zapobiegał awariom powodujacym ˛ niedost˛epność systemu, jak i tym, które nie powodowały takiego efektu. Warto zwrócić uwag˛e na fakt, że około 15% testów z zamanifestowanym bł˛edem spowodowało wykrycie zaburzenia w funkcji, która była wykonywana w trakcie zgłoszenia przerwania (wartość NRD na rysunku 5.4). Obsługa takiej sytuacji jest rozważana w 5.6.2. Pewnym ograniczeniem jest obsługa przez moduł naprawczy tylko statycznego kodu systemu operacyjnego – istnieje możliwość potencjalnego zwi˛ekszenia niezawodności poprzez napraw˛e kodu ładowanych modułów systemu operacyjnego. Warto zaznaczyć, że procedury obsługi przerwań moga˛ być wywołane zarówno przez kod systemu operacyjnego jak i aplikacje użytkownika. Oznacza to, że jeżeli system operacyjny dysponowałby referencyjnym obrazem kodu aplikacji użytkownika, to możliwe byłoby rozszerzenie zastosowania zaproponowanej metody o ten obszar. 5.6.2. Algorytm brudnych zasobów Główna˛ cecha˛ metody obsługi przerwań jest naprawa wyłacznie ˛ bł˛edów, które spowodowały wywołanie przerwania procesora już przy pierwszym wykonaniu zaburzonej instrukcji. Nie pokrywa ona przypadków, kiedy wprowadzony bład ˛ skutkuje awaria˛ po wykonaniu kilku instrukcji od aktywacji. W celu zbadania takich przypadków moduły opisane w sekcji 5.6.1 zostały wyposażone w funkcj˛e zrzutu obrazu kodu zaburzonej funkcji7 i obrazu jej kopii zapasowej. Uzyskane obrazy zostały poddane deasemblacji8 i poddane analizie – wszystkie zamieszczone w niniejszej sekcji przykłady kodu assembler zostały uzyskane w wyniku przeprowadzonych eksperymentów. Na listingu 5.3 zamieszczony jest przykładowy zapis porównujacy ˛ zaburzony zestaw instrukcji z oryginalnym. Zapis ten składa si˛e z kolejnych instrukcji procesora w j˛ezyku AT&T Assembly Language dla architektury x869 . W liniach 1-4 przedstawione sa˛ instrukcje, które były wspólne dla obu obrazów kodu przed zaburzeniem. W liniach 5-7 po lewej stronie znaku „|” zapisane sa˛ instrukcje zaburzonego kodu, natomiast po prawej kodu oryginalnego. Linie 8-10 zawieraja˛ instrukcje, które były wspólne dla obu obrazów, a wyst˛epuja˛ po zaburzonym fragmencie kodu. Znakiem „>” w linii 6 oznaczona jest instrukcja, która spowodowała zgłoszenie przerwania. W przypadku zaburzenia kodu przedstawionego na listingu 5.3 zmieniony był 1 bit. Instrukcje i ich argumenty w architekturze x86 kodowane sa˛ ciagami ˛ bajtów o zmiennej 7 8 9 Funkcja rozumiana jest tutaj jako symbol wymieniony w pliku /proc/kallsyms Proces przekształcenia kodu binarnego na odpowiadajacy ˛ mu zestaw instrukcji j˛ezyka assembler. http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html 132 1 2 3 4 5 6 7 8 9 10 mov %edx,%ecx mov %ebx,%eax mov %esi,%edx call *(%edi) mov (%ebx),%edx | mov 0x20(%ebx),%edx > and %dh,(%ecx) | xor %eax,%eax rorb $0x1,-0x3d09f3b2(%ebx) | mov 0xc(%esi),%ecx je 0x53 test %ecx,%ecx mov $0x41,%edi Listing 5.3: Deasemblacja instrukcji zaburzonej i oryginalnej długości, co spowodowało, że zaburzenie argumentu funkcji mov w linii 5 wpłyn˛eło na zmian˛e znaczenia kolejnych instrukcji w liniach 6-7. Z analizy zamieszczonego przykładu wynika, że tuż przed zgłoszeniem przerwania procesor wykonał tylko zaburzona˛ instrukcj˛e mov z linii 5. W wyniku jej działania do rejestru %edx została załadowana wartość pami˛eci spod adresu (%ebx) zamiast 0x20(%ebx). Naprawa˛ takiej sytuacji byłoby przywrócenie w procedurze obsługi przerwań oryginalnego obrazu kodu oraz cofni˛ecie licznika instrukcji procesora do instrukcji mov. Wynika to z faktu, że jedynym zmodyfikowanym rejestrem w zaburzonym wykonaniu był rejestr %edx. Rejestr ten przy wykonaniu oryginalnego kodu zostałby na nowo zapisany prawidłowa˛ wartościa.˛ Zaproponowana procedura naprawcza jest problemem odtworzenia prawidłowego stanu wykonania zadania. Opracowana została formalna definicja tego problemu: Definicja 5.6.1. Stan wykonania Si jest to kombinacja stanu pami˛eci Mi i stanu rejestrów procesora Ri przed wykonaniem i-tej instrukcji przez procesor P . Przebiegiem wykonania procesora P jest uporzadkowany ˛ zbiór stanów S = (S0 , S1 , ..., Sn ). Stanem równoważnym Wi stanowi Si jest kombinacja stanu pami˛eci Mi0 i stanu rejestrów procesora Ri0 , gdzie w przebiegu wykonania S stan Si może być zastapiony ˛ stanem Wi , a zasoby należace ˛ do Wi majace ˛ inne wartości niż ich odpowiedniki należace ˛ do Si w S nie sa˛ odczytywane lub sa˛ nadpisane nowymi wartościami. Zaburzonym przebiegiem wykonania jest uporzadkowany ˛ zbiór stanów Sf = (S0 , S1 , ..., Si−1 , Qi , Qi+1 , ..., Qn ) gdzie stany Sj , (0 ≤ j < i) sa˛ stanami uzyskanymi poprzez wykonanie niezaburzonych instrukcji, natomiast stany Qj , (i ≤ j ≤ n) sa˛ stanami uzyskanymi poprzez wykonanie zaburzonych instrukcji. Problem odtwarzania jest to znalezienie transformacji T (Qn , Sk ) stanu Qn do stanu równoważnego stanowi Sk , gdzie 0 ≤ k < i. Wynikiem przeprowadzenia tak zdefiniowanej operacji odtwarzania jest przepływ wykonania składajacy ˛ si˛e ze stanów S = (S0 , S1 , ..., Si−1 , Wi , Wi+i , ..., Wj−1 , Sj , Sj+1 , ..., Sn . Transformacja stanu Qn do Sk może składać si˛e z nast˛epujacych ˛ operacji: zmiana wartości 133 licznika instrukcji procesora, zapis zawartości rejestrów oraz pami˛eci, wykonanie operacji arytmetycznych. Zdefiniowany problem odtwarzania jest pokrewny problemowi wstecznego wykonania znanego z literatury. Wsteczne wykonanie polega na możliwości odtworzenia każdego stanu poprzedzajacego ˛ stan Si w celu inspekcji stanu pami˛eci w poszukiwaniu bł˛edów w implementacji. Jednak standardowa architektura systemów komputerowych nie wspiera takiego zastosowania. Istnieje wiele propozycji implementacji systemów pozwalajacych ˛ na wsteczne wykonanie – np. programistyczne (patrz [4, 74, 22]) lub wykorzystujace ˛ maszyny wirtualne (patrz [108]). Kluczowym problemem przy wstecznym wykonaniu sa˛ instrukcje destrukcyjne, które powoduja˛ niemożność odtworzenia poprzedniego stanu. Instrukcje te modyfikuja˛ stan pami˛eci lub rejestrów w ten sposób, że nie jest możliwe zastosowanie instrukcji odwrotnej pozwalajacej ˛ cofnać ˛ efekt wykonania pierwotnej instrukcji. Instrukcje, dla których istnieja˛ instrukcje niwelujace ˛ ich efekt, sa˛ nazywane instrukcjami odwracalnymi. Przykładem instrukcji destrukcyjnej jest funkcja mov, która nadpisuje adres lub rejestr pami˛eci. Instrukcja˛ odwracalna˛ jest instrukcja add, dla której instrukcja˛ odwrotna˛ jest instrukcja sub. Warto również zaznaczyć, że instrukcje architektury x86 moga˛ być destrukcyjne lub odwracalne w zależności od argumentów. Przykładem jest instrukcja xor, która dla wywołania xor %eax, %eax10 jest destrukcyjna, natomiast przy wywołaniu xor %ebx, %eax jest odwracalna11 . Wsteczne wykonanie w celu umożliwienia cofni˛ecia efektu działania instrukcji destrukcyjnej najcz˛eściej stosuje metod˛e utworzenia kopii nadpisywanych danych. W przypadku problemu odtwarzania zastosowanie wstecznego wykonania do wyznaczenia transformacji T (Qn , Sk ) jest niemożliwe. Wynika to z nast˛epujacych ˛ przyczyn: — wsteczne wykonanie w rozwiazaniach ˛ programistycznych polega na instrumentacji kodu, a w przypadku wykonania zaburzonego kodu dane zawarte w instrumentacji byłyby nieaktualne, — wsteczne wykonanie oparte o maszyn˛e wirtualna˛ wymaga zastosowania systemu gospodarza, który już nie podlegałby ochronie. Konieczne jest wi˛ec opracowanie nowej metody uzyskania transformacji T (Qn , Sk ). Przypadek zaburzenia kodu, który może być odtworzony poprzez wykonanie prawidłowego kodu został poprzednio przedstawiony na listingu 5.3. Natomiast przykład możliwości odtworzenia zasobów na podstawie stanu pami˛eci i rejestrów procesora w chwili zgłoszenia przerwania przedstawiony jest na listingu 5.4. Jest to szczególnie ciekawy przypadek, ponieważ odtworzenie wartości zapisanej w rejestrze %edx możliwe jest na dwa sposoby: poprzez ponowne wykonanie instrukcji z linii 2 lub skopiowanie zawartości %eax do rejestru %edx. 10 Instrukcja taka jest generowana przez kompilatory jako sposób wyzerowania wartości rejestru ze wzgl˛edu na krótszy wygenerowany kod binarny niż instrukcja mov $0,%eax. 11 Instrukcja˛ niwelujac ˛ a˛ jej działanie jest ona sama ze wzgl˛edu na właściwości działania xor. 134 Przykład nierozwiazywalnego ˛ zaburzenia kodu przedstawiony jest na listingu 5.5, gdzie w linii 2 stracona jest bezpowrotnie zawartość rejestru %eax potrzebna do wykonania prawidłowego kodu. Poniżej przedstawiony jest algorytm brudnych zasobów – podstawa˛ jego działania jest stwierdzenie, że możliwe jest przywrócenie stanu Si , o ile zasoby zapisane podczas wykonania zaburzonych instrukcji zostana˛ nadpisane podczas wykonania prawidłowego kodu, lub moga˛ być odtworzone na podstawie stanu pami˛eci w chwili zgłoszenia przerwania. Algorytm ten potrafi wyliczyć rozwiazania ˛ dla przykładu z listingu 5.3 oraz przykładu z listingu 5.4 (w wersji wykorzystujacej ˛ zmian˛e wartości licznika instrukcji). 1 2 3 4 mov %eax,%edx xor %eax,%edx | xor %eax,%eax > testb $0x2,(%edx) jne 0x1a Listing 5.4: Deasemblacja instrukcji zaburzonej i oryginalnej 1 2 3 mov 0x50(%eax),%eax mov 0x40194(%eax),%eax | mov 0x194(%eax),%eax > movzwl 0x260(%eax),%esi Listing 5.5: Deasemblacja instrukcji zaburzonej i oryginalnej Zaprojektowanie algorytmu rozwiazuj ˛ acego ˛ problem odtwarzalności wymaga bazy wiedzy o instrukcjach procesora. Potrzebne sa˛ informacje o tym, jakie zasoby sa˛ przez instrukcje modyfikowane. Obecna baza instrukcji została skonstruowana z instrukcji najcz˛eściej wyst˛epujacych ˛ w instrukcjach wykonanych po zaburzonej instrukcji12 . Składa si˛e ona z nast˛epujacych ˛ instrukcji: mov, lea, add, sub, xor, or, and, test, cmp. Algorytm brudnych zasobów przedstawiony jest na stronie 136. Zasada działania algorytmu jest nast˛epujaca: ˛ skanowany jest zbiór zaburzonych instrukcji w zakresie od pierwszej zaburzonej instrukcji do instrukcji, która zgłosiła przerwanie i wyznaczany jest zbiór zasobów, które zostały zapisane w wyniku wykonania tego kodu (linie 6-12) – zbiór ten nazwany jest zbiorem brudnych zasobów. W przypadku napotkania instrukcji, której działanie nie jest opisane w bazie instrukcji, działanie algorytmu jest przerywane (warunek w linii 7). Nast˛epnym etapem jest zbadanie, czy w przypadku wykonania niezaburzonych instrukcji, brudne zasoby nie zostana˛ nadpisane nowymi wartościami z wykorzystaniem niezabrudzonych zasobów (linie 15-20) – jeżeli tak, to taki zasób jest usuwany ze zbioru brudnych zasobów (linia 17). Skanowanie jest przeprowadzane tak długo jak analizowane sa˛ instrukcje dost˛epne w bazie instrukcji. 12 Zbiór instrukcji wyznaczono na podstawie zrzutów zaburzonego kodu dost˛epnych w dziennikach eksperymentów przeprowadzonych w 5.6.1. 135 Algorytm 5.1 Algorytm brudnych zasobów Input: beforeCode, faultCode, originalCode, failInstr Output: transform 1: if failInstr 6∈ faultCode then 2: return ∅; 3: end if 4: dirtyResources ← ∅, remainingResources ← ∅; 5: ptrInstr ← head(faultCode); 6: while ptrInstr ∈ faultCode do 7: if is_invalid(ptrInstr) then 8: return ∅; 9: end if 10: add(dirtyResources, written_resources(ptrInstr); 11: ptrInstr ← next(ptrInstr); 12: end while 13: remainingResources ← dirtyResources, 14: ptrInstr ← head(originalCode); 15: while ptrInstr ∈ originalCode ∧ is_valid(ptrInstr) do 16: if read_resources(ptrInstr) 6∈ dirtyResources then 17: remove(remainingResources, read_resources(ptrInstr); 18: end if 19: ptrInstr ← next(ptrInstr); 20: end while 21: if remainingResources == ∅ then return transform; 22: end if 23: ptrInstr ← tail(beforeCode); 24: while ptrInstr ∈ beforeCode ∧ is_valid(ptrInstr) do 25: if read_resources(ptrInstr) 6∈ dirtyResources then 26: remove(remainingResources, read_resources(ptrInstr); 27: add(transform, ptrInstr); 28: end if 29: if remainingResources == ∅ then return transform 30: end if 31: add(dirtyResources, written_resources(ptrInstr); 32: ptrInstr ← previous(ptrInstr); 33: end while 34: return ∅ 136 Jeżeli po zakończeniu tego etapu zbiór brudnych zasobów jest pusty, to rozwiazaniem ˛ problemu odtwarzania dla danego przypadku jest ustawienie wskaźnika instrukcji na poczatek ˛ niezaburzonego kodu – w wyniku jego wykonania wszystkie brudne zasoby zostana˛ nadpisane nowymi wartościami. Jeżeli zbiór brudnych zasobów nie jest pusty, to wykonywany jest ostatni etap polegajacy ˛ na zbadaniu instrukcji wykonywanych przed miejscem zaburzenia w analogiczny sposób, jak w poprzednim etapie z ta˛ różnica,˛ że licznik instrukcji jest „cofany”. Jeżeli w tym etapie uda si˛e osiagn ˛ ać ˛ pusty zbiór zasobów, to rozwiazaniem ˛ jest ustawienie licznika instrukcji na pierwsza˛ instrukcj˛e, od której prawidłowe wykonanie pozwoli nadpisać wszystkie brudne zasoby. Algorytm kończy si˛e niepowodzeniem, jeżeli nie uda si˛e oczyścić zbioru brudnych zasobów. Niestety możliwości zbadania skuteczności zaproponowanego algorytmu w praktyce sa˛ ograniczone z uwagi na fakt, że podstawowa implementacja wymaga deasemblacji kodu binarnego. Jest to utrudnione z poziomu jadra ˛ systemu operacyjnego z uwagi na brak bibliotek realizujacych ˛ taka˛ funkcj˛e w kodzie systemu operacyjnego GNU/Linux13 . W zwiazku ˛ z tym ograniczeniem przygotowane zostały dwa scenariusze sprawdzajace ˛ możliwości adaptacji zaproponowanej metody. Jeden z nich ma na celu sprawdzenie możliwości modyfikacji stanu zadania zgłaszajacego ˛ przerwanie. Drugi służy oszacowaniu liczby awarii, które potencjalnie moga˛ zostać obsłużone poprzez znalezienie rozwiazania ˛ problemu odtwarzania. Weryfikacja eksperymentalna W celu zbadania możliwości odtworzenia poprawnego stanu zadania w module naprawczym opisanym w sekcji 5.6.1 zaimplementowano heurystyk˛e polegajac ˛ a˛ na nast˛epujacym ˛ scenariuszu: jeżeli po wykonaniu procedury naprawczej zadanie ponownie zgłasza przerwanie (czyli instrukcja wywołujaca ˛ przerwanie nie jest pierwsza˛ zaburzona˛ instrukcja), ˛ to sprawdzane jest, czy w odległości 6 bajtów przed adresem zgłaszanej instrukcji wyst˛epuje kod instrukcji mov i w tym przypadku licznik instrukcji jest ustawiany na ten adres. Heurystyka ta polega na obserwacji, iż wiele przypadków nieobsłużonych przez moduły naprawcze z sekcji 5.6.1 jest podobna do przypadku przedstawionego na listingu 5.3, gdzie awaria jest zgłaszana w nast˛epnej instrukcji po załadowaniu danych spod niewłaściwego adresu pami˛eci. W wyniku przeprowadzenia eksperymentu (składajacego ˛ si˛e z 10 000 testów) identycznego z eksperymentem opisanym w sekcji 5.6.1 uzyskano 56 przypadków, gdzie przedstawiona heurystyka pozwoliła na zakończenie poprawnym wynikiem zadania zgłaszajacego ˛ przerwanie w wyniku zaburzenia pami˛eci. Dzi˛eki temu eksperymentowi zostało potwierdzone, że możliwe jest zwi˛ekszenie skuteczności modułu naprawczego poprzez zmian˛e wartości licznika instrukcji w procedurze naprawczej. 13 Istnieje inicjatywa zintegrowania deasemblera w http://www.phoronix.com/scan.php?page=news_item&px=MTA4MTI 137 kodzie jadra ˛ GNU/Linux – Oszacowanie potencjalnej skuteczności Oszacowanie liczby awarii, dla których istnieje rozwiazanie ˛ problemu odtwarzania zostało przeprowadzone poprzez implementacj˛e algorytmu brudnych zasobów operujacego ˛ na artefaktach eksperymentów opisanych w sekcji 5.6.1 dla eksperymentu „RM v.2 I”. Jeżeli w dziennikach eksperymentu istnieja˛ zrzuty zaburzonego i oryginalnego kodu, to podejmowana jest próba wyznaczenia transformacji T (Qn , Si ). Zaproponowany algorytm znalazł rozwiazanie ˛ problemu odtwarzania w 28% eksperymentów, które zakończyły si˛e awaria˛ pomimo przeprowadzenia próby naprawy metoda˛ pułapek procesora (NRD ), co pozwoliłoby na zwi˛ekszenie liczby prawidłowych wyników o około 3 p.p. (oznacza to zwi˛ekszenie wartości współczynnika Fr z 55% do 63%). Należy jednak założyć, że w cz˛eści przypadków znalezienie rozwiazania ˛ problemu odtwarzania nie zapobiegnie wystapieniu ˛ awarii (np. zaburzony kod został wykonany wi˛ecej niż raz i algorytm brudnych zasobów z tego powodu nie wyznaczył pełnego zbioru zasobów nadpisanych przez zaburzony kod). Dodatkowo warto zaznaczyć, że tylko w 2% przypadków algorytm brudnych zasobów wykrył zniszczenie zasobu uniemożliwiajace ˛ odtworzenie prawidłowego stanu. Dla 50% przypadków nie udało si˛e znaleźć rozwiazania ˛ z powodu wykonania zaburzonej instrukcji nieuwzgl˛ednionej w bazie instrukcji, a dla 10% przypadków niemożliwe było stwierdzenie, że wszystkie brudne zasoby zostana˛ nadpisane w trakcie wznowionego wykonania. Pozostałe przypadki niepowodzeń były zwiazane ˛ z wartościa˛ licznika instrukcji, która nie pozwalała na zastosowanie algorytmu (np. w wyniku wykonania zaburzonego kodu został wykonany skok w losowe miejsce pami˛eci i nie jest możliwe spekulowanie jaka sekwencja instrukcji została wykonana w wyniku zaburzenia). Wnioski Zdefiniowanie problemu odtwarzalności pozwoliło opracować oryginalny algorytm brudnych zasobów, który może istotnie zwi˛ekszyć skuteczność obsługi bł˛edów po stronie systemu operacyjnego, a także aplikacji użytkownika. Ograniczeniem przedstawionej implementacji jest stosunkowo niewielka baza instrukcji – otwiera to potencjalny obszar badań automatycznego wyznaczenia właściwości wszystkich instrukcji danej architektury ISA. Dodatkowym obszarem badań może być modyfikacja algorytmu brudnych zasobów o inspekcj˛e stanu stosu (jako potencjalnego miejsca przechowywania wartości rejestrów, które zostały nadpisane w rejestrach) oraz możliwość zastosowania instrukcji odwrotnych dla wykonanych instrukcji w celu odwrócenia efektów wykonania zaburzonych instrukcji. Efektywność algorytmu mogłaby być potencjalnie zwi˛ekszona dzi˛eki meta-danym dotyczacym ˛ kodu, które moga˛ być dost˛epne na poziomie kompilatora – np. czy wynik wykonania funkcji zależy wyłacznie ˛ od parametrów wywołania. 138 5.6.3. Ochrona stosu W podrozdziale 5.3 przedstawiono główne trudności w projektowaniu mechanizmów ochrony danych przechowywanych na stosie, czyli duże zróżnicowanie typów danych oraz ich duża zmienność w trakcie wykonania programów. Projektowanie mechanizmów zwi˛ekszania ochrony stosu wymaga zapewnienia możliwości odtworzenia prawidłowych danych oraz detekcji wystapienia ˛ bł˛edu. Należy również uwzgl˛ednić różne typy danych przechowywanych na stosie. Poniżej zaproponowana jest metoda ochrony wskaźników powrotu z funkcji przechowywanych na stosie pozwalajaca ˛ na unikni˛ecie awarii. Architektura Zaproponowane rozwiazanie ˛ polega na zmodyfikowaniu kodu wywoływanych funkcji o dodatkowe instrukcje w prologu oraz epilogu funkcji. W prologu znalazłby si˛e kod umieszczajacy ˛ na stosie dodatkowa˛ kopi˛e adresu powrotnego z funkcji otoczona˛ stałymi markerami oraz rezerwujacy ˛ miejsce na wartość rejestru licznika instrukcji. Natomiast dodatkowe instrukcje w epilogu funkcji umieszczałyby przed skokiem pod adres powrotu z instrukcji na stosie aktualna˛ wartość rejestru licznika instrukcji. Na rysunku 5.6 przedstawiono schemat zawartości ramki stosu po wykonaniu prologu oraz epilogu funkcji. W przypadku przekłamania adresu powrotnego z funkcji (pozycja oznaczona liczba˛ 1 na schemacie) wykonywany jest skok pod nieprawidłowy adres. W przypadku, gdy adres ten powoduje niedozwolony dost˛ep do pami˛eci, sterowanie jest przekazane do analogicznego modułu, jak ten opisany w sekcji 5.6.1. Moduł dokonuje analizy stosu przerwanego zadania i na podstawie wartości umieszczonych na stosie podejmowana jest decyzja o podj˛eciu próby naprawy. Zawartość stosu sprawdzana jest według nast˛epujacych ˛ kryteriów: — obecność markerów umieszczonych na pozycjach 3 i 5, — zawartość pozycji 2 jest różna od 0, — wartości na pozycjach 1 i 4 różnia˛ si˛e od siebie. Jeżeli wszystkie powyższe kryteria sa˛ spełnione, to podejmowana jest próba naprawy polegajaca ˛ na skopiowaniu wartości przechowywanej w pozycji 4 na pozycj˛e 1 oraz ustawienie wartości rejestru instrukcji na wartość przechowywana˛ w pozycji 2. W ten sposób nast˛epuje odtworzenie prawidłowej wartości wskaźnika powrotu ze stosu. Implementacja opisanego schematu wymaga wsparcia ze strony kompilatora w celu wygenerowania dodatkowych instrukcji prologu i epilogu funkcji oraz odpowiednim rozmieszczeniu pozostałych wartości na stosie zwiazanych ˛ normalna˛ praca˛ systemu. Niemniej wiele kompilatorów posiada funkcj˛e generowania kodu dla mechanizmu stack protector14 , który podobnie jak zaproponowane rozwiazanie ˛ wymaga dodatkowego kodu w prologu i epilogu 14 http://msdn.microsoft.com/en-us/library/8dbf701c(VS.80).aspx 139 Stackgpointer 1 Returngaddress 1 Returngaddress 2 0x00000000 2 Lastginstructiongpointer 3 Constantgmarker 3 Constantgmarker 4 Returngaddressg(copy) 4 Returngaddressg(copy) 5 Constantgmarker 5 Constantgmarker Stackgpointer a)gStangstosugpogwykonaniugprologugfunkcji b)gStangstosugpogwykonaniugepilogugfunkcji Rysunek 5.6: Schemat ramki stosu z ochrona˛ wskaźnika powrotu z funkcji funkcji oraz wymaga alokacji dodatkowej pami˛eci na stosie przed wykonaniem właściwego kodu funkcji. Eksperymentalna weryfikacja W celu weryfikacji działania opracowanej metody opracowany został moduł realizujacy ˛ opisana˛ procedur˛e naprawcza˛ oraz przygotowany został kod programu, który realizuje dla wybranej funkcji opracowany sposób odłożenia dodatkowych wartości na stosie. Dodatkowo opracowana funkcja wprowadza zaburzenie do adresu powrotu z funkcji w celu weryfikacji skuteczności procedury naprawczej. Kod opracowanej funkcji zamieszczony jest na listingu 5.6. W liniach 4-8 realizowany jest epilog funkcji według opisanych założeń. W liniach 9-10 nast˛epuje nadpisanie prawidłowej wartości adresu powrotu z funkcji. Natomiast w liniach 11-14 realizowany jest epilog funkcji. 1 2 3 void test() { asm( "push $0x0" "push $0xfefefefe" "mov 0x8(%ebp),%eax" "push $eax" "push $0xfefefefe" "mov $0x42,%eax" "mov %eax,0x4(%ebp)" "add $16,%esp" "call get_eip" "get_eip:" "pop %eax" 4 5 6 7 8 9 10 11 12 13 14 ); 15 16 } Listing 5.6: Implementacja kodu funkcji weryfikujacej ˛ skuteczność mechanizmu ochrony wskaźnika powrotu z instrukcji Weryfikacja działania została przeprowadzona poprzez dwukrotne uruchomienie programu wywołujacego ˛ funkcj˛e przedstawiona˛ na listingu 5.6 – bez zastosowania modułu naprawczego, 140 co spowodowało zakończenie działania programu z komunikatem „Segfault”. Natomiast przy drugim uruchomieniu aplikacji w systemie załadowany był moduł naprawczy, dzi˛eki czemu aplikacja wykonana została bez zgłoszenia awarii. Wnioski Zaproponowana metoda służy ochronie wskaźnika adresu powrotu z funkcji. Jej architektura jest zbliżona do mechanizmu stack protector dost˛epnego we współczesnych kompilatorach. Podobne rozwiazanie ˛ zostało zaprezentowane w [35], które różni si˛e nast˛epujaco ˛ od przedstawionego rozwiazania: ˛ na stosie wskaźnik powrotu instrukcji jest odkładany trzykrotnie, a wybranie właściwego adresu powrotu odbywa si˛e poprzez głosowanie. Rozwiazanie ˛ to może być skuteczniejsze szczególnie w przypadku przekłamań niskich bitów w adresie skoku (ponieważ takie przekłamanie może nie spowodować zgłoszenia przerwania), jednak rozwiazanie ˛ zaproponowane w niniejszej rozprawie wykorzystuje możliwość inspekcji stanu zadania w momencie pojawienia si˛e przerwania, co otwiera potencjalne nowe obszary badań. W szczególności ciekawym rozszerzeniem obecnego rozwiazania ˛ może być wzbogacanie wykorzystywanych struktur danych o redundantne informacje, które sa˛ wykorzystywane jedynie w momencie wystapienia ˛ przerwania. W takim scenariuszu narzut czasowy jest zwiazany ˛ wyłacznie ˛ z wyliczeniem dodatkowych danych służacych ˛ zwi˛ekszeniu niezawodności, natomiast ich wykorzystanie odbywa si˛e tylko w momencie wykrycia nieprawidłowości. Oba rozwiazania ˛ stanowia˛ interesujace ˛ podejścia, które należy porównać pod katem ˛ narzutu czasowego oraz skuteczności, jednak przeprowadzenie takiego eksperymentu wymaga opracowania zmian w kompilatorach i stanowi to obszar dalszych badań planowanych przez autora. Warto zaznaczyć, że inne typy danych przechowywanych na stosie wymagaja˛ projektowania innego typu mechanizmów zwi˛ekszajacych ˛ niezawodność. Przykładowo w przypadku odkładania na stos tymczasowych wartości rejestrów możliwe jest umieszczanie na stosie kilku kopii tych samych danych w celu późniejszego przeprowadzenia głosowania, jednak dla parametrów wywołań funkcji takie działanie jest już nieakceptowalne. Wynika to z faktu, iż parametr wywołania funkcji może być swobodnie modyfikowany przez wywoływana˛ funkcj˛e – musiałaby ona podczas zapisu aktualizować wszystkie kopie zapisywanego parametru. Oznacza to konieczność wymuszenia spójnego zachowania we wszystkich funkcjach w odróżnieniu od zaproponowanych mechanizmów, które moga˛ być zastosowane tylko w wybranych procedurach bez zerwania binarnej kompatybilności z pozostałymi procedurami. 5.6.4. Mechanizmy ochrony danych W 5.3 zaznaczono, że mechanizmy ochrony danych najcz˛eściej stosowane sa˛ do danych zewn˛etrznych, które zostały przekazane do systemu operacyjnego – ich weryfikacja 141 przeprowadzana jest na podstawie wyliczania sum kontrolnych. Oczywistym rozszerzeniem byłoby wzbogacenie struktur danych wyst˛epujacych ˛ w jadrze ˛ systemu operacyjnego o dodatkowe pola pozwalajace ˛ na weryfikacj˛e spójności danych. Niemniej rozwiazanie ˛ takie rodzi nast˛epujace ˛ pytania: czy konieczne jest obj˛ecie wszystkich struktur danych mechanizmem weryfikacji i czy narzut czasowy zwiazany ˛ z tym zastosowaniem b˛edzie akceptowalny. Dodatkowa˛ trudnościa˛ jest adaptacja takiego podejścia do tak dużej bazy źródeł jak jadro ˛ systemu GNU/Linux. W literaturze można znaleźć badania, które w przyszłości moga˛ pomóc rozwiazać ˛ wymienione problemy. Według autora szczególnie interesujace ˛ prace w tej dziedzinie to [15] oraz [17]. W [15] zaprezentowana została technika polegajaca ˛ na wykorzystaniu programowania aspektowego do zwi˛ekszenia opracowanego w j˛ezyku C++. niezawodności wbudowanego systemu operacyjnego Programowanie aspektowe jest to implementacja idei separacji zadań realizowanych przez kod poprzez podzielenie programu na niezwiazane ˛ ze soba˛ funkcjonalnie moduły. Przykładowo pewien program może zostać wzbogacony o funkcj˛e pomiaru czasu wykonania wskazanych funkcji poprzez zdefiniowanie aspektu15 , który na etapie kompilacji jest wplatany (weaved) w wynikowy kod programu. Podstawa˛ działania mechanizmu opisanego w [15] jest wzbogacenie klas j˛ezyka C++ o dodatkowe pola zawierajace ˛ kody korekcyjne dla pól oryginalnie zdefiniowanych w klasach. Dzi˛eki zastosowaniu aspektów dost˛ep do danych jest sprawdzany przed wywołaniem każdej z metod publicznych obiektu, natomiast pola zawierajace ˛ kody korekcyjne sa˛ aktualizowane po zakończeniu wykonania metody. Rozwiazanie ˛ to jest bardzo perspektywiczne z uwagi na możliwość wzbogacania tylko cz˛eści struktur danych o funkcje niezawodnościowe stosownie do potrzeb i narzutu na czas wykonania. Natomiast w [17] zaprezentowano niestandardowy mechanizm służacy ˛ do ochrony przed bł˛edami programistycznymi polegajacy ˛ na śledzeniu przez kompilator wskaźników do danych (zarówno danych składowanych na stosie oraz danych alokowanych). Z każdym wykrytym wskaźnikiem p powiazane ˛ sa˛ nast˛epujace ˛ informacje: a – adres przydzielonej pami˛eci; s – rozmiar przydzielonego obszaru. Nast˛epnie wszelkie operacje dost˛epu do danych z użyciem p powoduja˛ wygenerowanie dodatkowego kodu wykonujacego ˛ sprawdzenie, czy dost˛ep do danych dotyczy pami˛eci z zakresu adresów pomi˛edzy a i a + s. Jeżeli dost˛ep odbywa si˛e w wyznaczonym zakresie, to jest to prawidłowy dost˛ep do danych, natomiast w przeciwnym wypadku wykrywany jest bład ˛ dost˛epu do pami˛eci. Zaproponowana przez autorów metoda obsługi takiej sytuacji polega na porzuceniu operacji dost˛epu do wskazanej pami˛eci i wprowadzeniu dla wskaźnika p wirtualnej przestrzeni danych, gdzie nieprawidłowy dost˛ep do pami˛eci jest przekierowany do pami˛eci przydzielonej specjalnie dla wskaźnika 15 Aspekt jest to kombinacja punktu przeci˛ecia (ang. pointcut) oraz rady (ang. advice). Punkt przeci˛ecia definiuje okoliczności, w których ma być wykonana rada, czyli dodatkowa czynność do wykonania przez program. 142 p. Mechanizm ten powoduje, że odczytanie pami˛eci spod nieprawidłowego adresu nie spowoduje odczytania losowej zawartości pami˛eci (wirtualna pami˛eć jest inicjalizowana wartościa˛ 0), a zapis nie zaburzy innych danych przechowywanych w systemie. Mechanizm ten jest szczególnie interesujacy, ˛ ponieważ pozwala na unikni˛ecie awarii poprzez stworzenie dla nieprawidłowego dost˛epu do pami˛eci środowiska typu sandbox. Dodatkowym atutem tego rozwiazania ˛ jest automatyczne wykrywanie danych, które moga˛ być obj˛ete ochrona.˛ Rozwiazanie ˛ to było projektowane z myśla˛ o bł˛edach programistycznych, jednak potencjalnie może ono również wpłynać ˛ na popraw˛e niezawodności systemu w przypadku bł˛edów sprz˛etu. Przykładowym scenariuszem byłaby obsługa przekłamania w danych zawierajacych ˛ adresy kolejnych elementów listowej struktury danych. Zastosowanie opisanego mechanizmu zapobiegłoby odwołaniu do nieprawidłowej pami˛eci, kosztem braku dost˛epu do elementów listy znajdujacych ˛ si˛e za zaburzonym w˛ezłem – unikni˛eto by awarii, a mechanizmy wyższych warstw mogłyby podjać ˛ decyzj˛e o ewentualnym zastosowaniu innych technik odtwarzania. Opisane mechanizmy ochrony danych stanowia˛ interesujacy ˛ nurt w dziedzinie badań nad niezawodnościa.˛ Według autora kierunek pozwalajacy ˛ na automatyczne wzbogacanie danych o funkcje niezawodnościowe i zmniejszanie prawdopodobieństwa awarii systemu stanowi podstaw˛e skuteczności mechanizmów wyższego poziomu pozwalajacych ˛ na tolerowanie bł˛ednych danych. 5.7. Zastosowanie QEFI do optymalizacji niezawodności Platforma QEFI przedstawiona w rozdziale 3 umożliwia optymalizacj˛e mechanizmów zwi˛ekszania niezawodności. Wprowadzanie mechanizmów tego typu wia˛że si˛e z narzutem na czas wykonania oraz pami˛eć. Dodatkowo każdy z mechanizmów może charakteryzować si˛e innym poziomem skuteczności przy obsłudze bł˛edów. Zastosowanie QEFI pozwala na przeprowadzenie badań umożliwiajacych ˛ określić parametry tych mechanizmów w wybranych scenariuszach. W 5.6.1 przedstawiono eksperymenty, które pozwoliły zaproponowanego przez autora mechanizmu obsługi przerwań. ocenić skuteczność O ile w przypadku tego mechanizmu koszt narzutu na czas wykonania zwiazany ˛ jest jedynie z podj˛eciem działań naprawczych, a koszt pami˛eci to przede wszystkim zapasowy obraz kodu jadra ˛ systemu operacyjnego, to w przypadku próby zastosowań mechanizmów opisanych w 5.6.3 i 5.6.4 trudno jest ocenić narzut tych mechanizmów bez przeprowadzenia eksperymentów. W tych przypadkach szczególnie skuteczny może okazać si˛e mechanizm nieinwazyjnego śledzenia wykonania opisany w 3.4.3, dzi˛eki któremu możliwe jest wyznaczenie dokładnej liczby wykonań wskazanego kodu i na tej podstawie oszacowanie narzutu badanego mechanizmu. Dodatkowo dzi˛eki zastosowaniu QEFI możliwe jest badanie w sposób automatyczny również 143 wpływu innych parametrów na niezawodność oprogramowania – przykładowo: flagi kompilacji (np. poziom optymalizacji kodu wykonywalnego), czy dost˛epna ilość wolnej pami˛eci (co może mieć wpływ na sposób działania mechanizmów alokacji). QEFI pozwala na ewaluacj˛e nie tylko mechanizmów ukierunkowanych na kod, stos, czy dane systemu operacyjnego, ale również na poprawność działania sterowników w obliczu wystapienia ˛ bł˛edów w urzadzeniach ˛ wejścia/wyjścia. Jest to szczególnie praktyczne zastosowanie QEFI, ponieważ badanie tego typu oprogramowania jest trudne w zwiazku ˛ z koniecznościa˛ dysponowania testowanym urzadzeniem, ˛ w którym możliwe jest symulowanie bł˛edów lub jego emulowanym odpowiednikiem. W przypadku istnienia emulowanych odpowiedników opracowywane sa˛ rozwiazania ˛ pozwalajace ˛ na implementacj˛e testów jednostkowych z wykorzystaniem QEMU16 – dzi˛eki zastosowaniu mechanizmów wstrzykiwania bł˛edów w QEFI możliwe byłoby wzbogacenie tego typu testów o weryfikacje działania sterowników w przypadku anomalii (tak jak zostało to przedstawione w 4.5.1). 5.8. Podsumowanie W rozdziale przedstawiono przekrój rozwiazań ˛ służacych ˛ zwi˛ekszaniu niezawodności. Zaproponowane zostały autorskie mechanizmy: metoda obsługi przerwań, algorytm brudnych zasobów oraz metoda ochrony stosu. Dodatkowo przeprowadzono dyskusj˛e nad zastosowaniem QEFI do optymalizacji niezawodności. Skuteczność opracowanej oryginalnej metody obsługi pułapek procesora (szerzej w 5.6.1) zweryfikowano z zastosowaniem metodologi eksperymentów opisanej w rozdziale 3. Dzi˛eki jej implementacji możliwe było zwi˛ekszenie liczby prawidłowych wyników testowanego systemu o około 15 p.p.. Na podstawie dalszej analizy sytuacji wyjatkowych ˛ zdefiniowany został problem odtwarzalności i przedstawiony został algorytm brudnych zasobów jako jego rozwiazanie. ˛ Symulacja działania algorytmu pozwoliła na oszacowanie jego potencjalnej skuteczności – algorytm znalazł rozwiazanie ˛ problemu odtwarzalności dla około 7% sytuacji awaryjnych nieobsłużonych metoda˛ obsługi przerwań, co potencjalnie pozwoliłoby zwi˛ekszyć udział prawidłowych wyników testów o około 3 p.p.. Warto zaznaczyć, że skuteczność algorytmu może być zwi˛ekszona poprzez wzbogacenie bazy instrukcji oraz rozwini˛ecie technik odtwarzania danych ze stosu oraz z zastosowaniem odwrotnych operacji arytmetycznych. Przedstawiona technika jest odmiana˛ technik backward recovery, gdzie nast˛epuje próba odwrócenia skutków niepożadanych ˛ zmian w systemie b˛edacych ˛ wynikiem zaburzeń. Zastosowanie opracowanej metody ma na celu unikni˛ecie awarii, jednak wynik uzyskany po wykonaniu naprawionego kodu powinien być opatrzony informacja˛ o potencjalnym zaburzeniu, 16 http://people.igalia.com/berto/files/qemu-linuxcon-slides.pdf 144 a także mechanizmy niezawodnościowe wyższego poziomu powinny zapewnić tolerowanie potencjalnie wygenerowanych nieprawidłowych danych. W 5.6.3 zaprezentowano metod˛e ochrony stosu poprzez umieszczanie dodatkowych danych w nieaktywnej cz˛eści stosu (za wskaźnikiem wierzchołka stosu), które sa˛ wykorzystywane w sytuacji zgłoszenia awarii spowodowanej przekłamaniem adresu powrotu z instrukcji. Natomiast w 5.6.4 opisano dwie interesujace ˛ metody zwi˛ekszania niezawodności obsługi danych znane z literatury. Celem tych przykładów była ilustracja potencjalnych zysków wynikajacych ˛ z zaangażowania kompilatora w projektowanie mechanizmów zwi˛ekszania niezawodności. W ostatniej cz˛eści rozdziału przedstawiono zastosowanie QEFI do optymalizacji niezawodności poprzez możliwość badania skuteczności oraz kosztów poszczególnych mechanizmów. 145 6. Podsumowanie W rozprawie przedstawiono oryginalna˛ metodyk˛e oceny niezawodności systemu komputerowego z zastosowaniem emulacji wraz z implementacja˛ specjalistycznego narz˛edzia QEFI. Teza oraz cel rozprawy sformułowane sa˛ w rozdziale 1. Dzi˛eki opracowanej metodyce stworzono możliwość oceny niezawodności oprogramowania systemów operacyjnych, która jak przedstawiono w 1.1, według autora jest niedostatecznie opisana w literaturze. QEFI może być zastosowane do optymalizacji mechanizmów detekcji i obsługi (tolerowania) bł˛edów. W rozdziale 2 przedstawiono model rozważanego systemu komputerowego i oprogramowania, przeglad ˛ literatury dotyczacy ˛ dziedziny badania niezawodności oraz wprowadzono miary wykorzystywane w dalszej cz˛eści rozprawy. Poniżej zestawiono najważniejsze osiagni˛ ˛ ecia autora: Opracowanie metodyki symulacji bł˛edów z zastosowaniem emulacji Na podstawie analizy dost˛epnych mechanizmów emulacji systemów komputerowych (patrz 3.2) i potencjalnych zysków, wynikajacych ˛ z ich użycia (patrz 3.3), opracowana została oryginalna metodyka przeprowadzania eksperymentów (patrz 3.4.5) oraz szereg algorytmów umożliwiajacych ˛ jej realizacj˛e. Metodyka została zaimplementowana w postaci platformy QEFI wykorzystujacej ˛ emulator systemu komputerowego QEMU (patrz 3.4.6). Zaproponowana metodyka umożliwia istotne udoskonalenia wzgl˛edem rozwiazań ˛ znanych z literatury: możliwość badania niezawodności oprogramowania systemów operacyjnych oraz możliwość zastosowania nowych modeli bł˛edów. Istotna˛ funkcja˛ opracowanego rozwiazania ˛ jest funkcja nieinwazyjnego śledzenia emulowanego systemu (patrz 3.4.3). Metodyka została opracowana uwzgl˛edniajac ˛ możliwość rozpraszania, co znaczaco ˛ skróciło czas przeprowadzania eksperymentów. Opracowanie scenariuszy testowych do badania efektów bł˛edów w systemach operacyjnych Opracowane zostały oryginalne scenariusze testowe wykorzystane do oceny niezawodności systemów operacyjnych w szeregu eksperymentów przeprowadzonych z użyciem QEFI. Dzi˛eki opracowanej metodyce możliwe było przeprowadzenie eksperymentów pozwalajacych ˛ na porównanie wrażliwości na bł˛edy pami˛eci wielu architektur sprz˛etowych na poziomie ISA (patrz 4.3), w których wykazano, że niektóre architektury w sposób naturalny sa˛ mniej podatne na bł˛edy przekłamań pami˛eci. Możliwe było również porównanie różnych 147 systemów operacyjnych (patrz 4.4), w którym stwierdzono różna˛ podatność na bł˛edy i inny poziom szczegółowości zgłaszanych komunikatów dla każdego z systemów. Przeprowadzenie porównania architektur sprz˛etowych oraz systemów operacyjnych, było możliwe dzi˛eki opracowaniu symulowania bł˛edów na poziomie emulatora, co pozwoliło na unikni˛ecie modyfikacji badanego oprogramowania. Dodatkowo mechanizmy zaprojektowane w ramach metodyki pozwoliły na zaburzanie danych przesyłanych z emulowanych urzadzeń ˛ (patrz 4.5.1), a także wstrzykiwanie bł˛edów w różne typy danych systemu operacyjnego (patrz 4.5.2, 4.5.3): kod, stos, dane alokowane, dane tylko do odczytu, dane statyczne. Dzi˛eki zastosowaniu profilowania zwi˛ekszono efektywność przeprowadzonych testów, zidentyfikowano krytyczne komponenty, zbadano opóźnienie awarii bł˛edów w kodzie systemu operacyjnego oraz wyznaczono wartości współczynnika naturalnej odporności na bł˛edy. Opracowanie oryginalnych mechanizmów zwi˛ekszania niezawodności Na podstawie wyników uzyskanych w przeprowadzonych eksperymentach opracowane zostały oryginalne mechanizmy zwi˛ekszania niezawodności: metoda obsługi przerwań (patrz 5.6.1) oraz algorytm brudnych zasobów (patrz 5.6.2), który stanowi rozwiazanie ˛ zdefiniowanego problemu odtwarzalności. Metoda obsługi przerwań została zweryfikowana wykorzystujac ˛ QEFI, natomiast algorytm brudnych zasobów został zweryfikowany poprzez symulacj˛e (z uwagi na trudności w implementacji deasemblera w jadrze ˛ systemu operacyjnego). W przeprowadzonym eksperymencie zaproponowane mechanizmy moga˛ zwi˛ekszyć udział prawidłowych wyników o około 15 p.p. (metoda obsługi przerwań) oraz potencjalnie o dodatkowe 3 p.p. (algorytm brudnych zasobów). Opracowana został również metoda ochrony stosu (patrz 5.6.3) poprzez umieszczanie dodatkowych danych w nieaktywnej cz˛eści stosu. Opracowane mechanizmy wymagaja˛ minimalnych zmian w jadrze ˛ systemu operacyjnego GNU/Linux i wykorzystuja˛ mechanizm kprobes do wzbogacenia systemu o dodatkowe funkcje obsługi bł˛edów. Całość przeprowadzonych badań służy możliwości wykorzystania symulacji bł˛edów w środowisku emulatora w celu zwi˛ekszania niezawodności urzadzeń ˛ konsumenckich. Szczególnie istotnym zagadnieniem jest opracowanie scenariuszy testowych adekwatnych do przyszłych zastosowań badanego oprogramowania. Autor przedstawił możliwie szeroki aspekt wykorzystania QEFI od porównywania różnych konfiguracji systemów komputerowych po szczegółowa˛ analiz˛e wybranego systemu komputerowego. Przyj˛ete podejście pozwoliło na opracowanie mechanizmów zwi˛ekszania niezawodności dedykowanych badanej platformie. QEFI umożliwiło również weryfikacj˛e opracowanych mechanizmów oraz ocen˛e ich skuteczności – oznacza to, że QEFI może być zastosowane do optymalizacji mechanizmów niezawodności, gdy ich zastosowanie wia˛że si˛e z kosztem czasu wykonania lub dodatkowej pami˛eci. Przeprowadzone badania przedstawiaja˛ użyteczność emulacji 148 systemu komputerowych w badaniu niezawodności oprogramowania systemów operacyjnych, co stanowi dowód tezy sformułowanej w 1.3. 6.1. Spostrzeżenia i wnioski QEFI jest elastycznym środowiskiem symulacji bł˛edów. Dzi˛eki zastosowaniu emulacji możliwe jest badanie efektów nowych modeli bł˛edów oraz porównanie podatności na bł˛edy różnych konfiguracji systemów komputerowych, co pozwoliło na uzupełnienie stanu wiedzy o nowe fakty podsumowane poniżej. Badania nad różnymi architekturami sprz˛etowymi pozwoliły określić, że architektury różnia˛ si˛e podatnościa˛ na bł˛edy. Niemniej dla wszystkich architektur istnieja˛ rejony pami˛eci o wyższym stopniu podatności na przekłamania pami˛eci. Oznacza to, że niezawodność systemu może być zwi˛ekszona poprzez zastosowanie pami˛eci ECC tylko dla cz˛eści dost˛epnej pami˛eci. Niemniej oprogramowanie systemu operacyjnego w pierwszej kolejności powinno umieszczać w tych rejonach pami˛eci dane wrażliwe – w szczególności kod systemu operacyjnego, stos, czy dane krytyczne aplikacji użytkownika. Porównanie systemów operacyjnych pozwoliło wykryć, że systemy operacyjne działajace ˛ na tej samej platformie sprz˛etowej cechuje inny poziom manifestacji bł˛edów oraz szczegółowości komunikatów. W przypadku systemu Minix zebranie informacji o skuteczności mechanizmów zwi˛ekszania niezawodności wbudowanych w ten system było niemożliwe z uwagi na trudności konfiguracyjne (brak wypisywania na konsol˛e operatora informacji jadra ˛ systemu o podj˛etych działaniach naprawczych – np. restart usług systemu). System oparty na jadrze ˛ kFreeBSD okazał si˛e najbardziej podatny na bł˛edy, jednak poziom szczegółowości komunikatów był najmniejszy – oznacza to, że jakość implementacji mechanizmów obsługi sytuacji wyjatkowych ˛ w systemie operacyjnym potrafi si˛e zasadniczo różnić. Eksperymenty ukierunkowane na zaburzanie pracy działania urzadzeń ˛ wejścia/wyjścia na różnych poziomach abstrakcji stanowia˛ ilustracj˛e elastyczności QEFI. Pozwoliły określić poziom podatności na bł˛edy różnych scenariuszy wykorzystywania urzadzeń. ˛ Istotne cechy QEFI wzgl˛edem rozwiazań ˛ znanych z literatury to brak konieczności modyfikacji badanego oprogramowania oraz możliwość symulowania bł˛edów zwiazanych ˛ ze zgłaszaniem przerwań przez urzadzenia. ˛ Metoda nieinwazyjnego śledzenia zaimplementowana w QEFI umożliwiła profilowanie wykonywanego oprogramowania – dzi˛eki temu opracowane zostały eksperymenty zaburzania wyłacznie ˛ wykonywanego kodu, danych przechowywanych na stosie oraz danych alokowanych w systemie operacyjnym. Zastosowanie tej techniki skutkowało zwi˛ekszeniem efektywności przeprowadzanych eksperymentów. Badania pozwoliły stwierdzić, że najbardziej podatny na bł˛edy jest kod oprogramowania systemu operacyjnego, a 31-42% symulowanych bł˛edów nie 149 spowodowało manifestacji pomimo aktywacji bł˛edu. Niemniej poziom manifestacji bł˛edów jest specyficzny dla każdego z badanych scenariuszy testowych. Dodatkowo stwierdzono, że najcz˛eściej zgłaszanym komunikatem na skutek symulacji bł˛edów jest informacja o awarii wywołanej nieprawidłowym dost˛epem do pami˛eci, a także przy symulowaniu bł˛edów w przestrzeni kodu awarie zgłaszane sa˛ już po jednokrotnym wykonaniu zaburzonych instrukcji. Na podstawie zaobserwowanych faktów opracowane zostały mechanizmy zwi˛ekszania niezawodności: okresowa weryfikacja spójności kodu systemu operacyjnego, służaca ˛ detekcji bł˛edów przed ich aktywowaniem, metoda obsługi przerwań wraz z algorytmem brudnych zasobów oraz metoda ochrony wskaźników powrotu z funkcji przechowywanych na stosie. Zastosowanie mechanizmów opisanych w rozprawie pozwala na zwi˛ekszenie niezawodności systemu bez zwi˛ekszania kosztu sprz˛etu. Metoda obsługi przerwań wykorzystuje fakt cz˛estego wyst˛epowania awarii nieprawidłowego dost˛epu do pami˛eci do weryfikacji spójności kodu generujacego ˛ przerwanie oraz podj˛ecia procedur naprawczych: rekonstrukcja zaburzonego kodu oraz ewentualne dodatkowe działania – np. wyznaczenie przez algorytm brudnych zasobów modyfikacji stanu zadania. Pewnym problemem implementacyjnym algorytmu brudnych zasobów jest brak deassemblera w przestrzeni jadra ˛ systemu operacyjnego (przeprowadzono symulacyjna˛ weryfikacj˛e efektywności jego działania), niemniej prace nad tym rozwiazaniem ˛ sa˛ już prowadzone. Warto zaznaczyć, że w przeprowadzonych badaniach nie był uwzgl˛edniony kod ładowanych modułów (patrz 5.6.1), a obj˛ecie go ochrona˛ pozwoliłoby na zwi˛ekszenie efektywności przedstawionych mechanizmów. Dodatkowo sprawność algorytmu brudnych zasobów może być zwi˛ekszona przez rozszerzenie bazy instrukcji oraz opracowywanie nowych mechanizmów unieważniania zmian b˛edacych ˛ wynikiem działania zaburzonego kodu (patrz 5.6.2). Mechanizm ochrony stosu polega na umieszczaniu w nieaktywnej cz˛eści stosu dodatkowych danych umożliwiajacych ˛ rekonstrukcj˛e poprawnej wartości wskaźników powrotów z funkcji w przypadku ich zaburzeń (patrz 5.6.3). Niemniej wykorzystanie tego mechanizmu na szeroka˛ skal˛e wymaga wsparcia ze strony kompilatora w celu wygenerowania odpowiedniego kodu. Szczególnie interesujac ˛ a˛ cecha˛ mechanizmów projektowanych dla jadra ˛ systemu operacyjnego jest możliwość stosunkowo łatwego przeniesienia ich na grunt aplikacji użytkowania. Przykładowo zarysowanie metody obsługi przerwań w aplikacji użytkownika wymaga jedynie opracowania metody dost˛epu do referencyjnego obrazu kodu. 6.2. Zastosowania Opracowana metodyka przeprowadzania eksperymentów oceny niezawodności może stanowić cenne narz˛edzie dla projektantów systemów operacyjnych dzi˛eki możliwości 150 wstrzykiwania bł˛edów zarówno w komponenty wewn˛etrzne systemu operacyjnego, jak i zewn˛etrzne urzadzenia. ˛ Techniki zwi˛ekszania niezawodności przygotowane w niniejszej rozprawie moga˛ znaleźć zastosowanie w nowoczesnych urzadzeniach ˛ konsumenckich i specjalistycznych, zwi˛ekszajac ˛ ich niezawodność oraz dostarczajac ˛ informacji o stanie urzadzenia ˛ poprzez prób˛e wykrycia źródła bł˛edu. W szczególności techniki te zmniejszaja˛ prawdopodobieństwo wystapienia ˛ awarii, co może być kluczowym aspektem w pewnych zastosowaniach, gdzie koszt uzyskania nieprawidłowego wyniku wraz z informacja˛ o przeprowadzeniu procedury naprawczej w trakcie jego obliczania jest mniejszy niż awaria skutkujaca ˛ koniecznościa˛ ponownego uruchomienia systemu. 6.3. Kierunki dalszych badań Zaprezentowana metodyka oceny niezawodności może być rozszerzona o nowe modele bł˛edów w celu gł˛ebszej analizy wpływu bł˛edów na działanie systemu operacyjnego. Interesujacym ˛ zagadnieniem jest również zbadanie efektów bł˛edów w zależności od przeznaczenia systemu komputerowego (np. serwer plików, serwer WWW, stacja robocza, telefon komórkowy, terminal POS), a także zwi˛ekszenie ziarnistości badania efektów bł˛edów o informacje o podatności na bł˛edy poszczególnych modułów funkcjonalnych systemu (sterowniki, systemy plików, planner, itd.). Mechanizmy zwi˛ekszania niezawodności przedstawione w rozdziale 5 moga˛ zostać przeniesione na grunt aplikacji użytkownika, co może być rozwiazaniem ˛ znaczaco ˛ redukujacym ˛ wyst˛epowanie awarii. Dodatkowym zagadnieniem jest rozszerzenie algorytmu brudnych zasobów o mechanizmy, które pozwoliły na zwi˛ekszenie skuteczności przy obliczaniu rozwiazań ˛ problemu odtwarzalności. Według autora bardzo obiecujacym ˛ kierunkiem dalszych badań jest wykorzystanie kompilatorów do automatycznego dodawania mechanizmów zwi˛ekszania niezawodności do istniejacego ˛ oprogramowania oraz generacji dodatkowych danych ułatwiajacych ˛ przeprowadzanie procedur naprawczych. 151 Bibliografia [1] IEEE standard for reduced-pin and enhanced-functionality test access port and boundary-scan architecture. IEEE Std 1149.7-2009, pages c1–985, 2010. [2] K. Adams and O. Agesen. A comparison of software and hardware techniques for x86 virtualization. In Proceedings of the 12th international conference on Architectural support for programming languages and operating systems, ASPLOS-XII, pages 2–13, New York, NY, USA, 2006. ACM. [3] A. V. Aho, M. S. Lam, R. Sethi, and J. D. Ullman. Compilers: Principles, Techniques, and Tools (2nd Edition). Addison Wesley, 2006. [4] T. Akgul and V. J. Mooney. Instruction-level reverse execution for debugging. Technical report, School of Electrical and Computer Engineering, Georgia Institute of Technology, Atlanta, 2002. [5] A. Albinet, J. Arlat, and J. C. Fabre. Characterization of the impact of faulty drivers on the robustness of the linux kernel. In International Conference on Dependable Systems and Networks, pages 867–876, 2004. [6] H. Alemzadeh, Z. Kalbarczyk, R. Iyer, and J. Raman. Analysis of safety-critical computer failures in medical devices. Security Privacy, IEEE, PP(99):1–1, 2013. [7] B. Alexander, S. Donnellan, A. Jeffries, T. Olds, and N. Sizer. Boosting instruction set simulator performance with parallel block optimisation and replacement. In Proceedings of the Thirty-fifth Australasian Computer Science Conference - Volume 122, ACSC ’12, pages 11–20. Australian Computer Society, Inc., 2012. [8] J. Arlat, Y. Crouzet, J. Karlsson, P. Folkesson, E. Fuchs, and G. H. Leber. Comparison of physical and software-implemented fault injection techniques. IEEE Transactions on Computers, 52(9):1115–1133, 2003. [9] R. Barbosa, N. Silva, J. Duraes, and H. Madeira. Verification and validation of (real time) COTS products using fault injection techniques. In Sixth International IEEE Conference on Commercial-off-the-Shelf (COTS)-Based Software Systems, ICCBSS ’07, pages 233–242, 2007. [10] B. L. Belasco. High stability Windows programming for real time control. In International Conference on Security Technology (ICCST), IEEE, pages 127–133, 2010. [11] J. R. Bell. Threaded code. Communications of the ACM, 16(6):370–372, 1973. [12] F. Bellard. QEMU, a fast and portable dynamic translator. In Proceedings of the USENIX Annual Technical Conference, ATEC ’05, pages 41–41, Berkeley, CA, USA, 2005. USENIX Association. [13] M. Berndl, B. Vitale, M. Zaleski, and A. D. Brown. Context threading: a flexible and efficient dispatch technique for virtual machine interpreters. Generation and Optimization, pages 15–26, 2005. 153 In International Symposium on Code [14] A. Binu and G. S. Kumar. Virtualization techniques: A methodical review of XEN and KVM. In Advances in Computing and Communications, volume 190 of Communications in Computer and Information Science, pages 399–410. Springer Berlin Heidelberg, 2011. [15] C. Borchert, H. Schirmeier, and O. Spinczyk. Generative software-based memory error detection and correction for operating system data structures. In International Conference on Dependable Systems and Networks, pages 1–12, 2013. [16] S. Borkar. Designing reliable systems from unreliable components: the challenges of transistor variability and degradation. Micro, IEEE, 25(6):10–16, 2005. [17] M. Brunink, M. Susskraut, and C. Fetzer. Boundless memory allocations for memory safety and high availability. In International Conference on Dependable Systems Networks, pages 13–24, 2011. [18] K. Buchacker and V. Sieh. Framework for testing the fault-tolerance of systems including os and network aspects. In Sixth IEEE International Symposium on High Assurance Systems Engineering, pages 95–105, 2001. [19] J. Carreira, H. Madeira, and J. G. Silva. Xception: a technique for the experimental evaluation of dependability in modern computers. IEEE Transactions on Software Engineering, 24(2):125–136, 1998. [20] N. Chandra Shekar and W. Bhukya. Forensic analysis on QEMU. In Computational Intelligence and Information Technology, volume 250 of Communications in Computer and Information Science, pages 777–781. Springer Berlin Heidelberg, 2011. [21] D. Chen, G. Jacques-Silva, Z. Kalbarczyk, R. K. Iyer, and B. Mealey. Error behavior comparison of multiple computing systems: A case study using Linux on Pentium, Solaris on SPARC, and AIX on POWER. In 14th IEEE Pacific Rim International Symposium on Dependable Computing, PRDC ’08, pages 339 –346, 2008. [22] Shyh-Kwei Chen, W. K. Fuchs, and Jen-Yao Chung. Reversible debugging using program instrumentation. IEEE Transactions on Software Engineering, 27; 27(8):715–727, 2001. [23] S. Chyłek. Collecting program execution statistics with qemu processor emulator. In International Multiconference on Computer Science and Information Technology, IMCSIT ’09, pages 555–558, 2009. [24] S. Chyłek. QEMU CPU Tracer – an exact profiling tool. Metody Informatyki Stosowanej, 5/2011(30):167–172, 2011. [25] S. Chyłek and M. Goliszewski. QEMU-Based Fault Injection Framework. Studia Informatica, 33(4(109)):25–42, 2011. [26] S. Chyłek and M. Goliszewski. Wstrzykiwanie bł˛edów oparte na modelach - zastosowania QEMU w analizie niezawodności urzadzeń ˛ mobilnych. Zeszyty Naukowe Wydziału Elektroniki, Telekomunikacji i Informatyki Politechniki Gdańskiej, 1(9):489–494, 2011. [27] C. Constantinescu. Impact of deep submicron technology on dependability of VLSI circuits. In International Conference on Dependable Systems and Networks, pages 205–209, 2002. [28] C. Constantinescu. Trends and challenges in VLSI circuit reliability. Micro, IEEE, 23(4):14–19, 2003. 154 [29] J. Cornwell and A. Kongmunvattana. Efficient system-level remote checkpointing technique for BLCR. In Eighth International Conference on Information Technology: New Generations (ITNG), pages 1002–1007, 2011. [30] D. Cotroneo, R. Natella, and S. Russo. Assessment and improvement of hang detection in the Linux operating system. In 28th IEEE International Symposium on Reliable Distributed Systems, SRDS ’09, pages 288–294, 2009. [31] A. da Silva, J. F. Martinez, L. Lopez, A. B. Garcia, and V. Hernandez. XML schema based faultset definition to improve faults injection tools interoperability, 2008. [32] R. Dewar. Indirect threaded code. Communications of the ACM, 18(6):330–331, 1975. [33] R. J. Drebes and T. Nanya. Limitations of the Linux fault injection framework to test direct memory access address errors. In 14th IEEE Pacific Rim International Symposium on Dependable Computing, PRDC ’08, pages 146–152, 2008. [34] J. C. Fabre, M. Rodriguez, J. Arlat, and J. M. Sizun. microkernel-based systems using MAFALDA. Building dependable COTS In Pacific Rim International Symposium on Dependable Computing, 2000. [35] P. Gawkowski. Analysing and enhancing fault immunity of programs in systems with COTS elements. PhD thesis, Warsaw University of Technology, 2005. [36] P. Gawkowski and K. Grochowski. Inscript - a fault injection scripting language for system dependability evaluation. In Information Systems Architecture and Technology, Web Information System Engineering, Knowledge Discovery and Hybrid Computing, pages 245–254. Wrocław University of Technology, 2011. [37] P. Gawkowski, M. Kuczyńska, and A. Komorowska. Fault effects analysis and reporting system for dependability evaluation. In Rough Sets and Current Trends in Computing, volume 6086 of Lecture Notes in Computer Science, pages 524–533. Springer Berlin Heidelberg, 2010. [38] P. Gawkowski, P. Pawelczyk, J. Sosnowski, K. Cabaj, and M. Gajda. LRFI - fault injection tool for testing mobile software. In ISMIS Industrial Session, pages 269–282, 2011. [39] P. Gawkowski, T. Rutkowski, and J. Sosnowski. Improving fault handling software techniques. In IEEE 16th International On-Line Testing Symposium (IOLTS), IOLTS ’10, pages 197–199, 2010. [40] P. Gawkowski and J. Sosnowski. Analyzing fault effects in fault insertion experiments. Seventh International On-Line Testing Workshop, pages 21–24, 2001. [41] P. Gawkowski and J. Sosnowski. Using software implemented fault inserter in dependability analysis. Pacific Rim International Symposium on Dependable Computing, pages 81–88, 2002. [42] P. Gawkowski and J. Sosnowski. experiments. Developing fault injection environment for complex In 14th IEEE International On-Line Testing Symposium, IOLTS ’08, pages 179–181, 2008. [43] D. Gil, J. Gracia, J. C. Baraza, and P. J. Gil. Analysis of the influence of processor hidden registers on the accuracy of fault injection techniques. In Ninth IEEE International High-Level Design Validation and Test Workshop, pages 173–178, 2004. 155 [44] D. Gil, L. Saiz, J. Gracia, J. C. Baraza, and P. Gil. Injecting intermittent faults for the dependability validation of commercial microcontrollers. In IEEE International High Level Design Validation and Test Workshop, HLDVT ’08, pages 177–184, 2008. [45] R. Gioiosa, J. C. Sancho, S. Jiang, F. Petrini, and K. Davis. Transparent, incremental checkpointing at kernel level: a foundation for fault tolerance for parallel computers. In Proceedings of the 2005 ACM/IEEE conference on Supercomputing, SC ’05, pages 9–, Washington, DC, USA, 2005. IEEE Computer Society. [46] I. Gnaedig, M. Kaczmarek, D. Reynaud, and S. Wloka. Unconditional self-modifying code elimination with dynamic compiler optimizations. In 5th International Conference on Malicious and Unwanted Software (MALWARE), pages 47–54, 2010. [47] J. Gracia, L. Saiz, J. C. Baraza, D. Gil, and P. Gil. Analysis of the influence of intermittent faults in a microcontroller. In 11th IEEE Workshop on Design and Diagnostics of Electronic Circuits and Systems, DDECS 2008, pages 1–6, 2008. [48] Weining Gu, Z. Kalbarczyk, and R. K. Iyer. Error sensitivity of the Linux kernel executing on PowerPC G4 and Pentium 4 processors. In International Conference on Dependable Systems and Networks, pages 887–896, 2004. [49] A. H. Han, Young-Si Hwang, Young-Ho An, So-Jin Lee, and Ki-Seok Chung. Virtual ARM platform for embedded system developers. International Conference on Audio, Language and Image Processing, pages 586–592, 2008. [50] S. Hangal and M. S. Lam. Tracking down software bugs using automatic anomaly detection. In Proceedings of the 24th International Conference on Software Engineering, ICSE ’02, pages 291–301, New York, NY, USA, 2002. ACM. [51] J. L. Hennessy and D. A. Patterson. Computer Architecture, Fourth Edition: A Quantitative Approach. Morgan Kaufmann Publishers Inc., San Francisco, CA, USA, 2006. [52] J. N. Herder, H. Bos, B. Gras, P. Homburg, and A. S. Tanenbaum. Minix 3: a highly reliable, self-repairing operating system. SIGOPS Oper. Syst. Rev., 40(3):80–89, 2006. [53] J.N. Herder, H. Bos, B. Gras, P. Homburg, and A.S. Tanenbaum. Construction of a highly dependable operating system. In Sixth European Dependable Computing Conference, pages 3–12, 2006. [54] J.N. Herder, H. Bos, B. Gras, P. Homburg, and A.S. Tanenbaum. Fault isolation for device drivers. In International Conference on Dependable Systems Networks, pages 33–42, 2009. [55] Bing Huang, M. Rodriguez, Ming Li, and C. Smidts. On the development of fault injection profiles. In Annual Reliability and Maintainability Symposium, RAMS ’07, pages 226–231, 2007. [56] Intel Corporation. Intel 64 and IA-32 Architectures Software Developer’s Manual, 2013. [57] B. Jacob, S. Ng, and D. Wang. Memory Systems: Cache, DRAM, Disk. Morgan Kaufmann Publishers Inc., San Francisco, CA, USA, 2007. [58] G. Jacques-Silva, R. J. Drebes, J. Gerchman, J. M. F. Trindade, T. S. Weber, and I. Jansch-Porto. A network-level distributed fault injector for experimental validation of dependable distributed systems. 30th Annual International Computer Software and Applications Conference, 1:421–428, 2006. 156 [59] S. Jagannathan, Z. Diggins, N. Mahatme, T.D. Loveless, B. L. Bhuva, S-J Wen, R. Wong, and L.W. Massengill. Temperature dependence of soft error rate in flip-flop designs. In IEEE International Reliability Physics Symposium (IRPS), pages SE.2.1–SE.2.6, 2012. [60] M. Jakovljevic and A. Ademaj. Ethernet protocol services for critical embedded systems applications. In Digital Avionics Systems Conference (DASC), IEEE, pages 5.B.3–1–5.B.3–10, 2010. [61] T. Jarboui, J. Arlat, Y. Crouzet, and K. Kanoun. Experimental analysis of the errors induced into Linux by three fault injection techniques. In International Conference on Dependable Systems and Networks, pages 331–336, 2002. [62] T. Jarboui, J. Arlat, Y. Crouzet, K. Kanoun, and T. Marteau. Analysis of the effects of real and injected software faults: Linux as a case study. In Pacific Rim International Symposium on Dependable Computing, pages 51–58, 2002. [63] E. Jenn, J. Arlat, M. Rimen, J. Ohlsson, and J. Karlsson. Fault injection into VHDL models: the MEFISTO tool. Twenty-Fourth International Symposium on Fault-Tolerant Computing, pages 66–75, 1994. [64] Xun Jian and R. Kumar. Adaptive Reliability Chipkill Correct (ARCC). In 19th International Symposium on High Performance Computer Architecture, HPCA ’13, pages 270–281, 2013. [65] Seongwoo Kim and A.K. Somani. Soft error sensitivity characterization for microprocessor dependability enhancement strategy. In International Conference on Dependable Systems and Networks, pages 416–425, 2002. [66] W. Klonecki. Statystyka dla inżynierów. Wydawnictwo Naukowe PWN, 1999. [67] P. M. Kogge. An architectural trail to threaded-code systems. Computer, pages 22–32, 1982. [68] J. Korczyc and A. Kraśniewski. Evaluation of susceptibility of fpga-based circuits to fault injection attacks based on clock glitching. In IEEE 15th International Symposium on Design and Diagnostics of Electronic Circuits Systems, DDECS, pages 171–174, 2012. [69] M. Kubacki and J. Sosnowski. Analysing event log profiles in Linux systems. In Information Systems Architecture and Technology, Web Information System Engineering, Knowledge Discovery and Hybrid Computing, pages 135–144. Wrocław University of Technology, 2011. [70] M. Kubacki and J. Sosnowski. Enhanced instrumentation of system monitoring. In Information Systems in Management XVI: Modern ICT for Evaluation of Business Information Systems, pages 29–40. SGGW, 2012. [71] P. Latosiński and J. Sosnowski. Monitoring dependability of a mail server. Przeglad ˛ Elektrotechniczny, (10b):223–226, 2012. [72] A. Lesiak, P. Gawkowski, and J. Sosnowski. Error recovery problems. In 2nd International Conference on Dependability of Computer Systems, DepCoS-RELCOMEX ’07, pages 270–277, 2007. [73] Xiaofei Liao, Xiao Xie, and Hai Jin. Sharing virtual USB device in virtualized desktop. In Fourth International Symposium on Parallel Architectures, Algorithms and Programming (PAAP), pages 156–160, 2011. 157 [74] Xiyang Liu, Tao Liu, Zhiwen Bai, Yan Wang, Haoying Mu, and Chunxiang Li. a reversible debugging tool using dynamic binary translation. PORD: 14th Asia-Pacific Software Engineering Conference, pages 570–570, 2007. [75] H. Madeira, D. Costa, and M. Vieira. On the emulation of software faults by software fault injection. Proceedings International Conference on Dependable Systems and Networks, pages 417–426, 2000. [76] P. D. Marinescu and G. Candea. LFI: A practical and general library-level fault injector. In International Conference on Dependable Systems and Networks, pages 379–388, 2009. [77] D. Mihocka and S. Shwartsman. Virtualization without direct execution or jitting: Designing a portable virtual machine infrastructure. In 1st Workshop on Architectural and Microarchitectural Support for Binary Translation in ISCA-35, 2008. [78] J. S. Monson, M. Wirthlin, and B. Hutchings. A fault injection analysis of Linux operating on an FPGA-embedded platform. Int. J. Reconfig. Comput., 2012:7:7–7:7, 2012. [79] S. S. Mukherjee, M. Kontz, and S. K. Reinhardt. Detailed design and evaluation of redundant multi-threading alternatives. In 29th Annual International Symposium on Computer Architecture, pages 99–110, 2002. [80] M. Murciano and M. Violante. Validating the dependability of embedded systems through fault injection by means of loadable kernel modules. In High Level Design Validation and Test Workshop, IEEE International, pages 179–186, 2007. [81] A. B. Nagarajan, F. Mueller, C. Engelmann, and S. L. Scott. Proactive fault tolerance for HPC with Xen virtualization. In Proceedings of the 21st annual international conference on Supercomputing, ICS ’07, pages 23–32, New York, NY, USA, 2007. ACM. [82] P. Nazimek. Wykrywanie, ocena skuteczności i optymalizacja asercji w programach. Zeszyty Naukowe Wydziału ETI Politechniki Gdańskiej, 6:281–286, 2008. [83] P. Nazimek. Wykrywanie i zastosowanie asercji ze śladem. Zeszyty Naukowe Wydziału ETI Politechniki Gdańskiej, 19(8):379–384, 2010. [84] E. B. Nightingale, J. R. Douceur, and V. Orgovan. Cycles, cells and platters: An empirical analysisof hardware failures on a million consumer PCs. In Proceedings of the Sixth Conference on Computer Systems, EuroSys ’11, pages 343–356, New York, NY, USA, 2011. ACM. [85] D. K. Nilsson, Lei Sun, and T. Nakajima. A framework for self-verification of firmware updates over the air in vehicle ECUs. In GLOBECOM Workshops, pages 1–5, 2008. [86] K. Onoue, Y. Oyama, and A. Yonezawa. A virtual machine migration system based on a CPU emulator. First International Workshop on Virtualization Technology in Distributed Computing, pages 3–3, 2006. [87] E. Park, B. Egger, and J. Lee. Fast and space-efficient virtual machine checkpointing. In Proceedings of the 7th ACM SIGPLAN/SIGOPS international conference on Virtual execution environments, VEE ’11, pages 75–86, New York, NY, USA, 2011. ACM. [88] P. Popov and L. Strigini. Assessing asymmetric fault-tolerant software. Symposium on Software Reliability Engineering, pages 41–50, 2010. 158 In International [89] R. Radhakrishnan, N. Vijaykrishnan, L. K. John, Anand Sivasubramaniam, J. Rubio, and J. Sabarinathan. Java runtime systems: characterization and architectural implications. IEEE Transactions on Computers, 50(2):131–146, 2001. [90] L. Rashid, K. Pattabiraman, and S. Gopalakrishnan. Modeling the propagation of intermittent hardware faults in programs. In 16th Pacific Rim International Symposium on Dependable Computing, pages 19–26, 2010. [91] C. Reis and S. D. Gribble. Isolating web programs in modern browser architectures. In Proceedings of the 4th ACM European conference on Computer systems, EuroSys ’09, pages 219–232, New York, NY, USA, 2009. ACM. [92] C. Roscian, A. Sarafianos, J. M. Dutertre, and A. Tria. Fault model analysis of laser-induced faults in SRAM memory cells. In Workshop on Fault Diagnosis and Tolerance in Cryptography (FDTC), pages 89–98, 2013. [93] M. Sand, S. Potyra, and V. Sieh. Deterministic high-speed simulation of complex systems including fault-injection. In International Conference on Dependable Systems and Networks, pages 211–216, 2009. [94] B. Schroeder, E. Pinheiro, and W. Weber. DRAM errors in the wild: a large-scale field study. In Proceedings of the eleventh international joint conference on Measurement and modeling of computer systems, SIGMETRICS ’09, pages 193–204, New York, NY, USA, 2009. ACM. [95] Ningfang Song, Jiaomei Qin, Xiong Pan, and Yan Deng. Fault injection methodology and tools. In International Conference on Electronics and Optoelectronics, volume 1, pages V1–47–V1–50, 2011. [96] J. Sosnowski. Testowanie i niezawodność systemów komputerowych. Akademicka Oficyna Wydawnicza Exit, 2005. [97] J. Sosnowski, M. Kubacki, and H. Krawczyk. Monitoring event logs within a cluster system. In Complex Systems and Dependability, Advances in Intelligent and Soft Computing, pages 259–271. Springer, 2012. [98] J. Sosnowski and L. Tupaj. CPU testability in embedded systems. In Fifth IEEE International Symposium on Electronic Design, Test and Application, DELTA ’10, pages 108 –112, 2010. [99] J. Sosnowski, A. Tymoczko, and P. Gawkowski. An approach to distributed fault injection experiments. Parallel Processing and Applied Mathematics, pages 361–370, 2008. [100] J. Sosnowski, A. Tymoczko, and P. Gawkowski. Developing distributed system for simulation experiments. Information Systems Architecture and Technology, Information Systems and Computer Communication Networks, pages 263–274, 2008. [101] J. Sosnowski, P. Zygulski, and P. Gawkowski. Developing data warehouse for simulation experiments. In Rough Sets and Intelligent Systems Paradigms, volume 4585 of Lecture Notes in Computer Science, pages 543–552. Springer Berlin Heidelberg, 2007. [102] R. Svenningsson, H. Eriksson, J. Vinter, and M. Törngren. Model-implemented fault injection for hardware fault simulation. In Workshop on Model-Driven Engineering, Verification, and Validation, pages 31–36, 2010. 159 [103] A. S. Tanenbaum. Modern Operating Systems. Prentice Hall Press, Upper Saddle River, NJ, USA, 3rd edition, 2007. [104] D. Trawczyński, J. Sosnowski, and P. Gawkowski. Testing distributed ABS system with fault injection. In Innovations in Computing Sciences and Software Engineering, pages 201–206. Springer, 2010. [105] P. Tröger, F. Salfner, and S. Tschirpke. Software-implemented fault injection at firmware level. In Third International Conference on Dependability, DEPEND, pages 13–16, 2010. [106] T. Tsai, N. Theera-Ampornpunt, and S. Bagchi. A study of soft error consequences in hard disk drives. In International Conference on Dependable Systems and Networks, pages 1–8, 2012. [107] K. Vaswani and Y. N. Srikant. Dynamic recompilation and profile-guided optimisations for a .NET JIT compiler. Software, IEE Proceedings, 150(5):296–302, 2003. [108] Liming Wang, Xiyang Liu, Ailong Song, Lin Xu, and Tao Liu. An effective reversible debugger of cross platform based on virtualization. International Conference on Embedded Software and Systems, pages 448–453, 2009. [109] Long Wang, Z. Kalbarczyk, R.K. Iyer, and A. Iyengar. Checkpointing virtual machines against transient errors. In IEEE 16th International On-Line Testing Symposium, pages 97–102, 2010. [110] Jiesheng Wei, L. Rashid, K. Pattabiraman, and S. Gopalakrishnan. Comparing the effects of intermittent and transient hardware faults on programs. In 41st International Conference on Dependable Systems and Networks Workshops, pages 53–58, 2011. [111] P. M. Wells, K. Chakraborty, and G. S. Sohi. Adapting to intermittent faults in future multicore systems. In 16th International Conference on Parallel Architecture and Compilation Techniques, PACT 2007, pages 431–431, 2007. [112] S. Winter, C. Sarbu, B. Murphy, and N. Suri. The impact of fault models on software robustness evaluations. In 33rd International Conference on Software Engineering (ICSE), pages 51–60, 2011. [113] Jun Xu, Z. Kalbarczyk, and R. K. Iyer. Networked Windows NT system field failure data analysis. In Pacific Rim International Symposium on Dependable Computing, pages 178–185, 1999. [114] Yang Yang and LingLing Hua. Research and improvement of Linux real-time performance. In Advanced Technology in Teaching - Proceedings of the 2009 3rd International Conference on Teaching and Computational Science, volume 116 of WTCS 2009, pages 555–559. Springer Berlin Heidelberg, 2012. [115] Keun Soo Yim, Z. Kalbarczyk, and R.vK. Iyer. Measurement-based analysis of fault and error sensitivities of dynamic memory. In International Conference on Dependable Systems and Networks, pages 431–436, 2010. [116] FanPing Zeng, Juan Li, Ling Li, and Xufa Wang. Fault injection technology for software vulnerability testing based on Xen. In World Congress on Software Engineering, volume 4 of WCSE ’09, pages 206 –210, 2009. A. Dodatek – specyfikacja opracowanego oprogramowania Kody źródłowe QEFI oraz dodatkowe zasoby można znaleźć w repozytorium projektu znajdujacym ˛ si˛e pod adresem http://chylek.name/qefi/. A.1. QEFI Narz˛edzie QEFI składa si˛e z kilku współpracujacych ˛ ze soba˛ programów w celu realizacji eksperymentów symulowania bł˛edów w systemie komputerowym. A.1.1. QEMU Podstawowym komponentem QEFI jest emulator systemu komputerowego QEMU. W QEFI wykorzystano oprogramowanie QEMU w wersji 1.1.2. W celu realizacji metodyki symulowania bł˛edów zmodyfikowane zostały nast˛epujace ˛ moduły QEMU: Moduł Fault Injection – Opracowano nowy moduł realizujacy ˛ zaburzanie pami˛eci oraz kontrolujacy ˛ wyzwalanie warunkowego wstrzykiwania bł˛edu. Moduł śledzenia wykonania – Opracowano nowy moduł realizujacy ˛ nieinwazyjne śledzenie wykonania poprzez rejestrowanie wykonania instrukcji skoków przez emulowany procesor. Moduł konsoli sterowania – Modyfikacja modułu konsoli sterowania umożliwiajaca ˛ wykonywanie komend sterujacych ˛ procesem symulacji bł˛edów oraz profilowania. Moduł translacji binarnej – Modyfikacje polegajace ˛ na wplataniu w kod wygenerowany w procesie binarnej translacji dodatkowych funkcji realizujacych ˛ zarówno symulowanie bł˛edów, jak i profilowanie. Moduł dost˛ epu do pami˛ eci – Modyfikacje umożliwiajace ˛ symulowanie bł˛edów danych przy odczycie, wykorzystane w procesie zaburzania pami˛eci alokowanej przez system operacyjny. Moduł emulujacy ˛ urzadzenie ˛ USB MSD – Modyfikacje umożliwiajace ˛ symulowanie bł˛edów w pakietach wysyłanych z urzadzenia ˛ USB MSD. Moduł emulujacy ˛ urzadzenie ˛ USB UHCI – Modyfikacje symulowanie bł˛edów w rejestrach kontrolera USB UHCI. 161 umożliwiajace ˛ Moduł emulujacy ˛ urzadzenie ˛ e1000 – Modyfikacje umożliwiajace ˛ symulowanie bł˛edów w deskryptorach pakietów pochodzacych ˛ z urzadzenia ˛ sieciowego e1000. Poniżej zamieszczony jest listing nowych komend konsoli sterowania QEMU: fi_enable – Komenda powoduje właczenie ˛ funkcji zwiazanych ˛ ze wstrzykiwaniem bł˛edów. fi_disable – Komenda powoduje wyłaczenie ˛ funkcji zwiazanych ˛ ze wstrzykiwaniem bł˛edów. fi_write_pmem – Parametry: adres fizyczny, nowa wartość bajtu. Komenda pozwala zapisać dowolny bajt w pami˛eci operacyjnej wskazany adresem fizycznym. fi_write_vmem – Parametry: adres pami˛eci wirtualny, nowa wartość bajtu. Komenda pozwala zapisać dowolny bajt w pami˛eci operacyjnej wskazany adresem pami˛eci wirtualnej. Komenda może być wykonana wyłacznie ˛ po wstrzymaniu procesu emulacji, a zaburzana pami˛eć wirtualna jest pami˛ecia˛ procesu wykonywanego przed wstrzymaniem. fi_random_bit_vmem_range – Parametry: poczatek ˛ zakresu pami˛eci wirtualnej, koniec zakresu pami˛eci wirtualnej. Komenda powoduje wprowadzenie pojedynczego bł˛edu typu bit-flip w losowo wybrana˛ komórk˛e pami˛eci spośród zadanego zakresu. Komenda może być wykonana wyłacznie ˛ po wstrzymaniu procesu emulacji, a zaburzana pami˛eć wirtualna jest pami˛ecia˛ procesu wykonywanego przed wstrzymaniem. fi_disturb_usb_msd – Parametry: prawdopodobieństwo zaburzenia pakietu. Komenda powoduje wprowadzenie pojedynczego bł˛edu typu bit-flip w losowo wybrany bit pakietu danych wysyłanych z urzadzenia ˛ USB MSD. Wybór zaburzanego pakietu jest warunkowy, sterowany prawdopodobieństwem – tzn. przy każdej operacji wysyłania pakietu z urzadzenia ˛ USB MSD wybierana jest losowa liczba z zakresu [0−1]; jeżeli jest ona mniejsza niż zadane prawdopodobieństwo, to do pakietu wprowadzany jest bład. ˛ fi_disturb_usb_uhci – Parametry: prawdopodobieństwo wprowadzenia bł˛edu przy aktualizacji stanu rejestrów USB UHCI. Komenda powoduje wprowadzenie pojedynczego bł˛edu typu bit-flip w losowo wybrany bit w losowo wybranym rejestrze kontrolera USB UHCI – wybór momentu wprowadzenia bł˛edu jest warunkowy, sterowany prawdopodobieństwem – tzn. przy każdej operacji aktualizacji stanu rejestrów USB UHCI wybierana jest losowa liczba z zakresu [0 − 1]; jeżeli jest ona mniejsza niż zadane prawdopodobieństwo, to do losowego rejestru wprowadzany jest bład. ˛ fi_disturb_e1000 – Parametry: prawdopodobieństwo zaburzenia deskryptora pakietu. Komenda powoduje wprowadzenie pojedynczego bł˛edu typu bit-flip w losowo wybrany bit deskryptora pakietu danych pochodzacych ˛ z urzadzenia ˛ sieciowego e1000. Wybór zaburzanego deskryptora pakietu jest warunkowy, sterowany prawdopodobieństwem – tzn. przy każdej operacji wysyłania deskryptora pakietu z urzadzenia ˛ e1000 wybierana jest losowa liczba z zakresu [0 − 1]; jeżeli jest ona mniejsza niż zadane prawdopodobieństwo, to do pakietu wprowadzany jest bład. ˛ 162 fi_disturb_stack – Parametry: zaburzanej przestrzeni stosu. prawdopodobieństwo wprowadzenia bł˛edu, zakres Komenda powoduje wprowadzenie pojedynczego bł˛edu typu bit-flip w losowo wybrany bit danych w określonym zakresie liczonym od wierzchołka stosu. Wybór momentu wprowadzenia bł˛edu jest warunkowy, sterowany prawdopodobieństwem – tzn. przy każdym wykonaniu przez emulowany procesor instrukcji call, wybierana jest losowa liczba z zakresu [0 − 1]; jeżeli jest ona mniejsza niż zadane prawdopodobieństwo, to w określonym zakresie danych wprowadzany jest bład. ˛ fi_disturb_allocked_mem – Parametry: prawdopodobieństwo wprowadzenia bł˛edu, adres funkcji trace_kmalloc, adres funkcji kfree. Komenda powoduje wprowadzenie pojedynczego bł˛edu typu bit-flip w losowo wybrany bit danych spośród danych zaalokowanych przez system operacyjny od momentu wydania komendy. Zbiór danych jest wyznaczany dynamicznie poprzez śledzenie wywołań funkcji kmalloc oraz kfree. Wybór momentu wprowadzenia bł˛edu jest warunkowy, sterowany prawdopodobieństwem – tzn. przy każdej operacji odczytu danych przez emulowany procesor z wyznaczonego zbioru danych alokowanych, wybierana jest losowa liczba z zakresu [0−1]; jeżeli jest ona mniejsza niż zadane prawdopodobieństwo, to w odczytywanych zakresie danych wprowadzany jest bład. ˛ fi_enable_trace – Komenda powoduje właczenie ˛ trybu śledzenia wykonania. W katalogu roboczym QEMU tworzony jest plik zawierajacy ˛ skompresowana˛ algorytmem GZIP histori˛e skoków wykonanych przez procesor. fi_disable_trace – Komenda powoduje wyłaczenie ˛ trybu śledzenia wykonania. A.1.2. Nadzorca Nadzorca jest programem kontrolujacym ˛ przebieg wykonania testu. Jego głównym zadaniem jest uruchomienie instancji QEMU i wykonanie kroków scenariusza testowego. Oprogramowanie nadzorcy nawiazuje ˛ połaczenia ˛ konsola˛ sterowania QEMU oraz emulowanym portem szeregowym emulowanego systemu. Opcjonalnie Nadzorca uruchamia dodatkowe programy przeprowadzajace ˛ interakcj˛e z emulowanym systemem (np. skrypty programu expect realizujace ˛ szyfrowane połaczenia ˛ ssh). Predefiniowane jest kilka typów scenariuszy testowych (dokładny wykaz poniżej), a nowe scenariusze moga˛ być dodawane według potrzeb poprzez rozszerzenie programu Nadzorcy. Możliwe jest uruchomienie scenariusza testowego w trybie profilowania, gdzie bład ˛ nie jest wstrzykiwany, natomiast zbierane sa˛ dane z nieinwazyjnego śledzenia wykonania. Dla niektórych scenariuszy konieczne może być dostarczenie danych z profilowania. Flagi uruchamiania programu Nadzorcy: trace – Wykonanie scenariusza bez symulacji bł˛edu, natomiast zbierane sa˛ dane z nieinwazyjnego śledzenia wykonania. 163 fault – Typ bł˛edu spośród typów bł˛edów zdefiniowanych dla danego scenariusza testowego. port_control – Numer portu, na którym ma być prowadzona komunikacja Nadzorcy z konsola˛ sterowania QEMU. port_serial – Numer portu, na którym ma być prowadzona komunikacja Nadzorcy z emulowanym portem szeregowym SUT. scenario – Uruchomiony scenariusz testowy. Dost˛epne scenariusze: — wget – Scenariusz realizujacy ˛ kroki opisane w Scenariuszu 4.1 (strona 75). Dost˛epne typy bł˛edów: zaburzanie pami˛eci fizycznej, zaburzanie danych pami˛eci wirtualnej, zaburzanie kodu wyznaczonego z profilowania, zaburzanie danych alokowanych, zaburzanie danych na stosie. — curl – Scenariusz analogiczny do scenariusza wget wykorzystujacy ˛ program curl zamiast wget. Dost˛epne typy bł˛edów: zaburzanie pami˛eci fizycznej. — pendrive – Scenariusz realizujacy ˛ kroki opisane w Scenariuszu (strona 4.2). Dost˛epne typy bł˛edów: zaburzanie pakietów wysyłanych z urzadzenia ˛ USB MSD, zaburzanie wartości zawartości rejestrów urzadzenia ˛ USB UHCI. — srv – Scenariusz realizujacy ˛ kroki opisane w Scenariuszu 4.3 (strona 108).Dost˛epne typy bł˛edów: zaburzanie kodu wyznaczonego z profilowania, zaburzanie danych alokowanych, zaburzanie danych na stosie. W wyniku działania programu Nadzorcy wytworzone sa˛ nast˛epujace ˛ artefakty: appxLogFile.log – Dziennik programu Nadzorcy. login.txt – Zapis interakcji programu Nadzorcy z SUT na kanale konsoli szeregowej od momentu uruchomienia SUT do uruchomienia systemu operacyjnego działajacego ˛ w SUT. experiment.txt – Zapis interakcji programu Nadzorcy z SUT na kanale konsoli szeregowej od momentu uruchomienia systemu operacyjnego działajacego ˛ w SUT. monitor.txt – Zapis interakcji programu Nadzorcy z konsola˛ sterowania QEMU. serr.txt, sout.txt – Zrzut danych wypisanych przez program QEMU na standardowy strumień wyjścia oraz standardowy strumień bł˛edów. run.log – Dziennik wykonania scenariusza przez program Nadzorcy. output.gz – Opcjonalny plik zawierajacy ˛ skompresowane dane z profilowania. kallsyms.txt – Opcjonalny plik (zależny od scenariusza) zawierajacy ˛ zrzut pliku /proc/kallsyms systemu operacyjnego działajacego ˛ w SUT. sshout.txt, sshserr.txt, wgetserr.txt, wgetsout.txt, ... – Opcjonalne pliki zawierajace ˛ zrzut danych wypisanych przez dodatkowe programy uruchomione przez program Nadzorcy na standardowy strumień wyjścia oraz standardowy strumień bł˛edów. 164 A.1.3. Ekstraktor Program Ekstraktor jest programem pomocniczym realizujacym ˛ dekodowanie pliku z zapisanymi informacjami z profilowania – adresy skoków wykonanych przez procesor tłumaczone sa˛ na nazwy funkcji jadra ˛ systemu operacyjnego. Program działa na podstawie plików output.gz i kallsyms.txt, które sa˛ artefaktami wykonania scenariusza testowego przez program Nadzorcy w trybie trace. Szczegółowy schemat działania programu jest opisany w [24]. A.1.4. Eksperyment Eksperyment jest to skrypt realizujacy ˛ uruchomienie wielu instancji par programów Nadzorca-QEMU w celu wykonania zadanej liczby testów. Parametry skryptu to: rootdir – Główny katalog, w którym tworzone sa˛ podkatalogi b˛edace ˛ katalogami roboczymi par programów Nadzorca-QEMU (w podkatalogach składowane sa˛ artefakty każdej instancji programu Nadzorcy). port_range_control_start – jest parametr liczba, na programu port_control podstawie Nadzorcy której wyliczany (port_control = port_range_control_start + identyfikator instancji programu Nadzorcy nadany przez skrypt Eksperyment z zakresu 1..jobs). port_range_serial_start – jest parametr liczba, port_serial na programu podstawie Nadzorcy której wyliczany (port_serial = port_range_serial_start + identyfikator instancji programu Nadzorcy nadany przez skrypt Eksperyment z zakresu 1..jobs). jobs – Liczba jednocześnie uruchomionych instancji par programów Nadzorca-QEMU. W momencie zakończenia działania jednej z instancji uruchamiana jest nowa instancja, której przydzielany jest nowy katalog roboczy. tests – Liczba testów do wykonania. A.1.5. Analizator Program Analizator dokonuje podsumowania wyników wygenerowanych z użyciem skryptu Eksperyment. Wyposażony jest on w baz˛e komunikatów, których obecność sprawdza w artefaktach programu Nadzorca. Posiada on też wbudowane referencyjne dane scenariuszy – w szczególności funkcje oceny pozwalajace ˛ określić, czy dany test zakończył si˛e wynikiem prawidłowym. Wynikiem działania programu jest plik CSV zawierajacy ˛ podsumowanie wykrytych cech dla każdego z przeprowadzonych testów. Parametry wywołania programu to: rootdir – Główny katalog, w którym znajduja˛ si˛e katalogi z artefaktami przeznaczonymi do analizy. workers – Liczba watków ˛ równocześnie analizujacych ˛ artefakty. 165 scenario – Referencyjny scenariusz. Dost˛epne scenariusze: wget, curl, pendrive, srv. csv – Nazwa pliku stanowiacego ˛ wynik działania programu. viewerrors – Przełacznik ˛ umożliwiajacy ˛ przeglad ˛ dzienników wykonania testów z zamanifestowanym bł˛edem. performance – Przełacznik ˛ powodujacy ˛ zbieranie dodatkowych danych dotyczacych ˛ czasu wykonania testów. A.2. Zmiany w jadrze ˛ systemu GNU/Linux W celu implementacji mechanizmów zwi˛ekszania niezawodności wprowadzono nast˛epujace ˛ zmiany w jadrze ˛ systemu GNU/Linux (wersja 2.6.32): arch/x86/mm/fault.c – Zmodyfikowana została funkcja no_context_fail odpowiedzialna za zgłoszenie awarii wykonywanego zadania w przypadku zgłoszenia przerwania nieprawidłowego odwołania do pami˛eci. Wykonanie tej funkcji zostało uzależnione od wartości zwracanej przez nowa˛ funkcj˛e no_context_fail_check, która działa zgodnie z opisem funkcji F opisanej w 5.6.1 (strona 126) i jej działanie może być zmodyfikowane z użyciem mechanizmu kprobes. Jeżeli funkcja no_context_fail_check zwróci wartość TRUE, to zgłoszenie awarii jest zaniechane, a działanie zadania zgłaszajacego ˛ przerwanie jest wznowione. arch/x86/kernel/traps.c – Zmodyfikowana została funkcja fixup_exception odpowiedzialna za podj˛ecie próby naprawy przerwania general protection fault. Jeżeli domyślne działanie funkcji nie przyniosło efektu, wywoływana jest dodatkowa funkcja fixup_exception_check, która działa zgodnie z opisem funkcji F opisanej w 5.6.1 (strona 126) i jej działanie może być zmodyfikowane z użyciem mechanizmu kprobes. Jeżeli funkcja fixup_exception_check zwróci wartość TRUE, to sygnalizowane jest naprawienie bł˛edu i działanie zadania zgłaszajacego ˛ przerwanie jest wznowione. 166