Усиление медиа-фреймворка

Чтобы повысить безопасность устройства, Android 7.0 разбивает монолитный процесс mediaserver на несколько процессов с разрешениями и возможностями, ограниченными только теми, которые требуются каждому процессу. Эти изменения снижают уязвимости системы безопасности среды мультимедиа за счет:

  • Разделение компонентов AV-конвейера на изолированные процессы для конкретных приложений.
  • Включение обновляемых медиакомпонентов (экстракторов, кодеков и т.д.).

Эти изменения также повышают безопасность конечных пользователей, значительно снижая серьезность большинства уязвимостей безопасности, связанных с мультимедиа, обеспечивая безопасность устройств и данных конечных пользователей.

OEM-производителям и поставщикам SoC необходимо обновить свои изменения HAL и инфраструктуры, чтобы сделать их совместимыми с новой архитектурой. В частности, поскольку код Android, предоставленный поставщиком, часто предполагает, что все выполняется в одном и том же процессе, поставщики должны обновить свой код, чтобы передать собственные дескрипторы ( native_handle ), которые имеют значение для разных процессов. Для эталонной реализации изменений, связанных с усилением защиты носителя, обратитесь к frameworks/av и frameworks/native .

Архитектурные изменения

В предыдущих версиях Android использовался единый монолитный процесс mediaserver с большим количеством разрешений (доступ к камере, доступ к аудио, доступ к видеодрайверу, доступ к файлам, доступ к сети и т. д.). Android 7.0 разделяет процесс mediaserver на несколько новых процессов, каждый из которых требует гораздо меньшего набора разрешений:

усиление защиты медиасервера

Рис. 1. Изменения в архитектуре для усиления защиты медиасервера

Эта новая архитектура гарантирует, что даже если процесс будет скомпрометирован, вредоносный код не получит доступ ко всему набору разрешений, ранее имевшихся у медиасервера. Процессы ограничены политиками SElinux и seccomp.

Примечание. Из-за зависимости от поставщика некоторые кодеки по-прежнему работают на mediaserver и, следовательно, предоставляют mediaserver больше разрешений, чем необходимо. В частности, Widevine Classic продолжает работать на mediaserver для Android 7.0.

Изменения медиасервера

В Android 7.0 существует процесс mediaserver для управления воспроизведением и записью, например, передача и синхронизация буферов между компонентами и процессами. Процессы взаимодействуют через стандартный механизм Binder.

В стандартном сеансе воспроизведения локального файла приложение передает дескриптор файла (FD) на mediaserver (обычно через Java API MediaPlayer), а mediaserver :

  1. Оборачивает FD в объект Binder DataSource, который передается процессу извлечения, который использует его для чтения из файла с помощью Binder IPC. (Медиаэкстрактор не получает FD, а вместо этого заставляет Binder обращаться к mediaserver для получения данных.)
  2. Исследует файл, создает соответствующий экстрактор для типа файла (например, MP3Extractor или MPEG4Extractor) и возвращает интерфейс Binder для экстрактора процессу mediaserver .
  3. Делает вызовы Binder IPC к экстрактору, чтобы определить тип данных в файле (например, данные MP3 или H.264).
  4. Вызывает процесс mediacodec для создания кодеков нужного типа; получает интерфейсы Binder для этих кодеков.
  5. Выполняет повторные вызовы Binder IPC к экстрактору для чтения закодированных образцов, использует Binder IPC для отправки закодированных данных в процесс mediacodec для декодирования и получает декодированные данные.

В некоторых случаях кодек не используется (например, воспроизведение с разгрузкой, когда закодированные данные отправляются непосредственно на устройство вывода), или кодек может отображать декодированные данные напрямую, а не возвращать буфер декодированных данных (воспроизведение видео).

Изменения MediaCodecService

Служба кодеков — это место, где живут кодеры и декодеры. Из-за зависимости от поставщика не все кодеки еще находятся в процессе кодека. В Android 7.0:

  • Незащищенные декодеры и программные кодировщики живут в процессе кодирования.
  • Безопасные декодеры и аппаратные кодировщики находятся на mediaserver (без изменений).

Приложение (или медиасервер) вызывает процесс кодека для создания кодека требуемого типа, а затем вызывает этот кодек для передачи закодированных данных и извлечения декодированных данных (для декодирования) или для передачи декодированных данных и извлечения закодированных данных (для кодирования). . Передача данных в кодеки и из них уже использует общую память, поэтому этот процесс не меняется.

Изменения MediaDrmServer

