미디어 프레임워크 강화

기기 보안 개선을 위해 Android 7.0은 모노리식 mediaserver 프로세스를 각 프로세스에 의해 요구되는 내용으로 제한하는 권한 및 기능을 포함하는 여러 프로세스로 분할합니다. 이러한 변화는 다음을 통해 미디어 프레임워크의 보안 취약성을 줄여줍니다.

  • AV 파이프라인 구성요소를 앱 전용 샌드박스 프로세스로 분할
  • 업데이트 가능한 미디어 구성요소 지원(추출기, 코덱 등)

또한 이러한 변화는 대부분의 미디어 관련 보안 취약성의 심각도를 크게 줄임으로써 최종 사용자의 보안을 개선하여 최종 사용자의 기기와 데이터를 안전하게 지켜줍니다.

OEM 및 SoC 공급업체는 HAL 및 프레임워크 변경사항을 업데이트하여 새 아키텍처와 호환되도록 해야 합니다. 구체적으로 설명하자면, 공급업체에서 제공하는 Android 코드는 모든 것이 같은 프로세스에서 실행된다고 가정하는 경우가 많습니다. 따라서 공급업체는 자체 코드를 업데이트하여 프로세스 전체에 걸쳐 의미를 지니는 기본 핸들(native_handle)을 돌려야 합니다. 미디어 강화와 관련된 변경사항의 참조 구현은 frameworks/avframeworks/native를 참조하세요.

아키텍처 변경사항

이전 버전의 Android는 다수의 유용한 권한(카메라 액세스, 오디오 액세스, 비디오 드라이버 액세스, 파일 액세스, 네트워크 액세스 등)을 가진 단일 모노리식 mediaserver 프로세스를 사용했습니다. Android 7.0은 mediaserver 프로세스를 각각 더 작은 권한 모음을 필요로 하는 여러 새로운 프로세스로 분할합니다.

미디어 서버 강화

그림 1. 미디어 서버 강화와 관련된 아키텍처 변경사항

이 새로운 아키텍처는 프로세스가 손상되는 경우에도 악성 코드가 이전에 미디어 서버에서 보유했던 권한 모음 전체에 액세스하지 못하도록 합니다. 프로세스는 SElinux 및 seccomp 정책에 의해 제한됩니다.

참고: 공급업체 종속성을 이유로 일부 코덱은 mediaserver에서 계속 실행되며 결과적으로는 mediaserver에 필요 이상의 권한을 부여합니다. 구체적으로 Widevine Classic은 Android 7.0의 mediaserver에서 계속 실행됩니다.

MediaServer 변경사항

Android 7.0에서는 mediaserver 프로세스가 재생 및 녹화를 유도하기 위해 존재합니다. 구성요소 및 프로세스 간에 버퍼를 전달하고 동기화하는 경우를 예로 들 수 있습니다. 프로세스는 표준 바인더 매커니즘을 통해 통신합니다.

표준 로컬 파일 재생 세션에서는 애플리케이션이 파일 설명어(FD)를 mediaserver(보통 MediaPlayer Java API 사용) 및 mediaserver에 전달합니다.

  1. FD를 추출기 프로세스로 전달된 Binder DataSource 개체에 래핑합니다. 이 프로세스는 개체 및 바인더 IPC를 사용하여 파일에서 읽습니다(미디어 추출기는 FD를 가져오지 않지만 대신 바인더가 mediaserver로 콜백하여 데이터를 가져오도록 함).
  2. 파일을 살펴보고 파일 유형(MP3Extractor 또는 MPEG4Extractor 등)의 적절한 추출기를 생성한 후 추출기의 바인더 인터페이스를 mediaserver 프로세스로 반환합니다.
  3. 추출기에 바인더 IPC를 호출하여 파일(MP3 또는 H.264 데이터)의 데이터 유형을 파악합니다.
  4. mediacodec 프로세스로 호출되어 필수 유형의 코덱을 생성하고 이러한 코덱의 바인더 인터페이스를 수신합니다.
  5. 추출기에 반복적으로 바인더 IPC를 호출하여 인코딩된 샘플을 읽고 바인더 IPC를 사용하여 인코딩된 데이터를 mediacodec 프로세스로 보내어 디코딩한 후 디코딩된 데이터를 수신합니다.

