Mikrodroid

Microdroid to mini-Android system operacyjny działający w maszynie pVM. Nie musisz używać Microdroid, możesz uruchomić maszynę wirtualną z dowolnym systemem operacyjnym. Jednak głównymi przypadkami użycia maszyn pVM nie jest uruchamianie samodzielnego systemu operacyjnego, ale raczej oferowanie izolowanego środowiska wykonawczego do uruchamiania części aplikacji z silniejszymi gwarancjami poufności i integralności niż może zapewnić Android.

W przypadku tradycyjnych systemów operacyjnych zapewnienie dużej poufności i integralności wymaga sporo pracy (często powielanej), ponieważ tradycyjne systemy operacyjne nie pasują do nadrzędnej architektury Androida. Na przykład w przypadku standardowej architektury Androida programiści muszą wdrożyć sposób bezpiecznego ładowania i wykonywania części aplikacji w maszynie pVM, a ładunek jest zbudowany w oparciu o bibliotekę glibc. Aplikacja na Androida korzysta z Bionic, komunikacja wymaga niestandardowego protokołu poprzez vsock, a debugowanie za pomocą adb jest wyzwaniem.

Microdroid wypełnia te luki, dostarczając gotowy obraz systemu operacyjnego zaprojektowany tak, aby wymagał od programistów jak najmniejszego wysiłku przy przeładowywaniu części aplikacji na maszynę pVM. Kod natywny jest zbudowany na Bionic, komunikacja odbywa się za pośrednictwem Bindera i umożliwia importowanie plików APEX z Androida i udostępnia podzbiór API Androida, taki jak magazyn kluczy do operacji kryptograficznych z kluczami wspieranymi sprzętowo. Ogólnie rzecz biorąc, programiści powinni uznać Microdroid za znajome środowisko z narzędziami, do których przywykli w pełnym systemie operacyjnym Android.

Cechy

Microdroid to uproszczona wersja Androida z kilkoma dodatkowymi komponentami specyficznymi dla maszyn pVM. Mikrodroid obsługuje:

  • Podzbiór interfejsów API NDK (dostępne są wszystkie interfejsy API dla implementacji bibliotek libc i Bionic w systemie Android)
  • Funkcje debugowania, takie jak adb, logcat, tombstone i gdb
  • Zweryfikowany rozruch i włączony SELinux
  • Ładowanie i wykonywanie pliku binarnego wraz z bibliotekami współdzielonymi osadzonymi w pliku APK
  • Binder RPC przez vsock i wymiana plików z niejawną kontrolą integralności
  • Ładowanie APEXów

Microdroid nie obsługuje:

  • Interfejsy API Java systemu Android w pakietach android.\*

  • SystemServer i Zygota

  • Grafika/interfejs

  • HAL

Architektura mikrodroidów

Microdroid jest podobny do mątwy pod tym względem, że oba mają architekturę podobną do standardowego Androida. Microdroid składa się z następujących obrazów partycji zgrupowanych w złożony obraz dysku:

  • bootloader – sprawdza i uruchamia jądro.
  • boot.img - Zawiera jądro i dysk startowy.
  • vendor_boot.img — zawiera moduły jądra specyficzne dla maszyny wirtualnej, takie jak virtio.
  • super.img — składa się z partycji logicznych systemowych i logicznych dostawcy.
  • vbmeta.img — zawiera zweryfikowane metadane rozruchowe.

Obrazy partycji są dostarczane w pakiecie Virtualization APEX i pakowane w złożony obraz dysku przez VirtualizationService . Oprócz głównego obrazu dysku złożonego systemu operacyjnego VirtualizationService jest odpowiedzialna za utworzenie następujących innych partycji:

  • payload — zestaw partycji obsługiwanych przez pliki APEX i APK systemu Android
  • instance — zaszyfrowana partycja do przechowywania zweryfikowanych danych rozruchowych dla każdej instancji, takich jak sól dla instancji, zaufane klucze publiczne APEX i liczniki wycofania

Sekwencja rozruchowa

Sekwencja rozruchowa Microdroid ma miejsce po uruchomieniu urządzenia . Uruchamianie urządzenia zostało omówione w dokumencie Architektury . Rysunek 1 pokazuje kroki, które mają miejsce podczas sekwencji rozruchowej Microdroid:

Bezpieczny przepływ rozruchowy instancji microdroid

Rysunek 1. Bezpieczny przepływ rozruchowy instancji microdroid

