정책 호환성

이 문서에서는 새 플랫폼 SELinux 설정이 이전 공급업체 SELinux 설정과 다를 수 있는 플랫폼 OTA 관련 정책 호환성 문제를 Android가 어떻게 처리하는지에 관해 설명합니다.

트레블 기반 SELinux 정책 설계는 플랫폼공급업체 정책 간의 바이너리 차이를 고려합니다. 공급업체 파티션이 종속 항목(예: platform < vendor < oem)을 생성하면 체계가 더 복잡해집니다.

Android 8.0 이상에서는 SELinux 글로벌 정책이 비공개 구성요소와 공개 구성요소로 구분됩니다. 공개 구성요소는 정책 및 관련 인프라로 구성되며 플랫폼 버전에서 확실히 사용할 수 있습니다. 이 정책은 공급업체 정책 작성자에게 공개되므로 공급업체가 공급업체 정책 파일을 빌드할 수 있습니다. 파일이 플랫폼 제공 정책과 결합되면 기기와 관련하여 완전한 기능을 갖춘 정책이 생성됩니다.

  • 버전 관리를 위해 내보낸 플랫폼-공개 정책이 속성으로 작성됩니다.
  • 정책을 쉽게 작성할 수 있도록 내보낸 유형은 정책 빌드 프로세스의 일부로 버전이 지정된 속성으로 변환됩니다. 또한 공급업체 컨텍스트 파일에서 제공하는 라벨 지정 결정에 직접 공개 유형을 사용할 수도 있습니다.

Android는 플랫폼 정책의 내보낸 구체적인 유형과 각 플랫폼 버전에 상응하는 버전이 지정된 속성 간에 매핑을 유지합니다. 이렇게 하면 객체에 유형으로 라벨을 지정할 때 이전 버전의 플랫폼-공개 정책에 의해 보장되는 동작이 중단되지 않습니다. 각 플랫폼 버전의 매핑 파일을 최신 상태로 유지함으로써 이 매핑이 유지 관리되므로 공개 정책에서 내보낸 각 유형의 속성 멤버십 정보가 유지됩니다.

객체 소유권 및 라벨 지정

Android 8.0 이상에서 정책을 맞춤설정할 때 플랫폼 및 공급업체 정책을 별도로 유지하려면 각 객체의 소유권을 명확하게 정의해야 합니다. 예를 들어 공급업체가 /dev/foo 라벨을 지정한 후 플랫폼이 후속 OTA에서 /dev/foo 라벨을 지정하면 정의되지 않은 동작이 발생합니다. SELinux에서는 라벨 지정 충돌로 나타납니다. 기기 노드에는 마지막에 적용된 라벨로 확인되는 라벨이 하나만 있을 수 있습니다. 결과:

  • 성공적으로 적용되지 않은 라벨에 액세스해야 하는 프로세스는 리소스에 대한 액세스 권한을 잃게 됩니다.
  • 잘못된 기기 노드가 생성되었기 때문에 파일에 액세스할 수 있는 프로세스가 중단될 수 있습니다.

또한 시스템 속성은 시스템에서 정의되지 않은 동작을 초래할 수 있는 이름 지정(및 SELinux 라벨 지정) 충돌의 가능성이 있습니다. 플랫폼 및 공급업체 라벨 간의 충돌은 속성, 서비스, 프로세스, 파일 및 소켓을 포함하여 SELinux 라벨이 있는 모든 객체에서 발생할 수 있습니다. 이 문제를 방지하려면 이러한 객체의 소유권을 명확하게 정의해야 합니다.

라벨 충돌 외에도 SELinux 유형/속성 이름도 충돌할 수 있습니다. 유형/속성 이름이 충돌하면 항상 정책 컴파일러 오류가 발생합니다.

유형/속성 네임스페이스 지정

SELinux는 동일한 유형/속성의 여러 선언을 허용하지 않습니다. 중복 선언이 있는 정책은 컴파일에 실패합니다. 유형 및 속성 이름 충돌을 방지하려면 모든 공급업체 선언에 np_로 시작하는 네임스페이스를 지정해야 합니다.

type foo, domain; → type np_foo, domain;

시스템 속성 및 프로세스 라벨 지정 소유권

라벨 지정 충돌은 속성 네임스페이스를 사용하여 가장 잘 방지할 수 있습니다. 내보낸 플랫폼 속성의 이름을 바꾸거나 내보낸 플랫폼 속성을 추가할 때 플랫폼 속성을 쉽게 식별하고 이름 충돌을 피하려면 다음과 같이 모든 공급업체 속성에 고유한 접두사가 있어야 합니다.

속성 유형 허용되는 접두사
제어 속성 ctl.vendor.
ctl.start$vendor.
ctl.stop$vendor.
init.svc.vendor.
읽기 쓰기 가능 vendor.
읽기 전용 ro.vendor.
ro.boot.
ro.hardware.
영구 persist.vendor.

공급업체는 ro.boot.*(커널 cmdline에서 제공) 및 ro.hardware.*(명확한 하드웨어 관련 속성)를 계속 사용할 수 있습니다.

init rc 파일의 모든 공급업체 서비스에는 비 시스템 파티션용 init rc 파일의 서비스를 위한 vendor. 접두사가 있어야 합니다. 유사한 규칙이 공급업체 속성의 SELinux 라벨에 적용됩니다(공급업체 속성의 vendor_).

파일 소유권

