Hlavní navigace

KVM pro Android přinese sjednocení mobilní virtualizace

11. 12. 2020
Doba čtení: 7 minut

Sdílet

Zmatek, který je v architektuře Androidu co se týče úrovní oprávnění a využití virtualizace se výhledové chýlí ke konci. Vydělá na tom i KVM, do nějž míří mnohé patche.

KVM pro Android

Google má v běhu vývojářský projekt, jehož cílem je přinést kernelový virtualizační mechanismus Linuxu přímo do Androidu. Šéfem projektu je Will Deacon, který se nově objevil na KVM Forum, aby vše diskutoval s komunitou a také před pár týdny shrnul aktuální vývoj v prezentaci (pdf). Jak cíle projektu, tak výzvy, které po cestě přijdou. Protože narozdíl od jiných androidích projektů minulosti, tento „protected KVM“ je realizován jako otevřený, s kódem, který bude směřovat do upstreamu, tedy přímo do linuxového jádra.

Volba Willa Deacona za šéfa týmu v Googlu nebyla náhodná. Jde o vývojáře, který pracuje na ARM64 architektuře v jádru a jako maintainer a contributor přispívá i v dalších částech Linuxu (concurrency, zamykání, atomické operace, nástroje pro kernel memory model, …). Na kernelu zkrátka nechal nemálo práce, ale zatím ne zrovna na KVM. Nejblíže této části jádra je jeho udržování ovladačů ARM IOMMU. V týmu Android Systems pak v Googlu pracuje teprve od roku 2019.

KVM projekt v Googlu je mimochodem pro poslední jádra Linux 5.9 a 5.10 největším přispěvatelem do části týkající se KVM pro ARM. Will k tomu dodává, že KVM je nyní zkrátka horké téma, a to ne pouze pro ARM. Důvodem, proč je práce průběžně hrnuta přímo do upstreamu je jednoduchý: Will by se s kolegy rádi vyhnuli tomu, že by dělali velké balíky kódu mimo hlavní strom jádra a následně je tam házeli najednou. To linuxová komunita vidí nerada.

Pozadí Androidu

Google se snaží v posledních letech platformu Android trochu sjednotit. Už nechce doby, kdy každý jednotlivý smartphone nesl nějakou svoji modifikaci kernelu, nějakou konkrétní verzi a platforma jako celek tak byl jeden obrovský chaos dílčích verzí jádra. Poslední vývoj tedy Google směřuje k tzv. generic kernel image (GKI), který má srazit fragmentaci jádra v Androidu na minimum.

Právě ona roztříštěnost stála zčásti za tím, že nebylo možné věnovat dostatek pozornosti konkrétním verzím (protože každá jednotlivá byla zkrátka jednou z myriády verzí). Tento model nebyl ve svém důsledku vhodný ani pro upstream jádro. Daleko lepší by pro Android bylo mít jedno konkrétní jádro z hlavní větve, které nese ty správné verze subsystémů a abstrakcí a je schopné podporovat širokou škálu zařízení. Ale to nelze realizovat, dokud vývojáři nebudou mít vhled do jednotlivých rozdílných problémů a jejich řešení, které provoz takového jádra na různých typech platforem přináší. A ten nebudou mít, dokud bude všemožné dílčí modifikace jádra rozesety ve všemožných dílčích odvozenin, které se v zařízeních používají. Dokud se toto nesjednotí, těžko budou moci vývojáři psát nové věci natolik obecně, že budou fungovat všude.

Proto je zde GKI jako mechanismus, který vždy sváže konkrétní verzi Androidu s konkrétní verzí jádra. Udržovat se bude omezený subset modulových ABI jakožto stabilní rozhraní této verze a výrobci zařízení si budou moci vytvářet pro tuto verzi moduly ovladačů, které budou fungovat dál a dál díky tomu, že jádro bude LTS a bude dostávat i bezpečnostní aktualizace. Právě stížnosti vývojářů na neudržování ABI s vývojem kernelu jsou tím, co Androidí tým Googlu slyší nejhlasitěji.

Virtualizace na Androidu dnes

Současná situace kolem hypervizoru na Androidu je kulantně řečeno chaotická. Will dokonce přímo tvrdí, že pokud považujeme fragmentaci v oblasti kernelu za špatnou, tak virtualizace je na tom ještě o hodně, hodně, hodně hůř. Nejenže různá zařízení mají různé verze hypervizoru, ale ona ho mnohá nemají vůbec, resp. pokud jej mají, používají jej často k různým účelům. Prostě divoký západ, dodává Will.

Jedním z nich je využití k vylepšení zabezpečení systémů. To ale často naopak zavádí další možnost útoku na systém a připomíná zápisek Janna Horna z Project Zero. Hypervizor běží se zvýšenými oprávněními a to je samo o sobě v případě existence chyb rizikem.

Další využití je pro tzv. coarse-grained partitioning paměti, což je trošičku podobné IOMMU. Používá se to při spuštění systému k rozsekání paměti na oblasti, které jsou pak předány rozličným zařízením pro DMA přístup apod. Will sice chápe, proč toto někteří používají, ale přijde mu to jako tak trochu plýtvání.

Nakonec tu mám použití hypervisorů na Androidu pro běh kódu mimo Android samotný. Tohle Will nemá rád vůbec nejvíc ze všeho. ARMv8 má vícero úrovní oprávnění nazývaných exception levels, které jdou od nejvíce privilegovaného firmware (EL3), přes hypervisor (EL2) až po operační systém (EL1) a nakonec úroveň privilegovaného uživatele (EL0). Úroveň hypervizoru není firmwarová, takže výrobci zařízení se nemusejí až tolik hlídat, aby ze zařízení neudělali cihlu nějakou softwarovou chybou. Stejně tak nejde o úroveň operačního systému, takže zde běžící kód nemusí mít dobrou integraci se svým okolím. Takže se často stává, že kód, který se jinam nedá nasadit, se prostě strčí do virtualizace, což je opravdu špatné s ohledem na to, jaká oprávnění hypervizor může nabývat.

