Utwardzanie ram nośników

Aby poprawić bezpieczeństwo urządzeń, Android 7.0 dzieli monolityczny proces mediaserver na wiele procesów z uprawnieniami i możliwościami ograniczonymi tylko do tych, które są wymagane przez każdy proces. Te zmiany łagodzą luki w zabezpieczeniach Media Framework poprzez:

  • Dzielenie składników potoku AV na procesy piaskownicy specyficzne dla aplikacji.
  • Umożliwienie aktualizowania komponentów multimedialnych (ekstraktory, kodeki itp.).

Zmiany te poprawiają również bezpieczeństwo użytkowników końcowych, znacznie zmniejszając wagę większości luk w zabezpieczeniach związanych z mediami, zapewniając bezpieczeństwo urządzeń użytkowników końcowych i danych.

Producenci OEM i dostawcy SoC muszą zaktualizować swoje warstwy HAL i zmiany w strukturze, aby były zgodne z nową architekturą. W szczególności, ponieważ kod systemu Android dostarczony przez dostawcę często zakłada, że ​​wszystko działa w tym samym procesie, dostawcy muszą zaktualizować swój kod, aby przekazywać natywne uchwyty ( native_handle ), które mają znaczenie między procesami. Aby zapoznać się z referencyjną implementacją zmian związanych z utrwalaniem nośników, zobacz frameworks/av i frameworks/native .

Zmiany architektoniczne

Poprzednie wersje Androida wykorzystywały pojedynczy, mediaserver proces serwera mediów z wieloma uprawnieniami (dostęp do kamery, dostęp do dźwięku, dostęp do sterownika wideo, dostęp do plików, dostęp do sieci itp.). Android 7.0 dzieli proces mediaserver na kilka nowych procesów, z których każdy wymaga znacznie mniejszego zestawu uprawnień:

hartowanie serwera mediów

Rysunek 1. Zmiany w architekturze dla umocnienia serwera mediów

Ta nowa architektura zapewnia, że ​​nawet jeśli proces zostanie naruszony, złośliwy kod nie ma dostępu do pełnego zestawu uprawnień, które wcześniej posiadał serwer medialny. Procesy są ograniczone przez polityki SElinux i seccomp.

Uwaga: Z powodu zależności od dostawcy niektóre kodeki nadal działają na mediaserver i w konsekwencji przyznają mediaserver więcej uprawnień niż jest to konieczne. W szczególności mediaserver Classic nadal działa na serwerze mediów dla Androida 7.0.

Zmiany MediaServer

W systemie Android 7.0 proces mediaserver istnieje do sterowania odtwarzaniem i nagrywaniem, np. przekazywaniem i synchronizacją buforów między komponentami i procesami. Procesy komunikują się za pomocą standardowego mechanizmu Binder.

W standardowej sesji odtwarzania plików lokalnych aplikacja przekazuje deskryptor pliku (FD) do mediaserver (zwykle za pośrednictwem interfejsu MediaPlayer Java API) oraz do mediaserver :

  1. Zawija FD w obiekt Binder DataSource, który jest przekazywany do procesu wyodrębniania, który używa go do odczytu z pliku przy użyciu Binder IPC. ( mediaserver nie pobiera FD, ale zamiast tego wywołuje Binder z powrotem do serwera mediów, aby pobrać dane.)
  2. Sprawdza plik, tworzy odpowiedni ekstraktor dla typu pliku (np. MP3Extractor lub MPEG4Extractor) i zwraca interfejs Binder dla ekstraktora do procesu mediaserver .
  3. Wykonuje wywołania Binder IPC do ekstraktora w celu określenia typu danych w pliku (np. dane MP3 lub H.264).
  4. Wywołuje proces mediacodec w celu utworzenia kodeków wymaganego typu; otrzymuje interfejsy Bindera dla tych kodeków.
  5. Wykonuje powtarzające się wywołania Binder IPC do ekstraktora w celu odczytania zakodowanych próbek, używa Binder IPC do wysyłania zakodowanych danych do procesu mediacodec w celu odkodowania i odbiera zdekodowane dane.

W niektórych przypadkach nie jest zaangażowany żaden koder-dekoder (np. odciążone odtwarzanie, w którym zakodowane dane są wysyłane bezpośrednio do urządzenia wyjściowego) lub kodek może renderować dekodowane dane bezpośrednio zamiast zwracać bufor dekodowanych danych (odtwarzanie wideo).

Zmiany w MediaCodecService

Usługa kodeków to miejsce, w którym żyją kodery i dekodery. Ze względu na zależności od dostawców nie wszystkie kodeki działają jeszcze w procesie kodeków. W Androidzie 7.0:

  • Niezabezpieczone dekodery i kodery programowe działają w procesie kodeków.
  • Bezpieczne dekodery i kodery sprzętowe działają na mediaserver (bez zmian).

Aplikacja (lub serwer mediów) wywołuje proces kodera-dekodera w celu utworzenia kodera-dekodera wymaganego typu, a następnie wywołuje ten kodek w celu przekazania zakodowanych danych i pobrania dekodowanych danych (do dekodowania) lub przekazania zdekodowanych danych i pobrania zakodowanych danych (do kodowania) . Transfer danych do iz kodeków korzysta już z pamięci współdzielonej, więc proces ten pozostaje niezmieniony.

Zmiany MediaDrmServer