Сервер DRM используется при воспроизведении контента, защищенного DRM, например фильмов в Google Play Movies. Он безопасно расшифровывает зашифрованные данные и, таким образом, имеет доступ к хранилищу сертификатов и ключей, а также к другим конфиденциальным компонентам. Из-за зависимости от поставщиков процесс DRM пока не используется во всех случаях.

Изменения аудиосервера

В процессе AudioServer размещаются компоненты, связанные со звуком, такие как вход и выход звука, служба policymanager, определяющая маршрутизацию звука, и служба FM-радио. Дополнительные сведения об изменениях аудио и рекомендации по реализации см. в разделе Реализация аудио .

Изменения CameraServer

CameraServer управляет камерой и используется при записи видео для получения видеокадров с камеры, а затем передачи их на mediaserver для дальнейшей обработки. Подробные сведения об изменениях и рекомендации по внедрению изменений CameraServer см. в разделе Повышение безопасности Camera Framework .

Изменения ExtractorService

Служба экстрактора содержит экстракторы , компоненты, которые анализируют различные форматы файлов, поддерживаемые медиа-фреймворком. Служба извлечения является наименее привилегированной из всех служб — она не может читать FD, поэтому вместо этого она обращается к интерфейсу Binder (предоставляемому ему mediaserver for каждого сеанса воспроизведения) для доступа к файлам.

Приложение (или mediaserver ) вызывает процесс извлечения для получения IMediaExtractor , вызывает этот IMediaExtractor для получения IMediaSources для дорожки, содержащейся в файле, а затем вызывает IMediaSources для чтения данных из них.

Для передачи данных между процессами приложение (или mediaserver ) включает данные в response-Parcel как часть транзакции Binder или использует разделяемую память:

  • Использование разделяемой памяти требует дополнительного вызова Binder для освобождения разделяемой памяти, но это быстрее и потребляет меньше энергии для больших буферов.
  • Использование in-Parcel требует дополнительного копирования, но работает быстрее и потребляет меньше энергии для буферов размером менее 64 КБ.

Реализация

Для поддержки переноса компонентов MediaDrm и MediaCrypto в новый процесс mediadrmserver поставщики должны изменить метод выделения безопасных буферов, чтобы разрешить совместное использование буферов между процессами.

В предыдущих выпусках Android защищенные буферы выделялись на медиасервере с помощью OMX::allocateBuffer mediaserver и использовались во время расшифровки в том же процессе, как показано ниже:

Рис. 2. Android 6.0 и более раннее распределение буфера в медиасервере.

В Android 7.0 процесс выделения буфера изменен на новый механизм, обеспечивающий гибкость при минимальном влиянии на существующие реализации. Со MediaDrm и MediaCrypto в новом процессе mediadrmserver буферы распределяются по-разному, и поставщики должны обновить безопасные дескрипторы буфера, чтобы их можно было транспортировать через связующее, когда MediaCodec вызывает операцию расшифровки на MediaCrypto .

Рисунок 3. Android 7.0 и более поздние версии распределения буфера в медиасервере.

Использование родных дескрипторов

OMX::allocateBuffer allocateBuffer должен возвращать указатель на структуру native_handle , которая содержит файловые дескрипторы (FD) и дополнительные целочисленные данные. native_handle обладает всеми преимуществами использования FD, включая существующую поддержку связующего для сериализации/десериализации, обеспечивая при этом большую гибкость для поставщиков, которые в настоящее время не используют FD.

Используйте native_handle_create() , чтобы выделить собственный дескриптор. Код фреймворка становится владельцем выделенной структуры native_handle и отвечает за высвобождение ресурсов как в процессе, в котором изначально выделена структура native_handle , так и в процессе, в котором она десериализуется. Фреймворк выпускает собственные дескрипторы с помощью native_handle_close() , за которым следует native_handle_delete() , и сериализует/десериализует native_handle с помощью Parcel::writeNativeHandle()/readNativeHandle() .

Поставщики SoC, которые используют FD для представления защищенных буферов, могут заполнить FD в native_handle своим FD. Поставщики, которые не используют FD, могут представлять безопасные буферы, используя дополнительные поля в native_buffer .

Установка места расшифровки

Поставщики должны обновить метод дешифрования OEMCrypto, который работает с native_handle , чтобы выполнять любые специфичные для поставщика операции, необходимые для обеспечения возможности использования native_handle в новом пространстве процесса (изменения обычно включают обновления библиотек OEMCrypto).

Поскольку allocateBuffer — это стандартная операция OMX, Android 7.0 включает новое расширение OMX ( OMX.google.android.index.allocateNativeHandle ) для запроса этой поддержки и вызов OMX_SetParameter , уведомляющий реализацию OMX о необходимости использования собственных дескрипторов.