경우에 따라서는 코덱이 개입되지 않거나(인코딩된 데이터가 바로 출력 기기로 전송된 오프로드된 재생 등) 코덱이 디코딩된 데이터의 버퍼를 반환하는 대신 디코딩된 데이터를 직접적으로 렌더링할 수 있습니다(동영상 재생).

MediaCodecService 변경사항

코덱 서비스는 인코더 및 디코더가 상주하는 곳입니다. 공급업체 종속성을 이유로 일부 코덱은 아직까지 코덱 프로세스에 상주하지 않습니다. Android 7.0의 경우:

  • 비보안 디코더 및 소프트웨어 인코더가 코덱 프로세스에 상주합니다.
  • 보안 디코더 및 하드웨어 인코더가 mediaserver에 상주합니다. (변경 안 됨)

애플리케이션 또는 미디어 서버는 코덱 프로세스를 호출하여 필요한 유형의 코덱을 생성한 다음 이 코덱을 호출하여 인코딩된 데이터를 전달하고 디코딩된 데이터를 검색하거나(디코딩의 경우) 디코딩된 데이터를 전달하고 인코딩된 데이터를 검색합니다(인코딩의 경우). 코덱과의 데이터 전송 및 수신은 이미 공유된 메모리를 사용하므로 프로세스가 변경되지 않습니다.

MediaDrmServer 변경사항

DRM 서버는 Google Play 무비의 영화와 같은 DRM 보호 콘텐츠를 재생하는 데 사용됩니다. 이 서버는 암호화된 데이터의 안전한 복호화를 처리합니다. 따라서 인증서, 키 저장소 및 기타 민감한 구성요소에 액세스할 수 있습니다. 공급업체 종속성으로 인해 아직까지는 DRM 프로세스가 사용되지 않는 경우도 있습니다.

AudioServer 변경사항

AudioServer 프로세스는 오디오 입력 및 출력, 오디오 라우팅을 결정하는 정책 관리자 서비스 및 FM 라디오 서비스와 같은 오디오 관련 구성요소를 호스팅합니다. 오디오 변경사항 및 구현 가이드에 대한 자세한 내용은 오디오 구현을 참조하세요.

CameraServer 변경사항

CameraServer는 카메라를 제어하며, 동영상을 녹화하여 동영상 프레임을 카메라에서 가져온 다음 추가 처리를 위해 mediaserver로 전달하는 데 사용됩니다. 자세한 변경사항 및 CameraServer 변경사항 관련 구현 가이드는 카메라 프레임워크 강화를 참조하세요.

ExtractorService 변경사항

추출기 서비스는 추출기를 호스팅합니다. 이 구성요소는 미디어 프레임워크에서 지원하는 다양한 파일 형식을 파싱합니다. 추출기 서비스는 모든 서비스 중에서 가장 권한이 적으며, FD를 읽지 못하므로 대신 바인더 인터페이스에 호출(각 재생 세션의 mediaserver for에 의해 제공됨)하여 파일에 액세스합니다.

애플리케이션(또는 mediaserver)은 추출기 프로세스를 호출하여 IMediaExtractor를 가져오고, 해당 IMediaExtractor를 호출하여 파일에 포함된 트랙의 IMediaSources를 가져온 다음 IMediaSources를 호출하여 데이터를 읽습니다.

