Google przepisało oprogramowanie pvmfm używane w Androidzie w języku Rust

W ramach działań na rzecz wzmocnienia bezpieczeństwa krytycznych komponentów oprogramowania platformy Android, firma Google prze rewizję oprogramowania pvmfm w języku Rust, które jest używane do organizacji pracy maszyn wirtualnych uruchamianych przez hipernadzorcę pVM w ramach Android Virtualization Framework. Wcześniej oprogramowanie to było napisane w języku C i realizowane na poziomie bootloadera U-Boot, w którym wcześniej znajdowane były podatności spowodowane problemami z pamięcią.

Oprogramowanie przepisywane w Rust jest częścią Androida 14, a stworzone w procesie rozwoju oprogramowania uniwersalne biblioteki zostały udostępnione jako pakiety crate i przekazane społeczności Rust. Na przykład opublikowano pakiet smccc do wsparcia interfejsów ARM PSCI (Power State Coordination Interface) i wywołań SMCCC (SMC Calling Convention), oraz pakiet aarch64-paging do manipulacji tabelami stron pamięci. Przeprowadzono również prace nad poprawą błędów i rozszerzeniem funkcjonalności istniejącego pakietu virtio-drivers poprzez realizację sterowników VirtIO. Oprócz platformy Android, wskazane pakiety są wykorzystywane w projekcie Oak, który rozwija komponenty do transmisji, przechowywania i przetwarzania danych w zabezpieczonych środowiskach (TEE, Trusted Execution Environment).

Hipernadzorca pVM przejmuje kontrolę na wczesnym etapie uruchamiania i zapewnia pełną izolację pamięci maszyn wirtualnych i środowiska hosta, uniemożliwiając systemowi hosta dostęp do zabezpieczonych maszyn wirtualnych, w których przetwarzane są dane poufne. Oprogramowanie pvmfm (Protected Virtual Machine Firmware) przejmuje kontrolę od razu po uruchomieniu maszyny wirtualnej, przeprowadza weryfikację utworzonego środowiska i podejmuje decyzję o awaryjnym przerwaniu procesu uruchamiania w przypadku wykrycia problemów z integralnością lub generuje certyfikat rozruchowy dla systemu gościa w przypadku konieczności potwierdzenia łańcucha zaufania.

Przetwarzanie w języku Rust pozwala na prostsze i bezpieczniejsze przestrzeganie 'zasady dwóch', stosowanej przez Google w celu utrzymania bezpieczeństwa komponentów systemu Android. Zgodnie z tą zasadą, każdy dodawany kod musi spełniać nie więcej niż dwa z trzech warunków: obsługę niesprawdzonych danych wejściowych, użycie niebezpiecznego języka programowania (C/C++) oraz wykonywanie z podwyższonymi uprawnieniami. Z tej zasady wynika, że kod do przetwarzania zewnętrznych danych powinien być albo ograniczony do minimalnych uprawnień (izolowany), albo napisany w bezpiecznym języku programowania. Według statystyk Google, około 70% wszystkich niebezpiecznych luk wykrytych w Androidzie jest spowodowanych błędami w pracy z pamięcią.

Rust koncentruje się na bezpiecznej pracy z pamięcią i pozwala zmniejszyć ryzyko wystąpienia luk spowodowanych problemami takimi jak dostęp do obszaru pamięci po jego zwolnieniu oraz przekroczenie granic bufora. Bezpieczna praca z pamięcią w Rust jest zapewniana podczas kompilacji poprzez sprawdzanie referencji, śledzenie własności obiektów oraz uwzględnianie czasu życia obiektów (zakresu widoczności), a także przez ocenę poprawności dostępu do pamięci w czasie wykonywania kodu. Rust oferuje również narzędzia do ochrony przed przepełnieniami liczb całkowitych, wymaga obowiązkowej inicjalizacji wartości zmiennych przed ich użyciem, lepiej obsługuje błędy w standardowej bibliotece, stosuje koncepcję niemutowalności (immutable) referencji i zmiennych domyślnie oraz oferuje silną statyczną typizację w celu minimalizacji błędów logicznych.

Wśród trudności, jakie występują podczas tworzenia niskopoziomowych komponentów w języku Rust, takich jak sterowniki, wspomniana jest konieczność pracy z gołymi wskaźnikami w trybie unsafe, ponieważ Rust został stworzony z myślą o używaniu pamięci alokowanej w programie, a w kodzie działającym bez warstw nad sprzętem trzeba odnosić się do pamięci współdzielonej i MMIO. Obecnie możliwości Rust w zakresie pracy z gołymi wskaźnikami pozostawiają wiele do życzenia, ale sytuacja powinna się poprawić po stabilizacji wsparcia dla makr offset_of, slice_ptr_get i slice_ptr_len.

Wśród wad warto zauważyć potrzebę poprawionego składni do dostępu do pól struktur i indeksów tablic za pomocą surowych wskaźników bez tworzenia referencji, a także ograniczenia w tworzeniu bezpiecznych opakowań dla operacji unsafe, które mogą prowadzić do nieokreślonego zachowania i nie mogą być sprawdzone przez kompilator. Na przykład, nie można stworzyć takich opakowań dla operacji związanych z tabelami stron pamięci, ponieważ mapowanie stron w jednej części programu może wpłynąć na inne części.

Jeśli chodzi o rozmiar wynikowego kodu, stara wersja oprogramowania pVM zajmowała 220 kB, a nowa — 460 kB, jednak w nowej wersji dodano nowe możliwości, dzięki którym udało się pozbyć niektórych innych komponentów wykorzystywanych podczas ładowania. Ostatecznie całkowity rozmiar wszystkich starych i nowych komponentów rozruchowych okazał się porównywalny. Zauważono, że kiedy rozmiar ma większe znaczenie niż wydajność, porównywalne wyniki z językiem C można osiągnąć, włączając w kompilatorze dodatkowe tryby optymalizacji rozmiaru, eliminując zbędne zależności i nie używając narzędzi do formatowania tekstu.

Dodatkowo wspomina się o kontynuacji pracy nad realizacją możliwości uruchamiania aplikacji zaufanych (Trusted Application) napisanych w języku Rust w systemie operacyjnym Trusty, który zapewnia środowisko TEE (Trusted Execution Environment) dla Androida, działające równolegle z Androidem na tym samym procesorze w osobnym, izolowanym środowisku. Trusty jest wykorzystywane w urządzeniach Pixel i już korzysta z Rust w bibliotekach oraz komponentach systemowych (jądro pozostaje w języku C).

Źródło: opennet.ru

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster