- COMP.SEC.100
- 12. Käyttöjärjestelmät ja virtualisointi
- 12.6 Käyttöjärjestelmän koventaminen
Käyttöjärjestelmän koventaminen¶
Paras tapa suojata käyttöjärjestelmät ja virtuaalikoneet on rakentaa ne ilman haavoittuvuuksia, mikä tarkoittaa että tietoturva on integroitu (suunnitteluperiaatteen mukaisesti). Voidaan esimerkiksi käyttää formaaleja menetelmiä todistamaan, että ohjelmistossa tai laitteistossa ei voi olla tietyn tyyppisiä virheitä ja että järjestelmä on toiminnallisesti oikea. Todistamisen skaalaaminen erittäin suuriin järjestelmiin on yhä vaikeaa, mutta ala etenee nopeasti ja on saavuttanut vaiheen, jossa tärkeät komponentit, kuten mikroydin, tiedostojärjestelmät ja kääntäjät, on verifioitu muodollista spesifikaatiota vastaan. Lisäksi järjestelmän kaikkia osia ei tarvitse verifioida: eristyksen takaamiseen riittää turvallinen mikroydin/hypervisor ja muutama lisäosa. Muiden komponenttien todentaminen voi olla toivottavaa, mutta se ei ole välttämätöntä eristämisen kannalta. Tietenkin todistus on vain niin hyvä kuin taustalla oleva spesifikaatio. Jos siinä on virhe, ei auta, vaikka toteutus olisi varmuudella sen mukainen.
Yrityksistä huolimatta ei ole kuitenkaan pystytty poistamaan kaikkia haavoittuvuuksia suurista, todellisista järjestelmistä. Uhkamallissa kuvatuilta hyökkäyksiltä suojautumiseksi nykyaikaiset käyttöjärjestelmät käyttävät erilaisia ratkaisuja, jotka täydentävät edeltävän luvun eristys- ja välitysmenetelmiä. Tässä käsitellään viiden tyyppisiä suojauksia, joilla käyttöjärjestelmää voidaan koventaa (harden):
- Tiedon piilottaminen. Ajatuksena on, että hyökkääjä ei löydä ohjelmien ajoon liittyviä siirtymäkohtia muistista, koska niiden sijainti vaihtelee eri ajokerroilla satunnaisesti.
- Kontrollivuon rajoitukset, joilla pyritään siihen, että ohjelma ajautuisi niiden siirtymien kautta, jotka ohjelmoija on tarkoittanut. Hyökkääjähän voisi yrittää puuttua peliin juuri tällaisissa kohdissa, mutta rajoitukset auttavat myös virheitä vastaan.
- Osiointi, jolla nykyään täydennetään jo vakioksi tullutta datan ja ajettavien bittien erottelua. Tärkein osiointi tapahtuu prosessorin tarjoamien suojakehien tapaan ytimen ja käyttäjien välillä, mutta toiseen suuntaan kuin aiemmin Meltdownin tyyppisten haavoittuvuuksien takia.
- Koodin ja tietojen eheystarkistukset. Tämäkin on täydennystä vanhoihin menetelmiin, joilla on esim. hash-arvon avulla voitu tarkistaa, että tiedostot ovat entisellään. Uudempana näkökulmana on etäältä tehtävä tarkistus, joka koskee erityisesti käynnistysvaihetta.
- Poikkeamien havaitseminen. Tämä on ajonaikainen vastine ja jatke edelliselle. Samalla se on käyttöjärjestelmän toimintaan ulottuva erityistapaus yleisestä tietojärjestelmien valvonnasta suhteessa sallittavaan käyttäytymisen. Sallittavuuden rajojen sijasta joudutaan tässäkin yleensä vertailemaan normaaliin eli entuudestaan tuttuun.
Nämä kovennukset ovat sellaisia, joita käyttöjärjestelmien suunnittelijat ja ohjelmoijat tekevät vuorovaikutuksessa myös prosessorivalmistajien kanssa. Yritys, joka on asentamassa käyttöjärjestelmiä tietokoneisiinsa, voi kyllä ottaa käyttöön koneisiin tai tietoverkkoonsa IDS-järjestelmiä, jotka hälyttävät poikkeamista. Muilta osin tietyssä tehtävässä olevaa tietokonetta kannattaa käyttöönottovaiheessa koventaa hyökkäyspintaa pienentämällä. Sellainen työ alkaa oletussalasanojen vaihtamisesta. Lisäksi poistetaan tehtävän kannalta turhat ohjelmistot ja palvelut kokonaan tai ainakin käytöstä. Samoin poistetaan tarpeettomat käyttäjätunnukset tai paikalliset kirjautumistunnukset. Palvelinlaitteisiin jää usein paikallisesti kirjautuvaksi käyttäjäksi vain root.
Tiedon piilottaminen (syventävä)¶
Yksi tärkeimmistä puolustustavoista useimmissa nykyisissä käyttöjärjestelmissä on piilottaa kaikki, mistä hyökkääjät voivat olla kiinnostuneita. Erityisesti satunnaistamalla kaikkien asiaankuuluvien muistialueiden sijainnit (koodissa, keossa (heap), globaaleissa tiedoissa ja pinossa (stack)), hyökkääjät eivät tiedä mihin ohjata kontrollivuota, eivätkä he pysty havaitsemaan, mitkä osoitteet sisältävät arkaluontoisia tietoja jne. Termi Address Space Layout Randomization (ASLR) syntyi vuonna 2001, kun tämän satunnaistaminen toteutettiin Linux-ytimessä (asia on esillä myös ohjelmiston tietoturvassa). Pian samankaltaisia piirteitä ilmaantui muihin käyttöjärjestelmiin. Ensimmäiset yleiskäyttöiset, joissa ASLR oli oletusarvona, olivat OpenBSD vuonna 2003 ja Linux vuonna 2005. Windows ja MacOS seurasivat vuonna 2007. Nämä varhaiset toteutukset kuitenkin satunnaistivat vain käyttäjäohjelmien osoiteavaruuden. Satunnaistaminen pääsi tärkeimpien käyttöjärjestelmien ytimeen, nimellä Kernel ASLR (KASLR), vasta noin vuosikymmen käyttäjäohjelmiin soveltamisen jälkeen.
KASLR:n idea on yksinkertainen, mutta suunnittelussa on tehtävä monia ei-triviaaleja päätöksiä. Esimerkiksi kuinka satunnainen on satunnainen? Erityisesti, mikä osa osoitteesta satunnaistetaan? Oletetaan, että Linux-ytimen koodin osoitealue on 1 Gt (= 230), ja koodi voidaan aloittaa minkä tahansa 2 Mt:n (=221) rajan kohdalta. Satunnaistukseen käytettävissä olevien bittien määrä (entropia) on 30−21 = 9. Toisin sanoen tarvitaan enintään 512 arvausta ytimen koodin löytämiseen (mikä toki saadaan suoraankin laskemalla 1 Gt / 2 Mt). Jos hyökkääjä löytää haavoittuvuuden, jolla hän voi käyttäjätilan ohjelmasta ohjata ytimen kontrollivuon arvattuun osoitteeseen, riittäisi pääsy muutamaan sataan koneeseen. Tällöin olisi jo hyvä todennäköisyys saada ainakin yksi oikea arvaus, vaikka muut koneet kaatuvatkin prosessin aikana.
Toinen tärkeä päätös on, mitä satunnaistetaan. Useimmat tämän päivän toteutukset käyttävät karkearakeista satunnaistamista: ne satunnaistavat koodin, keon tai pinon alkukohdan (base), mutta siitä lukien jokainen elementti on kiinteällä etäisyydellä (offset). Tämä on yksinkertaista ja erittäin nopeaa. Kuitenkin, kun hyökkääjä onnistuu saamaan haltuunsa edes yhden koodiosoittimen tietovuodon kautta, hän tietää jokaisen käskyn osoitteen. Sama pätee soveltuvin osin kekoon, pinoon jne. Ei ole yllätys, että nämä tietovuodot ovat hyökkääjien arvostamia kohteita nykyään.
Hienojakoisempi satunnaistaminen on mahdollista. Voidaan esimerkiksi satunnaistaa sivun tai funktion tasolla. Jos sekoitetaan funktioiden järjestystä muistialueella, edes ytimen koodin alkukohdan tunteminen ei riitä hyökkääjälle. Voidaan mennä pitemmällekin ja sekoittaa muistilohkoja, käskyjä (mahdollisesti sijoittaen turhia käskyjä, joita ei koskaan suoriteta tai joilla ei ole vaikutusta) tai jopa rekisterien allokaatioita. Monet hienojakoiset satunnaistustekniikat maksavat tilaa ja aikaa.
Hienojakoinen satunnaistaminen toimii koodin lisäksi myös datalle. Tutkimukset ovat esimerkiksi osoittaneet, että keon allokaatiot, globaalit muuttujat ja jopa pinossa olevat muuttujat voivat sijaita hajallaan muistissa. Tietysti tämänkin tekeminen aiheuttaa kustannuksia suorituskyvyn ja muistin määrän suhteen.
KASLR:n, edes karkeasti satunnaistavan, käyttö on avuksi muistivirheiden hyväksikäyttöä vastaan, mutta se on vain heikko puolustus. Lukuisat julkaisut ovat osoittaneet, että KASLR voidaan rikkoa melko helposti vuotamalla tietoja ja/tai koodiosoittimia muistista, sivukanavista jne.
Kontrollivuon rajoitukset (syventävä)¶
Käyttöjärjestelmän kontrollivuon säätely on muistipaikkojen piilottamiseen verrattuna eri ulottuvuuteen kuuluva puolustustapa. Varmistamalla, että hyökkääjät eivät voi siirtää kontrollia valitsemaansa koodiin, vaikeutetaan muistivirheiden hyödyntämistä, vaikka niitä ei saisikaan poistetuksi. Paras esimerkki tunnetaan nimellä Control-Flow Integrity, CFI. Sitä tukevat monet kääntämiseen liittyvät työkaluohjelmat (toolchains, kuten LLVM ja Microsoftin Visual Studio), ja se on sisällytetty Windows-ytimeen nimellä Control Flow Guard vuodesta 2017 alkaen.
Käsitteellisesti CFI on todella yksinkertainen: varmistetaan, että koodin kontrollivuo seuraa aina staattista kontrollivuokaaviota. Funktiosta paluun pitäisi saada tapahtua vain sinne mistä kutsu tapahtui. Epäsuoran kutsun, joka käyttää funktio-osoitinta C:ssä tai virtuaalista funktiota C++:ssa, pitäisi pystyä kohdistumaan vain sellaisten funktioiden aloituspisteeseen, joita koodilla on oikeus kutsua. Tämän suojauksen toteuttamiseksi voidaan nimetä kaikki epäsuoralle siirtymäkäskylle luvalliset kohteet (paluut, epäsuorat kutsut ja epäsuorat hypyt) ja lisätä nimet tälle käskylle määritettyyn joukkoon. Ajon aikana tarkistetaan, osuuko käskyn edellyttämä kontrollin siirto joukossa olevaan kohteeseen. Jos ei, CFI hälyttää ja/tai kaataa ohjelman.
ASLR:n tavoin CFI:tä on monia tyyppejä, karkeasta hienoon ja kontekstiherkästä kontekstivapaaseen. Ja aivan kuten ASLR:ssä, useimmat toteutukset käyttävät nykyään vain yksinkertaisinta, karkeinta suojausta. Karkea CFI tarkoittaa sääntöjen hieman höllentämistä suorituskyvyn vuoksi. Esimerkiksi sen sijaan, että rajoitettaisiin funktion paluu vain niihin koodin kohtiin, joista tätä funktiota olisi voitu kutsua, voi rajoituksena olla mikä tahansa mahdollinen kutsukohta. Vaikka suoja onkin heikompi kuin hienorakeisessa CFI:ssä, tämä rajoittaa silti hyökkääjien liikkumavaraa merkittävästi ja ajonaikainen tarkistus on paljon nopeampi.
Nykyaikaisissa tietokoneissa jotkin CFI-muodot ovat (tai tulevat olemaan) jopa laitteiston tukemia. Esimerkiksi Intelin CET tukee varjopinoja paluiden eheyttä varten sekä epäsuorien haarautuminen seurantaa eteenpäin suuntautuvien siirtymien eheyttä varten — kumpaakin kuitenkin hyvin karkeajakoisella tavalla (CET = Control-flow Enforcement Technology). ARM-prosessori tarjoaa osoittimen todennusta estääkseen niiden peukalointia. Tämä tapahtuu lähinnä käyttämällä osoittimen ylimpiä bittejä tallentamaan osoittimen autentikointikoodi (pointer auth. code, PAC), joka toimii MACin tavoin osoittimen arvossa (vertailukohde MAC on siis msg. auth. code).
Valitettavasti CFI auttaa vain niitä hyökkäyksiä vastaan, jotka muuttavat kontrollivuota eli rämettävät paluuosoitteita, funktio-osoittimia tai hyppykohteita, mutta se on voimaton muunlaisia hyökkäyksiä vastaan. Se ei esimerkiksi voi estää muistin rämettämistä, jossa nykyisen prosessin käyttöoikeustaso nostetaan “rootiksi”(esim. asettamalla effective uid pääkäyttäjän tunnukseksi). Kun kontrollivuon rajoitukset ovat osoittautuneet hyviksi käytännössä, voi kysyä, ovatko vastaavat rajoitukset mahdollisia myös datan puolella. Vastaus on “kyllä, mutta”. Data-Flow Integrity, DFI määrittää staattisesti jokaiselle latauskäskylle (eli muistista lukevalle käskylle), mitkä tallentavat käskyt ovat voineet tuottaa kyseiset tiedot. Nämä käskyt varustetaan nimiöillä ja nimiöiden joukko tallennetaan. Ajon aikana pidetään tiedossa kullekin muistissa olevalle tavulle viimeisen siihen tallentaneen käskyn nimiö. Kun kohdataan latauskäsky, tarkistetaan, onko viimeinen tallennuskäsky kyseiseen osoitteeseen kirjoittavien laillisten tallennuskäskyjen joukossa, ja jos ei, annetaan hälytys. Toisin kuin CFI:tä, DFI:tä ei ole otettu laajalti käyttöön, ilmeisesti merkittävien suorituskykyvaikutusten vuoksi.
Osiointi (syventävä)¶
Käyttöjärjestelmät asettavat nykyään tiukan rajan koodin ja tiedon välille. Jokainen muistisivu on joko suoritettava tai kirjoitettava, mutta ei molempia samanaikaisesti. Käytäntö, jota usein kutsutaan nimellä W⊕X (write xor execute), estää siis käskyjen suorittamisen tietoalueelta ja olemassa olevan koodin muokkaamisen. Koodin injektointimahdollisuuden puuttuessa ohjelman kontrolloinnista kiinnostunut hyökkääjä joutuu käyttämään uudelleen jo olemassa olevaa koodia. Samanlaisia mekanismeja käytetään estämään arkojen tietojen (kuten systeemikutsujen ja keskeytysvektorien taulut jne.) muuttaminen ytimessä sen jälkeen kun ne on sinne alustettu. Kaikki suuret käyttöjärjestelmät tukevat tätä mekanismia, tyypillisesti soveltaen laitteistotukea (suorituksen estävä bitti prosessorissa), vaikka yksityiskohdat ja nimitykset vaihtelevat käyttöjärjestelmästä toiseen. Esimerkiksi Microsoftin toteutus on nimeltään Data Execution Prevention (DEP).
Aiemmassa luvussa nähtiin, miten käyttöjärjestelmät soveltavat CPU:n suojakehiä varmistaakseen, että käyttäjäprosessit eivät pääse käsiksi mielivaltaisiin tietoihin tai itsekseen suorittamaan koodia käyttöjärjestelmässä. Suojausta tarvitaan myös toisin päin, minkä uudet sivukanavahyökkäykset ovat osoittaneet (Meltdown, Spectre ym.). Aiemmin oli tehokkuussyistä käyttöjärjestelmän ydin yhdistetty jokaisen prosessin osoiteavaruuteen ja se suoritti systeemikutsut prosessin sivutaulujen avulla. Näin esim. Linux toimi tähän tapaan alusta eli vuodesta 1991 joulukuuhun 2017 asti (eli Meltdowniin asti). Koska ytimen omilla muistisivuilla on supervisor-bitti asetettuna, ei ollut eikä ole vaaraa, että käyttäjäprosessi pääsee käsiksi ytimen muistiin. Toisinpäin voi sivukanavien lisäksi olla vaarana ytimessä tapahtuva funktioviittauksen virhe, joka nollaa viittausosoitteen. Normaalisti osoitteessa nolla ei pitäisi olla koodia, mikä johtaa todennäköisesti “vain” ytimen kaatumiseen, mutta hyökkääjä on voinut - käyttäjätilassa kun ollaan - täyttää sen koodilla, joka muuttaa nykyisen prosessin oikeudet root-oikeuksiksi.
Jotta hyökkääjä ei pääsisi käyttäjätilan kautta syöttämään haitallisia tietoja ytimen käskyiksi ja jotta sivukanavia saataisiin suljetuksi, tarvitaan parempaa eristystä kuin suojauskehät tarjoavat. Monissa suorittimissa on nykyään tarjolla SMAP ja SMEP: Supervisor Mode Access ja Execution Protection. Ne otetaan käyttöön asettamalla oikeat bitit ohjausrekisteriin. Heti kun ne ovat päällä, kaikki yritykset käyttää (access) käyttäjän muistia tai siirtää kontrollia (execute) sinne johtavat sivuvirheeseen. Tietenkin tämä tarkoittaa myös sitä, että SMAP tulee kytkeä pois päältä aina, kun ydin tarvitsee pääsyn käyttäjän muistiin.
Vanhemmissa prosessoreissa, joissa Meltdown-haavoittuvuuden laitteistokorjaus ei ole mahdollinen, käyttöjärjestelmät, mm. Linux, erottavat ytimen sivutaulut täysin prosessien sivutauluista. Ydin voi silti viitata käyttäjäprosessin sivuihin tarvittaessa, mutta käyttöoikeudet voivat olla erilaisia. Erityisesti, jos ne on merkitty ei-suoritettaviksi, tuloksena on periaatteessa SMEP-ominaisuus. Muiden spekulatiiviseen suoritukseen perustuvien haavoittuvuuksien (kuten Spectre ja RIDL) osalta korjaus on ongelmallisempi. Vakavimpien ongelmien korjaamiseen voidaan käyttää useita erilaisia täsmäratkaisuja. Spekulointi voidaan esimerkiksi lopettaa kokonaan. Jotkin käyttöjärjestelmät, kuten Windows, soveltaa spekulointia vain koodiin samassa suojausalueessa ja samassa laskentaytimessä (core). Toiset, kuten OpenBSD jättää Intel-prosessoreiden hyperthreading-ominaisuuden kokonaan käyttämättä (2018-). Laitteiston uusiutumista odotellessa voi olla epäselvyyttä, kuinka riittäviä ja riittävästi täydentyviä tällaiset korjaukset ovat.
Kehittyneet sivukanavahyökkäykset perustuvat nykyaikaisten tietokonejärjestelmien aggressiiviseen resurssien jakamiseen. Useat suojausalueet jakavat saman välimuistin, saman TLB:n, saman haaranennustajan tilan, samat aritmeettiset yksiköt jne. Jakaminen on hyvä tehokkuuden kannalta, mutta kuten vähimmän yhteisen mekanismin periaate osoittaa, ne synnyttävät myös sivukanavia. Tällaisten hyökkäysten estämiseksi käyttöjärjestelmät saattavat joutua uhraamaan osan tehokkuudesta ja osioimaan resursseja hyvinkin hienojakoisesti. Esimerkiksi ohjelmisto- tai laitteistopohjaisen välimuistin allokointitekniikassa sivujen värjäyksellä käyttöjärjestelmä voi antaa eri prosesseille pääsyn välimuistin täysin erillisiin osiin. Valitettavasti osiointi ei aina ole yksinkertaista, eikä sitä tällä hetkellä ole tarjolla monille matalan tason resursseille.
Koodin ja tiedon eheystarkistukset (syventävä)¶
Yksi tapa vähentää haitallisen koodin mahdollisuuksia käyttöjärjestelmässä on varmistaa, että koodi ja/tai tiedot ovat muuttumattomia ja että ne ovat peräisin luotettavalta toimittajalta. Esimerkiksi Windows on useiden vuosien ajan käyttänyt ajureiden allekirjoittamista. Jotkin uudemmat versiot menevät pidemmälle ja ottavat ohjelmistosuojauksen rinnalle laitteiston, jolloin yhdistelmä lukitsee koneen siinä mielessä, että siinä pyörii vain luotettu koodi, sovellukset mukaan lukien. Tätä menettelyä Microsoft kutsuu nimellä Device Guard. Edes etuoikeutetut haittaohjelmat eivät voi helposti saada ei-valtuutettuja sovelluksia toimimaan, koska sallittavuuden tarkistava koneisto on laitteistoavusteisessa virtualisoidussa ympäristössä. Useimmat koodin allekirjoitusratkaisut kohdistuvat käyttöjärjestelmän laajennuksiin, jotka käyttöjärjestelmä siten tarkistaa eheiksi ja autenttisiksi. Samanlaista prosessia käytetään yleisesti päivityksiin.
Edellä sanottu vaikuttaa pätevältä, ja niin se onkin, mikäli luottamuksella on riittävä perusta. Luottamusankkurina (vrt. käsitekartta) on edellä koodi, joka tarkistaa allekirjoituksen, ja itse käyttöjärjestelmä. Miten voidaan tietää, ettei haitallinen bootkit ole peukaloinut niitä? Käynnistyksen aikana ladattavan järjestelmäohjelmiston eheyden varmistaminen sisältää useita vaiheita, jotka liittyvät useimmiten itse käynnistysprosessin vaiheisiin. Varhaisimmista kaupallisista tietokoneista lähtien käynnistys on ollut monivaiheinen. Jopa 1950-luvun alussa suosittu IBM 701 (niitä oli 19 kpl) käynnistettiin “Load”-painikkeella, jolloin järjestelmä luki yhden 36-bittisen sanan reikäkortilta. Osa tästä sanasta suoritettiin lisäkäskyjen lataamiseksi, ja saatiin käyntiin boot-ohjelma.
Turvallinen käynnistys alkaa luottamusankkurista (tai -juuresta), joka panee liikkeelle käynnistysprosessin ja perustuu tyypillisesti laitteistoon, esimerkiksi mikro-ohjaimeen. Se aloittaa ohjelmiston suorittamisen sisäisestä, muuttumattomasta muistista tai sisäisestä flash-muistista, jota ei voida ohjelmoida lainkaan uudelleen (tai mahdollisesti tiukoilla todennus- ja valtuutustarkastuksilla). Esimerkiksi nykyaikaisissa Apple-tietokoneissa on erillinen prosessori, T2 Security Chip, joka tarjoaa muun muassa turvallisen käynnistyksen laitteistojuuren. Google on kehittänyt samaan tarkoitukseen erityisprosessorin nimeltä Titan. Tarkastellaan nyt, miten laitteistopohjainen luottamus auttaa varmistamaan, että järjestelmä on käynnistynyt turvallisesti.
Yleiskäyttöisten tietokoneiden käynnistämisvaiheiden sarja alkaa tyypillisesti laiteohjelmistolla (firmware). Se voi esimerkiksi ladata erityisen käynnistyslatausohjelman (bootloader), joka lataa käyttöjärjestelmän ytimen, joka puolestaan voi ladata lisää käynnistysohjaimia, kunnes käyttöjärjestelmä on lopulta täysin alustettu ja valmis olemaan vuorovaikutuksessa käyttäjän tai sovellusten kanssa. Kaikki nämä vaiheet tarvitsevat suojaa. Esimerkiksi Unified Extensible Firmware Interface (UEFI) voi suojata ensimmäisen vaiheen Secure Bootin avulla. Secure Boot tarkistaa, onko käynnistyslatain allekirjoitettu asianmukaisella avaimella, eli sellaisella joka vastaa laiteohjelmistoon tallennettua avaintietoa. Käynnistyslatain voi nyt tarkistaa käyttöjärjestelmän ytimen digitaalisen allekirjoituksen ennen sen lataamista. Seuraavaksi ydin tarkistaa kaikki muut käyttöjärjestelmän osat, kuten käynnistysohjaimet ja mahdollisesti integroidut haittaohjelmien torjuntaohjelmistot, ennen niiden käynnistämistä. Käynnistämällä haittaohjelmien torjuntaohjelman ennen muita ohjaimia, se voi myöhemmin tarkistaa kaikki nämä myöhemmät komponentit ja laajentaa luottamusketjun täysin alustettuun käyttöjärjestelmään asti.
Joko nyt on kone turvallisesti käynnissä? Voi olla, mutta voidaanko siitä vakuuttua, erityisesti etäyhteyden päässä? Voidaan käyttää todistusta (attestation), jolla etäosapuoli voi havaita järjestelmään tehdyt muutokset. Todistus käyttää tyypillisesti erikoislaitteistoa, kuten TPM-moduulia (Trusted Platform Module), joka toimii luottamuksen juurena ja sisältää vaiheittain sen tarkistamisen, onko järjestelmään ladattu “oikea” ohjelmisto. TPM on kryptografinen laitteistomoduuli, joka tukee useita salaustoimintoja, avainten luomista ja hallintaa, turvallista tallennusta (esim. avaimille ja muille turvallisuuden kannalta arkaluonteisille tiedoille) ja mikä tärkeintä, eheysmittauksia. TPM on esillä myös laitteistoa käsittelevässä luvusssa.
Eheyden todistamiseksi TPM voisi toimittaa verifioijalle kryptografiset tiivisteet (hash-arvot) kaikista käynnistyksen eri vaiheissa ladatuista ohjelmamoduuleista. Verifioija vertaa oikeiden eli luotettujen moduulien tiivisteisiin. Vähempikin viestintä riittää: TPM muodostaa eri vaiheiden sille toimittamista tiivisteistä ketjun. Sen TPM lopuksi allekirjoittaa yksityisellä avaimellaan (Attestation Identity Key), joka ei koskaan poistu TPM:stä ja on peräisin valmistusvaiheessa luodusta kovakoodatusta avaimesta. Eheystodistusta varten TPM:ssä on joukko PCR-rekistereitä, jotka asetetaan tunnettuun arvoon jokaisessa käynnistyksessä (Platform Configuration Registers). Tällaiseen rekisteriin TPM muodostaa käynnistyksen hash-ketjun: jos rekisterin nykyinen arvo on X ja sinne pitäisi kirjoittaa uuden moduulin tiiviste Y, TPM laskee tiivistearvon hash(X,Y) ja tallentaa rekisteriin tämän. Käynnistysprosessia etäältä todistava osapuoli lähettää satunnaisluvun, noncen, ja saa TPM:ltä sen ja PCR-arvon perusteella lasketun ja allekirjoitetun vastauksen. Tällöin todistaja tietää, että vastaus tuli TPM:stä ja että se oli tuore. Ketjua seuraamalla, siis tiivisteitä itse laskemalla, todistaja voi tarkistaa, että koodi oli oikea kaikissa vaiheissa.
Koodin ja tietojen eheyden tarkistus saattaa jatkua ajon aikana. Esimerkiksi hypervisor voi tarjota toiminnallisuuden suorittaa virtuaalikoneidensa itsetestauksen: onko koodi edelleen sama, ovatko tietorakenteet edelleen oikeanlaisia? Tämä tekniikka tunnetaan nimellä Virtual Machine Introspection (VMI). VMI-toiminnallisuus voi sijaita hypervisorissa tai se voi olla erillisessä sovelluksessa. Koodin lisäksi VMI-ratkaisuissa yleisiä tarkistettavia asioita ovat prosessiluettelo (yrittääkö jokin rootkit piiloutua?), systeemikutsutaulukko (kaappaako joku tiettyjä järjestelmäkutsuja?), keskeytysvektorit (eli keskeytysten käsittelijöiden osoitteet) jne.
Poikkeavuuksien havaitseminen (syventävä)¶
Monitoria, olipa se sitten hypervisorissa tai käyttöjärjestelmässä, voidaan käyttää myös valvomaan järjestelmää epätavallisten tapahtumien varalta (anomaly detection, vrt. myös aiempi luku). Esimerkiksi järjestelmä, joka kaatuu satoja kertoja peräkkäin, voi olla joutunut osoiteavaruuden satunnaisuutta arvailevan hyökkäyksen kohteeksi. Tietenkin päätelmä olisi vain epäsuora. Poikkeamien havaitsemisjärjestelmien on löydettävä tasapaino liian monien väärien hälytysten ja liian harvojen hälytysten välillä.