플랫폼 및 공급업체 정책은 둘 다 일반적으로 모든 파일 시스템에 라벨을 제공하기 때문에 파일 충돌을 방지하기가 어렵습니다. 유형 이름 지정과는 달리 파일의 네임스페이스 지정은 실용적이지 않습니다. 많은 파일이 커널에 의해 생성되기 때문입니다. 이러한 충돌을 방지하려면 본 섹션의 파일 시스템 이름 지정 지침을 따르세요. Android 8.0에서 이러한 지침은 기술적 시정 조치가 없는 권장사항입니다. 향후 이러한 권장사항은 공급업체 테스트 모음(VTS)에 의해 적용됩니다.

System(/system)

시스템 이미지만 file_contexts, service_contexts 등을 통해 /system 구성요소의 라벨을 제공해야 합니다. /system 구성요소의 라벨이 /vendor 정책에 추가되면 프레임워크 전용 OTA 업데이트가 불가능할 수 있습니다.

Vendor(/vendor)

AOSP SELinux 정책은 플랫폼이 상호작용하는 vendor 파티션의 일부에 이미 라벨을 지정함으로써 플랫폼 프로세스의 SELinux 규칙을 작성하여 vendor 파티션의 일부와 통신하거나 일부에 액세스할 수 있도록 합니다. 예:

/vendor 경로 플랫폼에서 제공하는 라벨 라벨에 따른 플랫폼 프로세스
/vendor(/.*)? vendor_file 프레임워크의 모든 HAL 클라이언트, ueventd
/vendor/framework(/.*)? vendor_framework_file dex2oat, appdomain
/vendor/app(/.*)? vendor_app_file dex2oat, installd, idmap
/vendor/overlay(/.*) vendor_overlay_file system_server, zygote, idmap

결과적으로 vendor 파티션의 추가 파일에 라벨을 지정할 때 다음과 같이 특정 규칙을 따라야 합니다(neverallows를 통해 적용).

  • vendor_file vendor 파티션에서 모든 파일의 기본 라벨이어야 합니다. 플랫폼 정책에서는 이 라벨이 패스 스루 HAL 구현에 액세스하도록 요구합니다.
  • 공급업체 SEPolicy를 통해 vendor 파티션에 추가된 새로운 모든 exec_types에는 vendor_file_type 속성이 있어야 합니다. 이는 neverallows를 통해 적용됩니다.
  • 향후 플랫폼/프레임워크 업데이트와의 충돌을 방지하려면 vendor 파티션에서 exec_types 외의 다른 라벨을 파일에 지정하지 않아야 합니다.
  • AOSP에서 식별한 동일한 프로세스 HAL의 모든 라이브러리 종속 항목에는 same_process_hal_file.로 라벨을 지정해야 합니다.

Procfs(/proc)

/proc의 파일에는 genfscon 라벨만 사용하여 라벨을 지정할 수 있습니다. Android 7.0에서는 플랫폼공급업체 정책이 모두 genfscon을 사용하여 procfs의 파일에 라벨을 지정했습니다.

권장사항: 플랫폼 정책만 /proc에 라벨을 지정합니다. vendor 프로세스에서 현재 기본 라벨(proc)로 라벨이 지정된 /proc의 파일에 액세스해야 한다면 공급업체 정책은 파일에 명시적으로 라벨을 지정해서는 안 되며 대신 일반 proc 유형을 사용하여 공급업체 도메인의 규칙을 추가해야 합니다. 이렇게 하면 플랫폼 업데이트가 procfs를 통해 노출된 향후 커널 인터페이스를 수용하고 필요에 따라 명시적으로 라벨을 지정할 수 있습니다.

Debugfs(/sys/kernel/debug)

file_contextsgenfscon을 둘 다 사용하여 Debugfs에 라벨을 지정할 수 있습니다. Android 7.0부터 Android 10까지는 플랫폼과 공급업체가 모두 debugfs에 라벨을 지정합니다.

Android 11에서는 프로덕션 기기에서 debugfs에 액세스하거나 이를 마운트할 수 없습니다. 기기 제조업체는 debugfs를 삭제해야 합니다.

Tracefs(/sys/kernel/debug/tracing)

file_contextsgenfscon을 둘 다 사용하여 Tracefs에 라벨을 지정할 수 있습니다. Android 7.0에서는 플랫폼만 tracefs에 라벨을 지정합니다.

권장사항: 플랫폼만 tracefs에 라벨을 지정할 수 있습니다.

Sysfs(/sys)

file_contextsgenfscon을 둘 다 사용하여 /sys의 파일에 라벨을 지정할 수 있습니다. Android 7.0에서는 플랫폼 및 공급업체가 모두 file_contextsgenfscon을 사용하여 sysfs의 파일에 라벨을 지정합니다.

권장사항: 플랫폼은 기기에 고유하지 않은 sysfs 노드에 라벨을 지정할 수 있습니다. 노드가 기기에 고유하다면 공급업체만 파일에 라벨을 지정할 수 있습니다.

tmpfs(/dev)

file_contexts를 사용하여 /dev의 파일에 라벨을 지정할 수 있습니다. Android 7.0에서는 플랫폼 및 공급업체가 모두 이 경로의 파일에 라벨을 지정합니다.

권장사항: 공급업체는 /dev/vendor(예: /dev/vendor/foo, /dev/vendor/socket/bar)의 파일에만 라벨을 지정할 수 있습니다.

Rootfs(/)

file_contexts를 사용하여 /의 파일에 라벨을 지정할 수 있습니다. Android 7.0에서는 플랫폼 및 공급업체가 모두 이 경로의 파일에 라벨을 지정합니다.