프로세스 간에 데이터를 전송하기 위해 애플리케이션(또는 mediaserver)은 데이터를 바인더 트랜잭션의 일부로 회신 파셀에 포함하거나 공유된 메모리를 사용합니다.

  • 공유된 메모리를 사용하려면 바인더를 추가로 호출하여 공유된 메모리를 공개해야 하지만 대규모 버퍼의 경우 더 빠르고 전력도 훨씬 적게 사용합니다.
  • 인파셀을 사용하려면 추가 복사가 필요하지만 64KB보다 작은 버퍼의 경우 더 빠르고 전력도 훨씬 적게 사용합니다.

구현

MediaDrmMediaCrypto 구성요소를 새로운 mediadrmserver 프로세스로 이동하는 과정을 지원하기 위해서는 공급업체가 보안 버퍼의 할당 메소드를 변경하여 버퍼가 프로세스 간에 공유될 수 있도록 해야 합니다.

이전 Android 릴리스에서는 보안 버퍼가 OMX::allocateBuffer에 의해 mediaserver에 할당되었으며, 아래에 보이는 것처럼 같은 프로세스의 복호화 도중에 사용되었습니다.

그림 2. Android 6.0 이하의 버퍼 할당(미디어 서버에서)

Android 7.0에서는 버퍼 할당 프로세스가 새로운 매커니즘으로 변경되었습니다. 이 매커니즘은 유연성을 제공하는 동시에 기존 구현에 대한 영향을 최소화합니다. MediaDrmMediaCrypto 스택이 포함된 새로운 mediadrmserver 프로세스에서는 버퍼가 다른 방식으로 할당되며, 공급업체는 MediaCodecMediaCrypto에 대한 복호화 작업을 호출할 때 보안 버퍼 핸들이 바인더 전체에 걸쳐 전송될 수 있도록 보안 버퍼를 업데이트해야 합니다.

그림 3. Android 7.0 이상의 버퍼 할당(미디어 서버에서)

네이티브 핸들 사용

OMX::allocateBuffer는 포인터를 native_handle 구조에 반환해야 합니다. 이 구조에는 설명어(FD) 및 추가적인 정수 데이터가 포함되어 있습니다. native_handle은 FD 사용에 따른 모든 이점을 지니고 있으며, 직렬화/역직렬화를 위한 기존 바인더 지원을 포함하는 동시에 현재 FD를 사용하지 않는 공급업체를 위한 추가적인 유연성을 허용할 수 있습니다.

native_handle_create()를 사용하여 네이티브 핸들을 할당합니다. 프레임워크 코드는 할당된 native_handle 구조의 소유권을 가지며, native_handle이 원래 할당된 프로세스와 핸들이 역직렬화된 프로세스 둘 다에 리소스를 방출하는 역할을 합니다. 프레임워크는 native_handle_close()에 이어 native_handle_delete()를 포함하는 네이티브 핸들을 사용하며, Parcel::writeNativeHandle()/readNativeHandle()을 사용하여 native_handle을 직렬화/역직렬화합니다.

FD를 사용하여 보안 버퍼를 표시하는 SoC 공급업체는 자체 FD로 native_handle의 FD를 채울 수 있습니다. FD를 사용하지 않는 공급업체는 native_buffer의 추가 필드를 사용하여 보안 버퍼를 나타낼 수 있습니다.

복호화 위치 설정

공급업체는 native_handle에서 작동하는 OEMCrypto 복호화 메소드를 업데이트하여 native_handle을 새로운 프로세스 공간에서 사용할 수 있도록 하는 데 필요한 모든 공급업체 관련 작업을 수행해야 합니다(일반적으로 변경사항에는 OEMCrypto 라이브러리에 대한 업데이트가 포함됨).

allocateBuffer가 표준 OMX 작업이므로 Android 7.0은 새로운 OMX 확장 프로그램(OMX.google.android.index.allocateNativeHandle)을 포함하여 이러한 지원, 그리고 OMX 구현에 네이티브 핸들을 사용하도록 알리는 OMX_SetParameter에 대한 쿼리를 실시합니다.