Microdroid to miniwersja systemu Android działająca na maszynie pVM. Nie musisz używać Microdroida. Możesz uruchomić maszynę wirtualną z dowolnym systemem operacyjnym. Głównym zastosowaniem pVM nie jest jednak uruchamianie samodzielnego systemu operacyjnego, ale raczej oferowanie odizolowanego środowiska wykonawczego do uruchamiania części aplikacji z większymi gwarancjami poufności i integralności niż te, które może zapewnić Android.
W przypadku tradycyjnych systemów operacyjnych zapewnienie wysokiego poziomu poufności i integralności wymaga sporo pracy (często powielanej), ponieważ tradycyjne systemy operacyjne nie pasują do ogólnej architektury Androida. Na przykład w przypadku standardowej architektury Androida deweloperzy muszą wdrożyć sposób bezpiecznego wczytywania i wykonywania części aplikacji w pVM, a ładunek jest tworzony na podstawie glibc. Aplikacja na Androida korzysta z biblioteki Bionic, komunikacja wymaga niestandardowego protokołu przez vsock, a debugowanie za pomocą adb jest trudne.
Microdroid wypełnia te luki, udostępniając gotowy obraz systemu operacyjnego, który wymaga od deweloperów minimalnego wysiłku, aby przenieść część aplikacji do pVM. Kod natywny jest tworzony na podstawie Bionic, komunikacja odbywa się za pomocą Binder, a kod ten umożliwia importowanie pakietów APEX z Androida hosta i udostępnia podzbiór interfejsu API Androida, np. magazyn kluczy do operacji kryptograficznych z użyciem kluczy obsługiwanych przez sprzęt. Ogólnie rzecz biorąc, deweloperzy powinni uznać Microdroida za znane środowisko z narzędziami, do których przywykli w pełnej wersji systemu Android.
Funkcje
Microdroid to uproszczona wersja Androida z kilkoma dodatkowymi komponentami przeznaczonymi dla maszyn wirtualnych z ochroną. Microdroid obsługuje:
- Podzbiór interfejsów NDK API (wszystkie interfejsy API implementacji biblioteki libc i Bionic na Androidzie)
- Funkcje debugowania, takie jak adb, logcat, tombstone i gdb
- Weryfikacja podczas uruchamiania i SELinux
- Wczytywanie i wykonywanie pliku binarnego wraz z bibliotekami współdzielonymi osadzonymi w pliku APK
- Binder RPC przez vsock i wymiana plików z niejawnymi kontrolami integralności
- Wczytywanie pakietów APEX
Microdroid nie obsługuje:
Interfejsy Android Java API w pakietach
android.\*
SystemServer i Zygote
Grafika/UI
HAL
Architektura Microdroida
Microdroid jest podobny do Cuttlefish, ponieważ oba mają architekturę podobną do standardowego Androida. Mikrodroid składa się z tych obrazów partycji zgrupowanych w obrazie dysku kompozytowego:
bootloader
– weryfikuje i uruchamia jądro.boot.img
– zawiera jądro i dysk RAM z inicjalizacją.vendor_boot.img
– zawiera moduły jądra specyficzne dla maszyny wirtualnej, takie jak virtio.super.img
– składa się z partycji logicznych systemu i dostawcy.vbmeta.img
– zawiera metadane weryfikacji podczas uruchamiania.
Obrazy partycji są dostarczane w pakiecie Virtualization APEX i pakowane w złożony obraz dysku przez VirtualizationService
. Oprócz głównego obrazu dysku kompozytowego systemu operacyjnego VirtualizationService
odpowiada za utworzenie tych innych partycji:
payload
– zestaw partycji obsługiwanych przez pakiety APEX i APK na Androidzie.instance
– zaszyfrowana partycja do przechowywania zweryfikowanych danych uruchamiania poszczególnych instancji, takich jak sól poszczególnych instancji, zaufane klucze publiczne APEX i liczniki wycofywania zmian.
Sekwencja uruchamiania
Sekwencja uruchamiania Microdroida następuje po uruchomieniu urządzenia. Proces uruchamiania urządzenia jest omówiony w sekcji Oprogramowanie układowe pVM w dokumencie Architektura. Ilustracja 1 przedstawia kroki, które są wykonywane podczas sekwencji uruchamiania Microdroida:
Wyjaśnienie poszczególnych kroków:
Program rozruchowy jest wczytywany do pamięci przez crosvm, a pvmfw zaczyna wykonywać instrukcje. Przed przejściem do programu rozruchowego pvmfw wykonuje 2 zadania:
- Weryfikuje program rozruchowy, aby sprawdzić, czy pochodzi z zaufanego źródła (Google lub producenta OEM).
- Zapewnia, że ten sam program rozruchowy jest używany konsekwentnie w przypadku wielu uruchomień tej samej maszyny pVM dzięki użyciu obrazu instancji. W szczególności pVM jest początkowo uruchamiana z pustym obrazem instancji. pvmfw przechowuje tożsamość programu ładującego w obrazie instancji i szyfruje ją. Dlatego przy następnym uruchomieniu maszyny wirtualnej z tym samym obrazem instancji pvmfw odszyfruje zapisaną tożsamość z obrazu instancji i sprawdzi, czy jest ona taka sama jak wcześniej zapisana. Jeśli tożsamości się różnią, pvmfw odmawia uruchomienia.
Następnie program rozruchowy uruchamia Microdroida.
Program rozruchowy uzyskuje dostęp do dysku instancji. Podobnie jak w przypadku pvmfw, program rozruchowy ma dysk instancji z informacjami o obrazach partycji używanych w tej instancji podczas poprzednich uruchomień, w tym klucz publiczny.
Program rozruchowy weryfikuje vbmeta i połączone partycje, takie jak
boot
isuper
, a jeśli weryfikacja się powiedzie, uzyskuje tajne klucze pVM następnego etapu. Następnie Microdroid przekazuje kontrolę nad jądrem.Ponieważ partycja nadrzędna została już zweryfikowana przez program rozruchowy (krok 3), jądro bezwarunkowo montuje partycję nadrzędną. Podobnie jak w przypadku pełnej wersji Androida, partycja nadrzędna składa się z wielu partycji logicznych zamontowanych na dm-verity. Sterowanie jest następnie przekazywane do procesu
init
, który uruchamia różne usługi natywne. Skryptinit.rc
jest podobny do skryptu pełnej wersji Androida, ale dostosowany do potrzeb Microdroida.Proces
init
uruchamia menedżera Microdroida, który uzyskuje dostęp do obrazu instancji. Usługa menedżera Microdroid odszyfrowuje obraz za pomocą klucza przekazanego z poprzedniego etapu i odczytuje klucze publiczne oraz liczniki wycofywania klienta APK i APEX-ów, którym ta pVM ufa. Te informacje są później wykorzystywane przezzipfuse
iapexd
podczas montowania odpowiednio pakietu APK klienta i żądanych pakietów APEX.Usługa menedżera Microdroida rozpoczyna się
apexd
.apexd
montuje pakiety APEX w katalogach/apex/<name>
. Jedyna różnica między sposobem montowania pakietów APEX w Androidzie i Microdroidzie polega na tym, że w Microdroidzie pliki APEX pochodzą z wirtualnych urządzeń blokowych (/dev/vdc1
, …), a nie ze zwykłych plików (/system/apex/*.apex
).zipfuse
to system plików FUSE Microdroida.zipfuse
montuje pakiet APK klienta, który jest w zasadzie plikiem ZIP jako system plików. Plik APK jest przekazywany jako wirtualne urządzenie blokowe przez pVM z dm-verity, tak samo jak APEX. Plik APK zawiera plik konfiguracyjny z listą pakietów APEX, o które deweloper aplikacji poprosił w przypadku tej instancji pVM. Lista jest używana przezapexd
podczas aktywowania pakietów APEX.Proces rozruchu wraca do usługi menedżera Microdroida. Usługa menedżera komunikuje się następnie z
VirtualizationService
na Androidzie za pomocą Binder RPC, aby zgłaszać ważne zdarzenia, takie jak awaria lub wyłączenie, i przyjmować żądania, np. zakończenie działania pVM. Usługa menedżera odczytuje lokalizację głównego pliku binarnego z pliku konfiguracyjnego APK i go wykonuje.
Wymiana plików (AuthFS)
Komponenty Androida często używają plików jako danych wejściowych, wyjściowych i stanu oraz przekazują je jako deskryptory plików (typ ParcelFileDescriptor
w AIDL) z dostępem kontrolowanym przez jądro Androida. AuthFS ułatwia podobną funkcję wymiany plików między wzajemnie nieufającymi sobie punktami końcowymi w różnych chronionych maszynach wirtualnych.
AuthFS to zdalny system plików z przejrzystymi kontrolami integralności
poszczególnych operacji dostępu, podobny do fs-verity
. Sprawdzanie umożliwia interfejsowi, np. programowi do odczytywania plików działającemu w pVM, wykrycie, czy niezaufany backend, zwykle Android, nie manipulował zawartością pliku.
Aby wymieniać pliki, uruchamia się backend (fd\_server
) z konfiguracją poszczególnych plików, która określa, czy plik jest przeznaczony do danych wejściowych (tylko do odczytu) czy wyjściowych (do odczytu i zapisu). W przypadku danych wejściowych interfejs egzekwuje, aby zawartość pasowała do znanego skrótu, oprócz drzewa Merkle’a do weryfikacji dostępu. W przypadku danych wyjściowych AuthFS wewnętrznie utrzymuje drzewo skrótów zawartości obserwowanej podczas operacji zapisu i może wymuszać integralność podczas odczytywania danych.
Podstawowy transport jest obecnie oparty na Binder RPC, ale w przyszłości może się to zmienić w celu optymalizacji wydajności.
Zarządzanie kluczami
pVM są wyposażone w stabilny klucz szyfrujący, który nadaje się do ochrony danych trwałych, oraz klucz atestacyjny, który nadaje się do tworzenia podpisów, które można zweryfikować jako wygenerowane przez pVM.
Binder RPC
Większość interfejsów Androida jest wyrażona w języku AIDL, który jest oparty na sterowniku jądra systemu Linux Binder. Aby obsługiwać interfejsy między pVM, protokół Binder został przepisany tak, aby działał na gniazdach, w przypadku pVM – na vsock. Działanie na gniazdach umożliwia korzystanie w tym nowym środowisku z dotychczasowych interfejsów AIDL Androida.
Aby skonfigurować połączenie, jeden z punktów końcowych, np. ładunek pVM, tworzy obiekt RpcServer
, rejestruje obiekt główny i zaczyna nasłuchiwać nowych połączeń. Klienci mogą połączyć się z tym serwerem za pomocą obiektu RpcSession
, pobrać obiekt Binder
i używać go dokładnie tak, jak obiektu Binder
używa się z sterownikiem Binder jądra.