권장사항: 시스템만 /의 파일에 라벨을 지정할 수 있습니다.

Data(/data)

file_contextsseapp_contexts의 조합을 통해 데이터에 라벨을 지정할 수 있습니다.

권장사항: /data/vendor 외부에서의 공급업체 라벨 지정을 허용하지 않습니다. 플랫폼만 /data의 다른 부분에 라벨을 지정할 수 있습니다.

호환성 속성

SELinux 정책은 특정 객체 클래스 및 권한의 소스 유형과 타겟 유형 간의 상호작용입니다. SELinux 정책의 영향을 받는 모든 객체(프로세스, 파일 등)에는 하나의 유형만 있더라도 유형에는 여러 속성이 있을 수 있습니다.

다음과 같이 정책은 주로 기존 유형 측면에서 작성됩니다.

allow source_type target_type:target_class permission(s);

즉, 정책이 모든 유형을 숙지한 상태에서 작성되었기 때문에 효과가 있습니다. 그러나 공급업체 정책 및 플랫폼 정책이 특정 유형을 사용하고 특정 객체의 라벨이 이러한 정책 중 하나에서만 변경된다면 다른 정책에는 이전에 사용했던 액세스 권한을 얻거나 잃은 정책이 포함될 수 있습니다. 예:

File_contexts:
/sys/A   u:object_r:sysfs:s0
Platform: allow p_domain sysfs:class perm;
Vendor: allow v_domain sysfs:class perm;

다음으로 변경할 수 있습니다.

File_contexts:
/sys/A   u:object_r:sysfs_A:s0

공급업체 정책은 동일하게 유지되지만 새로운 sysfs_A 유형의 정책이 없기 때문에 v_domain은 액세스 권한을 잃게 됩니다.

속성 측면에서 정책을 정의함으로써 플랫폼 및 공급업체 코드 모두의 정책에 상응하는 속성이 있는 유형을 기본 객체에 제공할 수 있습니다. 모든 유형에서 이렇게 하면 구체적인 유형이 사용되지 않는 attribute-policy를 효과적으로 생성할 수 있습니다. 실제로 이 작업은 플랫폼과 공급업체 간에 중복되는 정책 부분(공급업체 정책의 일부로 구축되는 플랫폼 공개 정책으로 정의 및 제공됨)에만 필요합니다.

공개 정책을 버전이 지정된 속성으로 정의하면 다음과 같은 두 가지 정책 호환성 목표가 충족됩니다.

  • 플랫폼 업데이트 이후에도 공급업체 코드가 계속 작동해야 합니다. 공급업체 코드에 사용된 객체에 상응하는 객체의 구체적인 유형에 속성을 추가하고 액세스를 유지하여 지속적인 작동이 구현됩니다.
  • 정책을 지원 중단할 수 있어야 합니다. 이 기능은 상응하는 버전이 더 이상 지원되지 않는 즉시 삭제할 수 있는 속성으로 정책 세트를 명확하게 구분함으로써 구현됩니다. 이전 정책이 공급업체 정책에 여전히 존재하지만 업그레이드 시 자동으로 삭제된다는 점을 인식하면서 플랫폼에서 개발을 계속할 수 있습니다.

정책 쓰기 가능

정책 개발에 특정 버전 변경 관련 지식이 필요하지 않아야 한다는 목표를 충족하기 위해 Android 8.0에는 플랫폼-공개 정책 유형과 상응하는 속성 간의 매핑이 포함되어 있습니다. foo 유형은 foo_vN 속성에 매핑됩니다. 여기서 N은 타겟 버전입니다. vNPLATFORM_SEPOLICY_VERSION 빌드 변수이며 MM.NN 형식입니다. 여기서 MM은 플랫폼 SDK 번호이며 NN은 플랫폼 SEPolicy 관련 버전입니다.

공개 정책의 속성은 버전이 지정되지 않으며, 대신 플랫폼 및 공급업체 정책을 빌드하여 두 파티션 간의 인터페이스를 안정적으로 유지할 수 있는 API로 존재합니다. 플랫폼 및 공급업체 정책 작성자는 모두 현재 작성된 대로 정책을 계속 작성할 수 있습니다.

allow source_foo target_bar:class perm;으로 내보낸 플랫폼-공개 정책은 공급업체 정책의 일부로 포함됩니다. 컴파일(상응하는 버전 포함) 과정에서 이 정책은 기기의 공급업체 부분으로 전달되는 정책으로 변환됩니다. 아래의 변환된 CIL(Common Intermediate Language)을 참조하세요.

 (allow source_foo_vN target_bar_vN (class (perm)))

공급업체 정책은 플랫폼보다 앞서지 않기 때문에 이전 버전과 관계가 있으면 안 됩니다. 그러나 플랫폼 정책은 공급업체 정책이 얼마나 뒤떨어져 있는지를 파악하고 유형에 속성을 포함하며 버전이 지정된 속성에 상응하는 정책을 설정해야 합니다.

정책의 차이

각 유형의 끝에 _vN을 추가하여 속성을 자동으로 생성하면 버전 차이에 따른 유형에 속성을 매핑하는 작업 외에는 아무것도 하지 않습니다. Android는 속성의 버전 간 매핑과 속성과 유형 간 매핑을 유지 관리합니다. 이는 앞서 언급한 매핑 파일에서 다음 CIL과 같은 구문을 사용하여 실행됩니다.

(typeattributeset foo_vN (foo))