V hypervizorech ani neběhají žádné virtuální stroje, takže se zde tak trochu plýtvá potenciálem a dochází ke snížení jako celkově funkcionality, tak zejména bezpečnosti jako takové. Funkcionalita je omezena tím, že k virtualizaci není obecný přístup ze samotného Androidu a bezpečnost je narušena právě onou výše zmíněnou fragmentací znemožňující rozumné obecné aktualizace.

Will by se svým týmem rád Androidu, resp. aplikacím třetích stran běžícím s určitými, zbytečně nadstandardními privilegii, tato privilegia omezil a k tomu je potřeba přenositelné prostředí, které může hostovat různé služby způsobem, kdy jsou izolovány od zbytku Androidu. Stejnou cestou pak půjde izolovat i jednotlivé programy od sebe.

Nasazení KVM

Cestou, jak toho dosáhnout, je přesun důvěryhodného kódu do virtuálního stroje na stejné úrovni jakou má samotný Android. Kód třetích stran by pak neměl vyšší (ani nižší) důvěru než Android samotný. Ale chce to míti v Androidu hypervizor, který by se o tyto virtuální stroje z hlediska provozu staral. Idea je taková: použít GKI k uvedení KVM do systému a s jeho pomocí zbavit aplikace třetích stran příliš vysokých privilegií.

Všechna zařízení s ARM64 a Androidem mají podporu virtualizace v hardwaru a mají dvoustupňovou MMU, která umí rozdělování paměti na oddíly, takže host nemůže mimo svůj region paměti. KVM je podporováno pro ARM64 od jádra Linux 3.11 (léta páně 2013). SoC podporují dva základní módy. Ty starší umí non-VHE (nVHE), novější odpovídající architektuře ARMv8.1 umí Virtualization Host Extensions (VHE).

V prvním starším režimu jak hostitel, tak host, běží oba s oprávněními na úrovni operačního systému (EL1). Sekunduje jim virtual machine monitor (VMM) běžící na úrovni hypervizoru, tedy EL2. Protože samotný hostitel nemá dostatek privilegií k přepínání mezi hosty, musí to pro něj dělat právě VMM. A proto je starší režim nVHE pomalejší.

Novější verze VME umožňuje EL2 programům menší omezení, takže hostující kernel může běžet přímo na EL2 a sám obsluhovat hosty na úrovni EL1. To je výrazně rychlejší, nicméně tento režim není plně kompatibilní s modelem hrozeb u Androidu. Hostující kernel má vlastně přístup k paměti všech hostů a vlastně staví celý model na hlavu a tudíž samotný Android může být v privilegované pozici, což není žádoucí.

Představovaný bezpečnostní model Androidu vyžaduje, aby data hostů byla privátní i když bude kompromitován hostitelský kernel. A KVM používající VHE tohle neumí. Není to samozřejmě problémem pro starší verzi nVHE – to je možná lepší cesta, protože staší důvěřovat pouze onomu přepínači na úrovni EL2, nikoli celému hostitelskému kernelu.

Když ale od těchto úvah odbočíme, tak další možností je virtualizovat celý Android. To by nebylo špatné, ale Will dodává, že si nemyslí, že by to bylo nějak viditelně lepší. Tato metoda by přinesla jiné výzvy k řešení. Problémy by vyvstaly například u latencí u přerušení. Také je potřeba zachovat nějakou průchozí cestu zařízení (device pass-through) a podle Willa tohle ARM IOMMU v současné chvíli nezvládají dobře.

Otevřené problémy

Zkrátka problémů k řešení je zatím stále dost. Nicméně většina z nich se ve výsledku týká toho, jak je nakládáno s virtuální pamětí, jak probíhá její správa. Dnes je to tak, že hostitelský kernel je tím, kdo ovládá virtuální paměť hypervizoru.

Root tip

Stage-1 mapování paměti vytváří hostitelský kernel, který tak může měnit tabulky stránek hypervizoru „pod zadkem“ a stejně tak může zapisovat do libovolné paměti hypervizoru. I tabulky stránek na stage-2 jsou spravovány hostitelským kernelem. A když na EL2 proběhne přepnutí hosta, jen se slepě nainstalují tyto tabulky s důvěrou v to, že hostitel dělá správnou věc. Toto a některé další (popora IOMMU, přesun kódu pro nakládání s tabulkami stránek do EL2, …) jsou věci, které se musí změnit.

Protected KVM project už má nějaké patche, které cílí na vydání jádra Linux 5.11 a mění nakládání s tabulkami stránek. Některé z nich už jsou dokonce v Linuxu 5.10 (např. tabulky stránek pro fault handling a per-CPU data handling). Projekt dále adaptuje Chrome OS VMM (crosvm) jako své VMM. Crosvm (napsané mimochodem v Rustu) je již zahrnuto v Android open-source project (AOSP), přináší sebou spoustu virtio zařízení a dobrou mezi-architekturovou podporu. Ale to jsou vlastně vše jen první malé i velké stavební kameny, práce je ještě jak na kostele. Nicméně pokud bude jednoho dne úsilí završeno úspěchem, bude Android zase o něco bezpečnější platformou.

Autor článku

Příznivec open-source rád píšící i o ne-IT tématech. Odpůrce softwarových patentů a omezování občanských svobod ve prospěch korporací.