Oto wyjaśnienie poszczególnych kroków:

  1. Program ładujący jest ładowany do pamięci przez crosvm i rozpoczyna wykonywanie pvmfw. Przed skokiem do bootloadera pvmfw wykonuje dwa zadania:

    • Weryfikuje program ładujący, aby sprawdzić, czy pochodzi z zaufanego źródła (Google lub OEM).
    • Zapewnia, że ​​ten sam program ładujący będzie konsekwentnie używany podczas wielu rozruchów tej samej maszyny pVM dzięki wykorzystaniu obrazu instancji. W szczególności maszyna pVM jest początkowo uruchamiana z pustym obrazem instancji. pvmfw przechowuje tożsamość programu ładującego w obrazie instancji i szyfruje go. Zatem następnym razem, gdy pVM zostanie uruchomiona z tym samym obrazem instancji, pvmfw odszyfruje zapisaną tożsamość z obrazu instancji i sprawdzi, czy jest to ta sama tożsamość, która została zapisana wcześniej. Jeśli tożsamości się różnią, pvmfw odmawia uruchomienia.

    Następnie program ładujący uruchamia Microdroid.

  2. Program ładujący uzyskuje dostęp do dysku instancji. Podobnie jak pvmfw, program ładujący posiada dysk instancji zawierający informacje o obrazach partycji używanych w tej instancji podczas poprzednich rozruchów, w tym o kluczu publicznym.

  3. Program ładujący weryfikuje vbmeta i powiązane partycje, takie jak boot i super , i jeśli się powiedzie, wyprowadza sekrety pVM następnego etapu. Następnie Microdroid przekazuje kontrolę jądru.

  4. Ponieważ super partycja została już zweryfikowana przez program ładujący (krok 3), jądro bezwarunkowo montuje super partycję. Podobnie jak w przypadku pełnego systemu Android, super partycja składa się z wielu partycji logicznych zamontowanych na platformie dm-verity. Następnie kontrola jest przekazywana procesowi init , który uruchamia różne usługi natywne. Skrypt init.rc jest podobny do tego z pełnego Androida, ale dostosowany do potrzeb Microdroid.

  5. Proces init uruchamia menedżera Microdroid, 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 wycofania plików APK i APEX klienta, którym ufa ta pVM. Informacje te są później wykorzystywane przez zipfuse i apexd , gdy montują odpowiednio plik APK klienta i żądane pliki APEX.

  6. Usługa menedżera Microdroid uruchamia się apexd .

  7. apexd montuje APEXy w katalogach /apex/<name> . Jedyna różnica między sposobem montowania APEXów w systemie Android i Microdroid polega na tym, że w Microdroid pliki APEX pochodzą z wirtualnych urządzeń blokowych ( /dev/vdc1 , …), a nie ze zwykłych plików ( /system/apex/*.apex ).

  8. zipfuse to system plików FUSE firmy Microdroid. zipfuse montuje plik APK klienta, który jest zasadniczo plikiem Zip jako systemem plików. Poniżej 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ą plików APEX, których zażądał twórca aplikacji dla tej instancji pVM. Lista jest używana przez apexd podczas aktywacji APEXów.

  9. Przepływ rozruchu powraca do usługi menedżera Microdroid. Usługa menedżera komunikuje się następnie z VirtualizationService systemu Android za pomocą Binder RPC, dzięki czemu może raportować ważne zdarzenia, takie jak awaria lub zamknięcie, i akceptować żądania, takie jak zakończenie pVM. Usługa menedżera odczytuje lokalizację głównego pliku binarnego z pliku konfiguracyjnego APK i wykonuje go.

Wymiana plików (AuthFS)

Komponenty Androida często korzystają z plików 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 udostępnia podobną funkcjonalność do wymiany plików pomiędzy wzajemnie nieufnymi punktami końcowymi ponad granicami pVM.

Zasadniczo AuthFS to zdalny system plików z przejrzystymi kontrolami integralności poszczególnych operacji dostępu, podobny do fs-verity . Kontrole pozwalają frontendowi, np. programowi do odczytu plików działającemu w maszynie pVM, wykryć, czy niezaufany backend, zazwyczaj system Android, manipuluje zawartością pliku.

Aby wymieniać pliki, uruchamiany jest backend ( fd\_server ) z konfiguracją dla każdego pliku, określającą, czy jest on przeznaczony do wejścia (tylko do odczytu), czy do wyjścia (odczyt i zapis). W przypadku danych wejściowych frontend wymusza zgodność zawartości ze znanym skrótem na szczycie drzewa Merkle w celu weryfikacji podczas uzyskiwania dostępu. W przypadku danych wyjściowych AuthFS wewnętrznie utrzymuje drzewo skrótów zawartości zaobserwowanej podczas operacji zapisu i może wymusić integralność podczas ponownego odczytywania danych.

Podstawowy transport jest obecnie oparty na Binder RPC, jednak może się to zmienić w przyszłości, aby zoptymalizować wydajność.

Zarządzanie kluczami

Maszyny pVM są wyposażone w stabilny klucz plombujący , odpowiedni do chronionych, trwałych danych, oraz klucz zaświadczający , który nadaje się do tworzenia podpisów, które można zweryfikować, wytwarzanych przez pVM.

Spoiwo RPC

Większość interfejsów Androida jest wyrażona w formacie AIDL , który jest zbudowany na bazie sterownika jądra Binder Linux. Aby obsługiwać interfejsy między maszynami pVM, protokół Binder został przepisany tak, aby działał na gniazdach, a w przypadku maszyn pVM vsock . Obsługa gniazd umożliwia wykorzystanie istniejących interfejsów AIDL systemu Android w tym nowym środowisku.

Aby skonfigurować połączenie, jeden punkt końcowy, taki jak ładunek pVM, tworzy obiekt RpcServer , rejestruje obiekt główny i rozpoczyna nasłuchiwanie nowych połączeń. Klienci mogą połączyć się z tym serwerem za pomocą obiektu RpcSession , uzyskać obiekt Binder i używać go dokładnie w taki sam sposób, w jaki obiekt Binder jest używany ze sterownikiem Binder jądra.