플랫폼 업그레이드

다음 섹션에서는 플랫폼 업그레이드 시나리오를 자세히 설명합니다.

동일한 유형

이 시나리오는 객체가 정책 버전에서 라벨을 변경하지 않을 때 발생합니다. 이는 소스 및 타겟 유형에 동일하며 모든 릴리스에서 binder_device 라벨이 지정된 /dev/binder에서 볼 수 있습니다. 변환된 정책에서 다음과 같이 표현됩니다.

binder_device_v1 … binder_device_vN

v1v2로 업그레이드할 때 플랫폼 정책에는 다음이 포함되어야 합니다.

type binder_device; -> (type binder_device) (in CIL)

v1 매핑 파일(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattributeset binder_device_v1 (binder_device))

v2 매핑 파일(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattributeset binder_device_v2 (binder_device))

v1 공급업체 정책(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattribute binder_device_v1)
(allow binder_device_v1 …)

v2 공급업체 정책(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattribute binder_device_v2)
(allow binder_device_v2 …)
새로운 유형

이 시나리오는 플랫폼이 새로운 유형을 추가했을 때 발생하며, 새로운 유형 추가는 새로운 기능을 추가할 때 또는 정책을 강화하는 동안 발생할 수 있습니다.

  • 새로운 기능. 유형이 이전에 존재하지 않은 객체(예: 새 서비스 프로세스)에 라벨을 지정할 때 공급업체 코드가 이전에 객체와 직접 상호작용하지 않았으므로 상응하는 정책이 존재하지 않습니다. 유형에 상응하는 새 속성은 이전 버전의 속성을 보유하지 않으므로 버전을 타겟팅하는 매핑 파일에 항목이 필요하지 않습니다.
  • 정책 강화. 유형이 정책 강화를 나타낼 때 새로운 유형 속성은 이전 유형에 상응하는 속성 체인에 다시 연결되어야 합니다(이전 예와 유사하게 /sys/Asysfs에서 sysfs_A로 변경). 공급업체 코드는 sysfs에 액세스할 수 있는 규칙을 사용하고 이 규칙을 새 유형의 속성으로 포함해야 합니다.

v1v2로 업그레이드할 때 플랫폼 정책에는 다음이 포함되어야 합니다.

type sysfs_A; -> (type sysfs_A) (in CIL)
type sysfs; (type sysfs) (in CIL)

v1 매핑 파일(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattributeset sysfs_v1 (sysfs sysfs_A))

v2 매핑 파일(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattributeset sysfs_v2 (sysfs))
(typeattributeset sysfs_A_v2 (sysfs_A))

