Utwardzanie ram medialnych

Aby poprawić bezpieczeństwo urządzenia, Android 7.0 dzieli monolityczny proces mediaserver na wiele procesów, których uprawnienia i możliwości są ograniczone tylko do tych wymaganych przez każdy proces. Zmiany te łagodzą luki w zabezpieczeniach platformy medialnej poprzez:

  • Dzielenie komponentów potoku AV na procesy w piaskownicy specyficzne dla aplikacji.
  • Włączanie aktualizowalnych komponentów multimediów (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 multimediami, zapewniając bezpieczeństwo urządzeń i danych użytkowników końcowych.

Producenci OEM i dostawcy SoC muszą zaktualizować zmiany w HAL i frameworku, aby były zgodne z nową architekturą. W szczególności, ponieważ dostarczony przez dostawcę kod Androida 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 utwardzaniem multimedió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 sterowników 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 multimedialnego

Rysunek 1. Zmiany w architekturze w celu wzmocnienia serwera multimediów

Ta nowa architektura gwarantuje, że nawet w przypadku naruszenia bezpieczeństwa procesu złośliwy kod nie będzie miał dostępu do pełnego zestawu uprawnień posiadanych wcześniej przez mediaserver . Procesy są ograniczone przez zasady SElinux i seccomp.

Uwaga: ze względu na zależności od dostawców niektóre kodeki nadal działają na mediaserver i w rezultacie przyznają mediaserver więcej uprawnień, niż jest to konieczne. W szczególności Widevine Classic nadal działa na mediaserver dla systemu Android 7.0.

Zmiany w MediaServerze

W systemie Android 7.0 istnieje proces mediaserver umożliwiający odtwarzanie i nagrywanie, np. przekazywanie i synchronizowanie buforów pomiędzy komponentami i procesami. Procesy komunikują się poprzez standardowy mechanizm Bindera.

Podczas standardowej sesji lokalnego odtwarzania plików aplikacja przekazuje deskryptor pliku (FD) do mediaserver (zwykle za pośrednictwem interfejsu API Java MediaPlayer), a mediaserver :

  1. Zawija FD w obiekt Binder DataSource, który jest przekazywany do procesu wyodrębniającego, który używa go do odczytu z pliku przy użyciu Binder IPC. (Ektraktor multimediów nie pobiera FD, ale zamiast tego powoduje, że Binder oddzwania do mediaserver w celu pobrania danych.)
  2. Sprawdza plik, tworzy ekstraktor odpowiedni dla typu pliku (np. MP3Extractor lub MPEG4Extractor) i zwraca interfejs Bindera 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 Binder dla tych kodeków.
  5. Wykonuje wielokrotne wywołania Binder IPC do ekstraktora w celu odczytania zakodowanych próbek, używa Binder IPC do wysłania zakodowanych danych do procesu mediacodec w celu zdekodowania i odbiera zdekodowane dane.

W niektórych przypadkach użycia nie jest używany żaden kodek (np. odtwarzanie bez obciążenia, podczas którego zakodowane dane są wysyłane bezpośrednio do urządzenia wyjściowego) lub kodek może bezpośrednio renderować zdekodowane dane zamiast zwracać bufor zdekodowanych danych (odtwarzanie wideo).

Zmiany w usłudze MediaCodecService

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

  • Niezabezpieczone dekodery i kodery programowe podlegają procesowi kodeka.
  • Bezpieczne dekodery i kodery sprzętowe znajdują się na mediaserver (bez zmian).

Aplikacja (lub mediaserver ) wywołuje proces kodeka, aby utworzyć kodek wymaganego typu, a następnie wywołuje ten kodek, aby przekazać zakodowane dane i pobrać zdekodowane dane (do dekodowania) lub przekazać zdekodowane dane i pobrać zakodowane dane (do kodowania) . Przesyłanie danych do i z kodeków wykorzystuje już pamięć współdzieloną, więc proces ten pozostaje niezmieniony.

Zmiany w MediaDrmServerze

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

Zmiany w AudioServerze

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

Zmiany w serwerze CameraServer

CameraServer steruje kamerą i jest używany podczas nagrywania wideo w celu uzyskania klatek wideo z kamery, a następnie przekazania ich do mediaserver w celu dalszej obróbki. Aby uzyskać szczegółowe informacje na temat zmian i wskazówek dotyczących wdrażania zmian w serwerze CameraServer, zobacz Ulepszanie środowiska kamery .

Zmiany w usługach ekstraktorowych

Usługa ekstraktora obsługuje ekstraktory , czyli komponenty analizujące różne formaty plików obsługiwane przez platformę multimediów. Usługa ekstraktora jest najmniej uprzywilejowana ze wszystkich usług — nie może czytać plików FD, więc zamiast tego wykonuje wywołania interfejsu Binder (dostarczanego mu przez 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 IMediaExtractor w celu uzyskania IMediaSources dla ścieżki zawartej w pliku, a następnie wywołuje IMediaSources w celu odczytania z nich danych.

Aby przesyłać dane pomiędzy procesami, aplikacja (lub mediaserver ) uwzględnia dane w przesyłce zwrotnej w ramach transakcji Binder lub wykorzystuje pamięć współdzieloną:

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

Realizacja

Aby wesprzeć przenoszenie 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 były przydzielane na mediaserver przez OMX::allocateBuffer i używane podczas deszyfrowania w tym samym procesie, jak pokazano poniżej:

Rysunek 2. Android 6.0 i niższa alokacja bufora w serwerze multimediów.

W Androidzie 7.0 proces alokacji bufora został zmieniony na nowy mechanizm zapewniający elastyczność przy jednoczesnej minimalizacji wpływu na istniejące implementacje. Dzięki stosom MediaDrm i MediaCrypto w nowym procesie mediadrmserver bufory są przydzielane inaczej i dostawcy muszą zaktualizować uchwyty bezpiecznych buforów, aby można je było transportować przez segregator, gdy MediaCodec wywołuje operację deszyfrowania na MediaCrypto .

Rysunek 3. Android 7.0 i nowszy alokacja bufora na serwerze multimediów.

Użyj natywnych uchwytów

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 FD, w tym istniejącą obsługę segregatorów dla serializacji/deserializacji, jednocześnie zapewniając większą elastyczność dostawcom, którzy obecnie nie korzystają z FD.

Użyj native_handle_create() , aby przydzielić natywny uchwyt. Kod frameworka przejmuje na własność przydzieloną strukturę native_handle i jest odpowiedzialny za zwalnianie zasobów zarówno w procesie, w którym pierwotnie przydzielono native_handle , jak i w procesie, w którym jest on deserializowany. Struktura udostępnia natywne uchwyty za pomocą funkcji native_handle_close() po której następuje native_handle_delete() i serializuje/deserializuje native_handle za pomocą Parcel::writeNativeHandle()/readNativeHandle() .

Dostawcy SoC, którzy używają FD do reprezentowania bezpiecznych buforów, mogą zapełnić FD w native_handle swoim FD. Dostawcy, którzy nie korzystają z FD, mogą reprezentować bezpieczne bufory, korzystając z dodatkowych pól w pliku native_buffer .

Ustaw lokalizację deszyfrowania

Dostawcy muszą zaktualizować metodę deszyfrowania OEMCrypto działającą na native_handle , aby wykonać wszelkie operacje specyficzne dla dostawcy niezbędne do umożliwienia obsługi native_handle w nowej przestrzeni procesowej (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 wysyłania zapytań o tę obsługę oraz wywołanie OMX_SetParameter , które powiadamia implementację OMX, że powinna używać natywnych uchwytów.