Serwer DRM jest używany podczas odtwarzania treści chronionych DRM, takich jak filmy w Filmach Google Play. Obsługuje odszyfrowywanie zaszyfrowanych danych w bezpieczny sposób i jako taki ma dostęp do przechowywania certyfikatów i kluczy oraz innych wrażliwych komponentów. Ze względu na zależności od dostawców, proces DRM nie jest jeszcze używany we wszystkich przypadkach.

Zmiany AudioServer

Proces AudioServer obsługuje komponenty związane z dźwiękiem, takie jak wejście i wyjście audio, usługa Policymanager, która określa routing audio oraz usługa radia FM. Aby uzyskać szczegółowe informacje na temat zmian dźwięku i wskazówek dotyczących implementacji, zobacz Implementacja dźwięku .

Zmiany CameraServer

mediaserver steruje kamerą i jest używany podczas nagrywania wideo w celu uzyskania klatek wideo z kamery, a następnie przekazania ich do serwera mediów w celu dalszej obsługi. Szczegółowe informacje na temat zmian i wskazówki dotyczące implementacji zmian w programie CameraServer można znaleźć w dokumencie Camera Framework Hardening .

Zmiany w usłudze Extractor

Usługa ekstraktora obsługuje ekstraktory , komponenty, które analizują różne formaty plików obsługiwane przez strukturę mediów. Usługa ekstraktora jest najmniej uprzywilejowana ze wszystkich usług — nie może czytać FD, więc zamiast tego wykonuje wywołania do interfejsu Binder (udostępnianego mu przez serwer mediów mediaserver for każdej sesji odtwarzania), aby uzyskać dostęp do plików.

Aplikacja (lub mediaserver ) wywołuje proces ekstraktora w celu uzyskania IMediaExtractor , wywołuje ten IMediaExtractor w celu uzyskania IMediaSources dla ścieżki zawartej w pliku, a następnie wywołuje IMediaSources w celu odczytania z nich danych.

Aby przesłać dane pomiędzy procesami, aplikacja (lub mediaserver ) włącza dane w paczce-odpowiedzi w ramach transakcji Binder lub wykorzystuje pamięć współdzieloną:

  • Korzystanie z pamięci współdzielonej wymaga dodatkowego wywołania programu Binder w celu zwolnienia pamięci współdzielonej, ale jest szybsze i zużywa mniej energii w przypadku dużych buforów.
  • Korzystanie z funkcji In-Parcel wymaga dodatkowego kopiowania, ale jest szybsze i zużywa mniej energii w przypadku buforów mniejszych niż 64 KB.

Realizacja

Aby wesprzeć przeniesienie komponentów MediaDrm i MediaCrypto do nowego procesu mediadrmserver , dostawcy muszą zmienić metodę alokacji bezpiecznych buforów, aby umożliwić współdzielenie buforów między procesami.

W poprzednich wersjach Androida bezpieczne bufory są przydzielane w mediaserver przez OMX::allocateBuffer i używane podczas odszyfrowywania w tym samym procesie, jak pokazano poniżej:

Rysunek 2. Android 6.0 i dolna alokacja buforów w mediaserver.

W systemie Android 7.0 proces alokacji buforów został zmieniony na nowy mechanizm, który zapewnia elastyczność, jednocześnie minimalizując wpływ na istniejące implementacje. Dzięki MediaDrm i MediaCrypto w nowym procesie mediadrmserver bufory są przydzielane w inny sposób, a dostawcy muszą aktualizować uchwyty bezpiecznego bufora, aby mogły być transportowane przez binder, gdy MediaCodec wywołuje operację odszyfrowywania na MediaCrypto .

Rysunek 3. Android 7.0 i wyższy alokacja buforów w mediaserver.

Korzystanie z uchwytów natywnych

OMX::allocateBuffer musi zwracać wskaźnik do struktury native_handle , która zawiera deskryptory plików (FD) i dodatkowe dane całkowite. native_handle ma wszystkie zalety korzystania z funkcji FD, w tym istniejącą obsługę spinacza dla serializacji/deserializacji, jednocześnie zapewniając większą elastyczność dostawcom, którzy obecnie nie używają funkcji FD.

Użyj native_handle_create() , aby przydzielić natywny uchwyt. Kod platformy przejmuje własność przydzielonej struktury native_handle i jest odpowiedzialny za zwalnianie zasobów zarówno w procesie, w którym native_handle jest pierwotnie przydzielony, jak i w procesie, w którym jest on zdeserializowany. Framework zwalnia natywne uchwyty za pomocą native_handle_close() , po którym następuje native_handle_delete() i serializuje/deserializuje native_handle przy użyciu Parcel::writeNativeHandle()/readNativeHandle() .

Dostawcy SoC, którzy używają FD do reprezentowania bezpiecznych buforów, mogą wypełnić FD w native_handle swoimi FD. Dostawcy, którzy nie używają FD, mogą reprezentować bezpieczne bufory przy użyciu dodatkowych pól w native_buffer .

Ustawianie lokalizacji deszyfrowania

Dostawcy muszą zaktualizować metodę odszyfrowywania OEMCrypto, która działa na native_handle , aby wykonać wszelkie operacje specyficzne dla dostawcy, które są niezbędne do uczynienia native_handle użytecznym w nowej przestrzeni procesów (zmiany zazwyczaj obejmują aktualizacje bibliotek OEMCrypto).

Ponieważ allocateBuffer to standardowa operacja OMX, system Android 7.0 zawiera nowe rozszerzenie OMX ( OMX.google.android.index.allocateNativeHandle ) do wysyłania zapytań o tę obsługę oraz wywołanie OMX_SetParameter , które powiadamia implementację OMX, że powinna używać uchwytów natywnych.