v1 공급업체 정책(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

v2 공급업체 정책(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattribute sysfs_A_v2)
(allow … sysfs_A_v2 …)
(typeattribute sysfs_v2)
(allow … sysfs_v2 …)
삭제된 유형

이 (드문) 시나리오는 유형이 삭제될 때 발생하며, 유형 삭제는 기본 객체가 다음과 같을 때 발생할 수 있습니다.

  • 기본 객체가 유지되지만 다른 라벨을 받습니다.
  • 기본 객체가 플랫폼에 의해 삭제됩니다.

정책이 완화되는 동안 유형이 삭제되고 이 유형으로 라벨이 지정된 객체에 기존의 다른 라벨이 지정됩니다. 이는 속성 매핑의 병합을 나타냅니다. 공급업체 코드는 보유하고 있던 속성으로 기본 객체에 여전히 액세스할 수 있어야 하지만 나머지 시스템은 이제 새로운 속성으로 기본 객체에 액세스할 수 있어야 합니다.

전환된 속성이 새 속성이라면 라벨 재지정은 새 유형의 사례와 동일하지만 단, 기존 라벨 사용 시 이전 속성의 새 유형을 추가하면 이 유형으로 라벨이 지정된 다른 객체도 새롭게 액세스할 수 있다는 점은 다릅니다. 이는 본질적으로 플랫폼에서 하는 작업이며 호환성을 유지하기 위해 허용되는 절충점으로 간주됩니다.

(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

버전 1 예: 축소 유형(sysfs_A 삭제)

v1v2로 업그레이드할 때 플랫폼 정책에는 다음이 포함되어야 합니다.

type sysfs; (type sysfs) (in CIL)

v1 매핑 파일(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattributeset sysfs_v1 (sysfs))
(type sysfs_A) # in case vendors used the sysfs_A label on objects
(typeattributeset sysfs_A_v1 (sysfs sysfs_A))

v2 매핑 파일(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattributeset sysfs_v2 (sysfs))

v1 공급업체 정책(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattribute sysfs_A_v1)
(allow … sysfs_A_v1 …)
(typeattribute sysfs_v1)
(allow … sysfs_v1 …)

v2 공급업체 정책(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattribute sysfs_v2)
(allow … sysfs_v2 …)

버전 2 예: 완전히 삭제(foo 유형)

v1v2로 업그레이드할 때 플랫폼 정책에는 다음이 포함되어야 합니다.

# nothing - we got rid of the type

v1 매핑 파일(CIL)에서 다음과 같은 구문을 사용합니다.

(type foo) #needed in case vendors used the foo label on objects
(typeattributeset foo_v1 (foo))

v2 매핑 파일(CIL)에서 다음과 같은 구문을 사용합니다.

# nothing - get rid of it

v1 공급업체 정책(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattribute foo_v1)
(allow foo …)
(typeattribute sysfs_v1)
(allow sysfs_v1 …)

v2 공급업체 정책(CIL)에서 다음과 같은 구문을 사용합니다.

(typeattribute sysfs_v2)
(allow sysfs_v2 …)
새로운 클래스/권한

이 시나리오는 플랫폼 업그레이드로 인해 이전 버전에는 없는 새로운 정책 구성요소가 도입될 때 발생합니다. 예를 들어 Android가 추가, 찾기 및 나열 권한을 생성한 servicemanager 객체 관리자를 추가할 때 servicemanager에 등록하려는 공급업체 데몬은 사용할 수 없었던 권한이 필요로 했습니다. Android 8.0에서는 플랫폼 정책만 새 클래스 및 권한을 추가할 수 있습니다.

공급업체 정책에서 생성 또는 확장할 수 있는 모든 도메인이 방해 없이 새 클래스를 사용할 수 있게 하려면 플랫폼 정책에 다음과 유사한 규칙이 포함되어야 합니다.

allow {domain -coredomain} *:new_class perm;

여기서 공급업체 이미지가 액세스 권한을 얻을 수 있도록 모든 인터페이스(공개 정책) 유형으로의 액세스를 허용하는 정책이 필요할 수도 있습니다. 이로 인해 허용되지 않는 보안 정책이 초래되면(servicemanager 변경과 마찬가지로) 공급업체 업그레이드가 강제로 발생할 수 있습니다.

삭제된 클래스/권한

이 시나리오는 ZygoteConnection 객체 관리자와 같은 객체 관리자가 삭제될 때 발생하며 문제를 일으키지 않습니다. 객체 관리자 클래스 및 권한은 공급업체 버전에 의해 더 이상 사용되지 않을 때까지 정책에 정의된 상태로 남아 있을 수 있습니다. 이는 상응하는 매핑 파일에 정의를 추가하여 실행됩니다.

새 유형 및 라벨 재지정 유형의 공급업체 맞춤설정

새로운 공급업체 유형은 새로운 프로세스, 바이너리, 기기, 하위 시스템 및 저장된 데이터를 설명하는 데 필요하므로 공급업체 정책 개발의 핵심입니다. 따라서 공급업체 정의 유형을 생성할 수 있어야 합니다.

공급업체 정책은 항상 기기에서 가장 오래된 정책이므로 모든 공급업체 유형을 정책의 속성으로 자동으로 변환할 필요는 없습니다. 플랫폼은 공급업체 정책에서 라벨이 지정된 어떤 것에 의존하지 않습니다. 플랫폼은 라벨 지정에 관해 알지 못하기 때문입니다. 그러나 플랫폼은 이러한 유형으로 라벨이 지정된 객체와 상호작용하는 데 사용하는 속성 및 공개 유형을 제공합니다(예: domain, sysfs_type 등). 플랫폼이 이러한 객체와 계속 올바르게 상호작용하도록 하려면 속성 및 유형을 적절하게 적용해야 하며 맞춤설정 가능한 도메인에 특정 규칙을 추가해야 할 수도 있습니다(예: init).

Android 9의 속성 변경사항

Android 9로 업그레이드하는 기기는 다음 속성을 사용할 수 있지만 Android 9로 실행되는 기기는 다음 속성을 사용하지 않아야 합니다.

위반자 속성

Android 9에는 다음과 같은 도메인 관련 속성이 포함되어 있습니다.

  • data_between_core_and_vendor_violators. vendorcoredomains 간 경로를 통해 파일을 공유하지 않아야 하는 요구사항을 위반하는 모든 도메인의 속성입니다. 플랫폼 및 공급업체 프로세스는 온디스크 파일을 사용하여 통신해서는 안 됩니다(불안정한 ABI). 권장사항
    • 공급업체 코드는 /data/vendor를 사용해야 합니다.
    • 시스템은 /data/vendor를 사용하지 않아야 합니다.
  • system_executes_vendor_violators. 공급업체 바이너리를 실행하지 않아야 하는 요구사항을 위반하는 모든 시스템 도메인(initshell domains 제외)의 속성입니다. 공급업체 바이너리를 실행하면 API가 불안정해집니다. 플랫폼은 공급업체 바이너리를 직접 실행해서는 안 됩니다. 권장사항
    • 공급업체 바이너리에 과한 이러한 플랫폼 종속 항목은 HIDL HAL 뒤에 있어야 합니다.

      또는

    • 공급업체 바이너리에 액세스해야 하는 coredomains는 공급업체 파티션으로 이동되어야 합니다. 따라서 coredomain이 되지 않아야 합니다.

신뢰할 수 없는 속성

임의 코드를 호스팅하는 신뢰할 수 없는 앱은 HwBinder 서비스에 액세스해서는 안 됩니다. 단, 이러한 앱에서 액세스해도 충분히 안전한 것으로 간주되는 때는 예외입니다(아래의 안전 서비스 참조). 이와 관련한 두 가지 주요 이유는 다음과 같습니다.

  1. HIDL은 현재 호출자 UID 정보를 노출하지 않으므로 HwBinder 서버는 클라이언트 인증을 실행하지 않습니다. HIDL이 그러한 데이터를 노출했더라도 많은 HwBinder 서비스는 앱보다 낮은 수준(예: HAL)에서 작동하거나 승인에 앱 ID를 사용해서는 안 됩니다. 따라서 보안을 위해 모든 HwBinder 서비스는 모든 클라이언트가 서비스에서 제공하는 작업을 실행할 수 있는 권한을 똑같이 부여받았다고 간주하는 것이 기본 가정입니다.
  2. HAL 서버(HwBinder 서비스의 하위 집합)는 system/core 구성요소보다 보안 문제 발생률이 더 높은 코드를 포함하고 있으며 스택의 하위 레이어(하드웨어에 이르기까지)에 액세스할 수 있으므로 Android 보안 모델을 우회할 기회가 증가합니다.

안전 서비스

안전 서비스에는 다음이 포함됩니다.

  • same_process_hwservice. 이러한 서비스는 정의에 따라 클라이언트 프로세스에서 실행되므로 프로세스가 실행되는 클라이언트 도메인과 동일한 액세스 권한을 갖습니다.
  • coredomain_hwservice. 이러한 서비스는 이유 2와 관련된 위험을 초래하지 않습니다.
  • hal_configstore_ISurfaceFlingerConfigs. 이 서비스는 어떤 도메인에서도 사용할 수 있도록 특별히 설계되었습니다.
  • hal_graphics_allocator_hwservice. 이러한 작업은 surfaceflinger 바인더 서비스에 의해서도 제공되며, 앱은 액세스가 허용됩니다.
  • hal_omx_hwservice. 이 서비스는 mediacodec 바인더 서비스의 HwBinder 버전으로, 앱은 액세스가 허용됩니다.
  • hal_codec2_hwservice. 이 서비스는 hal_omx_hwservice의 최신 버전입니다.

유용한 속성

안전하지 않은 것으로 간주되는 모든 hwservices에는 untrusted_app_visible_hwservice 속성이 있습니다. 상응하는 HAL 서버에는 untrusted_app_visible_halserver 속성이 있습니다. Android 9로 실행되는 기기는 untrusted 속성을 사용해서는 안 됩니다.

권장사항:

  • 신뢰할 수 없는 앱은 대신 공급업체 HIDL HAL과 통신하는 시스템 서비스와 통신해야 합니다. 예를 들어 앱이 binderservicedomain과 통신할 수 있으며 결과적으로 mediaserver(이는 binderservicedomain임)가 hal_graphics_allocator와 통신합니다.

    또는

  • vendor HAL에 직접 액세스해야 하는 앱은 자체적인 공급업체 정의 SEPolicy 도메인을 보유해야 합니다.

파일 속성 테스트

Android 9에는 특정 위치의 모든 파일에 적절한 속성이 있는지 확인하는 빌드 시간 테스트가 포함되어 있습니다(예: sysfs의 모든 파일에는 필수 sysfs_type 속성이 있음).

플랫폼-공개 정책

플랫폼-공개 정책은 v1 및 v2의 플랫폼 정책 통합을 유지하지 않고 Android 8.0 아키텍처 모델을 준수하는 핵심입니다. 공급업체는 사용 가능한 유형 및 속성과 이러한 유형 및 속성의 규칙을 포함하며 이후 공급업체 정책(예: vendor_sepolicy.cil)의 일부가 되는 플랫폼 정책의 하위 집합에 노출됩니다.

공급업체 생성 정책에서 유형 및 규칙은 자동으로 attribute_vN으로 변환됩니다. 따라서 모든 플랫폼 제공 유형은 버전이 지정된 속성입니다(하지만 속성은 버전이 지정되지 않음). 플랫폼은 제공한 구체적인 유형을 적절한 속성에 매핑하여 공급업체 정책이 계속 작동하고 특정 버전에 제공된 규칙이 포함될 수 있도록 해야 합니다. 플랫폼-공개 정책과 공급업체 정책의 조합은 독립적인 플랫폼 및 공급업체 빌드를 허용하려는 Android 8.0 아키텍처 모델 목표를 충족합니다.

속성 체인에 매핑

속성을 사용하여 정책 버전에 매핑할 때 유형은 한 속성 또는 여러 속성에 매핑되므로 유형으로 라벨이 지정된 객체는 이전 유형에 상응하는 속성을 통해 액세스할 수 있습니다.

정책 작성자의 버전 정보를 숨기려는 목표를 유지한다는 것은 버전이 지정된 속성을 자동으로 생성하여 적절한 유형에 할당하는 것을 의미합니다. 정적 유형의 일반적인 사례에서 이는 간단합니다. type_footype_foo_v1에 매핑됩니다.

sysfssysfs_A 또는 mediaserveraudioserver와 같은 객체 라벨 변경 시에는 이 매핑을 만드는 것이 그리 간단하지 않습니다(위의 예에 설명되어 있음). 플랫폼 정책 운영자는 객체의 전환 지점에서 매핑을 만드는 방법을 결정해야 합니다. 이를 위해서는 객체와 할당된 라벨 간의 관계를 이해하고 매핑 발생 시기를 결정해야 합니다. 이전 버전과의 호환성을 위해서는 업데이트할 수 있는 유일한 파티션인 플랫폼 측면에서 이 복잡성을 관리해야 합니다.

버전 업데이트

단순화하기 위해 Android 플랫폼은 새 릴리스 브랜치가 삭제될 때 SEPolicy 버전을 출시합니다. 위에서 설명한 것처럼 버전 번호는 PLATFORM_SEPOLICY_VERSION에 포함되며 MM.nn 형식입니다. 여기서 MM은 SDK 값이며 nn /platform/system/sepolicy.에 유지되는 비공개 값입니다. 예를 들어 Kitkat은 19.0, Lollipop은 21.0, Lollipop-MR1은 22.0, Marshmallow는 23.0, Nougat은 24.0, Nougat-MR1은 25.0, Oreo는 26.0, Oreo-MR1은 27.0 그리고 Android 9는 28.0입니다. 업데이트 버전 번호가 항상 정수가 되는 것은 아닙니다. 예를 들어 버전의 MR 범프로 인해 system/sepolicy/public에서 호환되지 않는 변경이 필요하지만 API 범프는 필요하지 않다면 SEPolicy 버전은 vN.1이 될 수 있습니다. 개발 브랜치에 있는 버전은 never-to-be-used-in-shipping-devices 10000.0입니다.

Android는 업데이트 시 가장 오래된 버전을 지원 중단할 수 있습니다. 버전을 지원 중단할 시기에 관한 정보를 입력하기 위해 Android는 특정 Android 버전을 실행하고 여전히 주요 플랫폼 업데이트를 수신하는 공급업체 정책이 있는 기기의 수를 수집할 수 있습니다. 기기의 수가 특정 임계값보다 작으면 상응하는 버전은 지원 중단됩니다.

여러 속성의 성능 영향

https://github.com/SELinuxProject/cil/issues/9에 설명된 대로 한 유형에 다수의 속성이 할당되면 정책 캐시 누락 시 성능 문제가 발생합니다.

이는 Android에서 문제로 확인되었으므로 정책 컴파일러가 정책에 추가한 속성을 삭제할 뿐만 아니라 사용하지 않는 속성을 삭제하도록 Android 8.0을 변경하였습니다. 이러한 변경으로 인해 성능 회귀가 해결되었습니다.

System_ext 공개 및 제품 공개 정책

Android 11부터 system_ext 및 제품 파티션이 지정된 공개 유형을 공급업체 파티션으로 내보낼 수 있습니다. 플랫폼 공개 정책과 마찬가지로 공급업체는 버전이 지정된 속성으로 자동 변환되는 유형과 규칙을 사용합니다. 예를 들어 type에서 type_N으로 변환되는데 여기서 N은 공급업체 파티션이 빌드되는 플랫폼의 버전입니다.

system_ext 및 제품 파티션이 동일한 플랫폼 버전 N을 기반으로 하는 경우 빌드 시스템은 type에서 type_N로의 ID 매핑이 포함된 system_ext/etc/selinux/mapping/N.cilproduct/etc/selinux/mapping/N.cil의 기본 매핑 파일을 생성합니다. 공급업체는 버전이 지정된 속성 type_N으로 type에 액세스할 수 있습니다.

공급업체가 N을 유지하는 동안 system_ext와 제품 파티션만 업데이트되는 경우(예: N에서 N+1 이상으로) 공급업체는 system_ext 및 제품 파티션 유형에 대한 액세스 권한을 잃을 수 있습니다. 손상을 방지하려면 system_ext 및 제품 파티션은 구체적인 유형의 매핑 파일을type_N 속성으로 제공해야 합니다. 각 파트너는 N+1 이상의 system_ext 및 제품 파티션으로 N 공급업체를 지원하려는 경우 매핑 파일을 유지관리해야 합니다.

이를 위해 파트너는 다음을 실행해야 합니다.

  1. 생성된 기본 매핑 파일을 N system_ext 및 제품 파티션 에서 소스 트리로 복사합니다.
  2. 필요에 따라 매핑 파일을 수정합니다.
  3. N+1(또는 그 이상) system_ext 및 제품 파티션에 매핑 파일을 설치합니다.

예를 들어 N system_ext에 foo_type이라는 공개 유형이 하나 있다고 가정해 보겠습니다. 그러면 N system_ext 파티션의 system_ext/etc/selinux/mapping/N.cil은 다음과 같습니다.

(typeattributeset foo_type_N (foo_type))
(expandtypeattribute foo_type_N true)
(typeattribute foo_type_N)

bar_typeN+1 system_ext에 추가되고 bar_typeN 공급업체의 foo_type에 매핑되어야 하는 경우 N.cil

(typeattributeset foo_type_N (foo_type))

위와 같은 형식에서 아래와 같은 형식으로 업데이트할 수 있습니다.

(typeattributeset foo_type_N (foo_type bar_type))

그런 다음 N+1 system_ext의 파티션에 설치됩니다. N 공급업체는 N+1 system_ext의 foo_typebar_type에 계속 액세스할 수 있습니다.

SELinux 컨텍스트 라벨 지정

플랫폼 sepolicy와 공급업체 sepolicy 사이의 구별을 지원하기 위해 시스템은 SELinux 컨텍스트 파일을 다르게 빌드하여 별도로 분리합니다.

파일 컨텍스트

Android 8.0에서는 다음과 같은 file_contexts 관련 변경사항을 도입했습니다.

  • 부팅 시 기기의 추가 컴파일 오버헤드를 방지하기 위해 file_contexts는 이제 바이너리 형식으로 존재하지 않습니다. 대신 {property, service}_contexts와 같은 읽기 쉬운 정규 표현식 텍스트 파일로 존재합니다(7.0 이전과 같음).
  • file_contexts는 다음과 같은 두 파일로 나뉩니다.
    • plat_file_contexts
      • 기기별 라벨이 없는 Android 플랫폼 file_context입니다. 단, sepolicy 파일이 제대로 작동할 수 있도록 정확하게 라벨이 지정되어야 하는 /vendor 파티션의 일부에는 라벨을 지정합니다.
      • 기기의 system 파티션에 있는 /system/etc/selinux/plat_file_contexts에 상주해야 하며 시작 시 공급업체 file_context와 함께 init에 의해 로드되어야 합니다.
    • vendor_file_contexts
      • 기기 Boardconfig.mk 파일의 BOARD_SEPOLICY_DIRS가 가리키는 디렉터리에 있는 file_contexts를 결합하여 빌드한 기기별 file_context입니다.
      • vendor 파티션의 /vendor/etc/selinux/vendor_file_contexts에 설치되어야 하며 시작 시 플랫폼 file_context와 함께 init에 의해 로드되어야 합니다.

속성 컨텍스트

Android 8.0에서 property_contexts는 다음과 같은 두 파일로 나뉩니다.

  • plat_property_contexts
    • 기기별 라벨이 없는 Android 플랫폼 property_context입니다.
    • system 파티션에 있는 /system/etc/selinux/plat_property_contexts에 상주해야 하며 시작 시 공급업체 property_contexts와 함께 init에 의해 로드되어야 합니다.
  • vendor_property_contexts
    • 기기 Boardconfig.mk 파일의 BOARD_SEPOLICY_DIRS가 가리키는 디렉터리에 있는 property_contexts를 결합하여 빌드한 기기별 property_context입니다.
    • vendor 파티션에 있는 /vendor/etc/selinux/vendor_property_contexts에 상주해야 하며 시작 시 플랫폼 property_context와 함께 init에 의해 로드되어야 합니다.

서비스 컨텍스트

Android 8.0에서 service_contexts는 다음과 같은 파일로 나뉩니다.

  • plat_service_contexts
    • servicemanager를 위한 Android 플랫폼별 service_context이며 service_context에는 기기별 라벨이 없습니다.
    • system 파티션에 있는 /system/etc/selinux/plat_service_contexts에 상주해야 하며 시작 시 공급업체 service_contexts와 함께 servicemanager에 의해 로드되어야 합니다.
  • vendor_service_contexts
    • 기기 Boardconfig.mk 파일의 BOARD_SEPOLICY_DIRS가 가리키는 디렉터리에 있는 service_contexts를 결합하여 빌드한 기기별 service_context입니다.
    • vendor 파티션에 있는 /vendor/etc/selinux/vendor_service_contexts에 상주해야 하며 시작 시 플랫폼 service_contexts와 함께 servicemanager에 의해 로드되어야 합니다.
    • servicemanager는 부팅 시 이 파일을 찾지만 완벽하게 준수하는 TREBLE 기기에서는 vendor_service_contexts가 존재하지 않아야 합니다. vendor 프로세스와 system 프로세스 간의 모든 상호작용이 반드시 hwservicemanager/hwbinder를 거쳐야 하기 때문입니다.
  • plat_hwservice_contexts
    • hwservicemanager를 위한 Android 플랫폼 hwservice_context로, 기기별 라벨이 없습니다.
    • system 파티션에 있는 /system/etc/selinux/plat_hwservice_contexts에 상주해야 하며 시작 시 vendor_hwservice_contexts와 함께 hwservicemanager에 의해 로드되어야 합니다.
  • vendor_hwservice_contexts
    • 기기 Boardconfig.mk 파일의 BOARD_SEPOLICY_DIRS가 가리키는 디렉터리에 있는 hwservice_contexts를 결합하여 빌드한 기기별 hwservice_context입니다.
    • vendor 파티션에 있는 /vendor/etc/selinux/vendor_hwservice_contexts에 상주해야 하며 시작 시 plat_service_contexts와 함께 hwservicemanager에 의해 로드되어야 합니다.
  • vndservice_contexts
    • 기기 Boardconfig.mk 파일의 BOARD_SEPOLICY_DIRS가 가리키는 디렉터리에 있는 vndservice_contexts를 결합하여 빌드한 vndservicemanager를 위한 기기별 service_context입니다.
    • 이 파일은 vendor 파티션에 있는 /vendor/etc/selinux/vndservice_contexts에 상주해야 하며 시작 시 vndservicemanager에 의해 로드되어야 합니다.

Seapp 컨텍스트

Android 8.0에서 seapp_contexts는 다음과 같은 두 파일로 나뉩니다.

  • plat_seapp_contexts
    • 기기별 변경사항이 없는 Android 플랫폼 seapp_context입니다.
    • system 파티션에 있는 /system/etc/selinux/plat_seapp_contexts.에 상주해야 합니다.
  • vendor_seapp_contexts
    • 기기 Boardconfig.mk 파일의 BOARD_SEPOLICY_DIRS가 가리키는 디렉터리에 있는 seapp_contexts를 결합하여 빌드한 플랫폼 seapp_context의 기기별 확장입니다.
    • vendor 파티션에 있는 /vendor/etc/selinux/vendor_seapp_contexts에 상주해야 합니다.

MAC 권한

Android 8.0에서 mac_permissions.xml는 다음과 같은 두 파일로 나뉩니다.

  • 플랫폼mac_permissions.xml
    • 기기별 변경사항이 없는 Android 플랫폼 mac_permissions.xml입니다.
    • system 파티션에 있는 /system/etc/selinux/.에 상주해야 합니다.
  • 비 플랫폼 mac_permissions.xml
    • 기기 Boardconfig.mk 파일의 BOARD_SEPOLICY_DIRS가 가리키는 디렉터리에 있는 mac_permissions.xml에서 빌드한 플랫폼 mac_permissions.xml의 기기별 확장입니다.
    • vendor 파티션에 있는 /vendor/etc/selinux/.에 상주해야 합니다.