Чтобы повысить безопасность устройства, Android 7.0 разбивает монолитный процесс mediaserver
на несколько процессов с разрешениями и возможностями, ограниченными только теми, которые требуются каждому процессу. Эти изменения снижают уязвимости системы безопасности среды мультимедиа за счет:
- Разделение компонентов AV-конвейера на изолированные процессы для конкретных приложений.
- Включение обновляемых медиакомпонентов (экстракторов, кодеков и т.д.).
Эти изменения также повышают безопасность конечных пользователей, значительно снижая серьезность большинства уязвимостей безопасности, связанных с мультимедиа, обеспечивая безопасность устройств и данных конечных пользователей.
OEM-производителям и поставщикам SoC необходимо обновить свои изменения HAL и инфраструктуры, чтобы сделать их совместимыми с новой архитектурой. В частности, поскольку код Android, предоставленный поставщиком, часто предполагает, что все выполняется в одном и том же процессе, поставщики должны обновить свой код, чтобы передать собственные дескрипторы ( native_handle
), которые имеют значение для разных процессов. Для эталонной реализации изменений, связанных с усилением защиты носителя, обратитесь к frameworks/av
и frameworks/native
.
Архитектурные изменения
В предыдущих версиях Android использовался единый монолитный процесс mediaserver
с большим количеством разрешений (доступ к камере, доступ к аудио, доступ к видеодрайверу, доступ к файлам, доступ к сети и т. д.). Android 7.0 разделяет процесс mediaserver
на несколько новых процессов, каждый из которых требует гораздо меньшего набора разрешений:
Эта новая архитектура гарантирует, что даже если процесс будет скомпрометирован, вредоносный код не получит доступ ко всему набору разрешений, ранее имевшихся у медиасервера. Процессы ограничены политиками SElinux и seccomp.
Примечание. Из-за зависимости от поставщика некоторые кодеки по-прежнему работают на mediaserver
и, следовательно, предоставляют mediaserver
больше разрешений, чем необходимо. В частности, Widevine Classic продолжает работать на mediaserver
для Android 7.0.
Изменения медиасервера
В Android 7.0 существует процесс mediaserver
для управления воспроизведением и записью, например, передача и синхронизация буферов между компонентами и процессами. Процессы взаимодействуют через стандартный механизм Binder.
В стандартном сеансе воспроизведения локального файла приложение передает дескриптор файла (FD) на mediaserver
(обычно через Java API MediaPlayer), а mediaserver
:
- Оборачивает FD в объект Binder DataSource, который передается процессу извлечения, который использует его для чтения из файла с помощью Binder IPC. (Медиаэкстрактор не получает FD, а вместо этого заставляет Binder обращаться к
mediaserver
для получения данных.) - Исследует файл, создает соответствующий экстрактор для типа файла (например, MP3Extractor или MPEG4Extractor) и возвращает интерфейс Binder для экстрактора процессу
mediaserver
. - Делает вызовы Binder IPC к экстрактору, чтобы определить тип данных в файле (например, данные MP3 или H.264).
- Вызывает процесс
mediacodec
для создания кодеков нужного типа; получает интерфейсы Binder для этих кодеков. - Выполняет повторные вызовы 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
и использовались во время расшифровки в том же процессе, как показано ниже:
В Android 7.0 процесс выделения буфера изменен на новый механизм, обеспечивающий гибкость при минимальном влиянии на существующие реализации. Со MediaDrm
и MediaCrypto
в новом процессе mediadrmserver
буферы распределяются по-разному, и поставщики должны обновить безопасные дескрипторы буфера, чтобы их можно было транспортировать через связующее, когда MediaCodec
вызывает операцию расшифровки на MediaCrypto
.
Использование родных дескрипторов
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 о необходимости использования собственных дескрипторов.