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 w 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 przekazać 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, monolityczny proces mediaserver 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 gwarantuje, ż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 użycia 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 kodeka w celu utworzenia kodeka wymaganego typu, a następnie wywołuje ten kodek w celu przekazania zakodowanych danych i pobrania zdekodowanych danych (do dekodowania) lub przekazania zdekodowanych danych i pobrania zakodowanych danych (w celu zakodowania) . 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 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ższa 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, zapewniając jednocześnie 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. Struktura zwalnia natywne uchwyty za pomocą native_handle_close() , a następnie 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 jest standardową operacją OMX, system Android 7.0 zawiera nowe rozszerzenie OMX ( OMX.google.android.index.allocateNativeHandle ) do zapytania o tę obsługę oraz wywołanie OMX_SetParameter , które powiadamia implementację OMX, że powinna używać uchwytów natywnych.