ポリシーの互換性

この記事では、Android がプラットフォーム OTA におけるポリシーの互換性の問題を処理する方法を説明します。互換性の問題は、新しいプラットフォーム SELinux 設定が、以前のベンダー SELinux 設定と異なる場合に生じます。

Treble ベースの SELinux ポリシー設計では、プラットフォーム ポリシーとベンダー ポリシーのバイナリ差異が考慮されます。ベンダー パーティションによって依存関係(platform < vendor < oem など)が生成される場合は、スキームがさらに複雑になります。

Android 8.0 以上では、SELinux グローバル ポリシーはプライベート コンポーネントとパブリック コンポーネントに分割されています。パブリック コンポーネントは、ポリシーおよび関連するインフラストラクチャで構成されます。これらは特定のプラットフォーム バージョンで利用できることが保証されています。このポリシーは、ベンダー ポリシーの作成者に公開され、ベンダーはこれに基づいてベンダー ポリシー ファイルを作成できるようになります。これをプラットフォームから提供されるポリシーと組み合わせることで、デバイスで完全に機能するポリシーが完成します。

  • バージョニングのため、エクスポートされたプラットフォーム パブリック ポリシーは「属性」として記述されます。
  • ポリシーの作成を容易にするため、エクスポートされたタイプはポリシー作成プロセスの一環として、「バージョニングされた属性」に変換されます。パブリック タイプは、ベンダーのコンテキスト ファイルによるラベル付けの決定に直接使用することもできます。

Android では、プラットフォーム ポリシーにエクスポートされたコンクリート タイプと、それに対応する、プラットフォーム バージョンごとにバージョニングされた属性とのマッピングが維持されます。したがって、オブジェクトがタイプによってラベル付けされていても、以前のバージョンのプラットフォーム パブリック ポリシーで保証されていた動作が機能しなくなることはありません。このマッピングを維持するため、マッピング ファイルはプラットフォームのバージョンごとに最新の状態に保たれています。これにより、パブリック ポリシーにエクスポートされた各タイプの属性メンバーシップ情報が保持されます。

オブジェクトのオーナーシップとラベル付け

Android 8.0 以上でポリシーをカスタマイズする場合、プラットフォームとベンダーのポリシーを分離するため、オブジェクトごとにオーナーシップを明確に定義する必要があります。たとえば、ベンダーが /dev/foo とラベル付けし、その後 OTA でプラットフォームが /dev/foo とラベル付けした場合、未定義の動作になります。SELinux の場合、これはラベル付けの競合になります。デバイスノードには 1 つのラベルしか付けられないため、最後に適用されたラベルが有効になります。その結果、次のことが起こります。

  • 適用に失敗したラベルへのアクセスを必要とするプロセスは、リソースにアクセスできなくなります。
  • ファイルへのアクセス権を獲得したプロセスは、間違ったデバイスノードが作成されたことが原因で障害を起こす可能性があります。

システム プロパティでも名前の競合が発生し、その結果システムで(および 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)

システム イメージでのみ、file_contextsservice_contexts などを使用して、/system コンポーネントにラベルを付ける必要があります。/vendor ポリシーで /system コンポーネントにラベルを追加すると、フレームワークのみの OTA アップデートができなくなる可能性があります。

ベンダー(/vendor)

AOSP SELinux ポリシーは、プラットフォームが操作する vendor パーティションの各領域にすでにラベルを付けているため、プラットフォーム プロセス用の SELinux ルールを作成すれば、vendor パーティションの各領域に対する通信またはアクセスが可能になります。例:

/vendor パス プラットフォーム提供のラベル ラベルに依存するプラットフォーム プロセス
/vendor(/.*)? vendor_file フレームワークのすべての HAL クライアント(ueventd など)
/vendor/framework(/.*)? vendor_framework_file dex2oatappdomain など
/vendor/app(/.*)? vendor_app_file dex2oatinstalldidmap など
/vendor/overlay(/.*) vendor_overlay_file system_serverzygoteidmap など

この結果、vendor パーティションの追加ファイルにラベルを付ける場合は、特定のルール(neverallows を通じて適用されます)に従う必要があります。

  • vendor パーティション内では、すべてのファイルに対して vendor_file をデフォルトのラベルにする必要があります。プラットフォーム ポリシーでは、これがパススルー HAL 実装にアクセスする必要があります。
  • ベンダーの SEPolicy によって vendor パーティションに追加されたすべての新しい exec_types では、vendor_file_type 属性が必要です。これは neverallow によって適用されます。
  • 将来のプラットフォームまたはフレームワークのアップデートで競合を回避するには、vendor パーティションのファイルに exec_types 以外のラベルを付けないようにします。
  • AOSP で識別される同じプロセス HAL のすべてのライブラリ依存関係には、same_process_hal_file. というラベルを付ける必要があります。

Procfs(/proc)

/proc 内のファイルには、genfscon ラベルのみでラベル付けできます。Android 7.0 では、プラットフォーム ポリシーとベンダー ポリシーの両方で、procfs 内のファイルのラベル付けに genfscon が使用されていました。

おすすめの方法: プラットフォーム ポリシーでのみ /proc でラベル付けします。vendor プロセスが、現在デフォルトのラベル(proc)が付けられている /proc 内のファイルにアクセスする必要がある場合は、ベンダー ポリシーでは明示的にラベル付けせず、汎用的な proc タイプを使用してベンダー ドメインのルールを追加してください。こうすることで、プラットフォームをアップデートしても、procfs を通じて公開される将来のカーネル インターフェースに対応でき、必要に応じてそれらに明示的にラベル付けできます。

Debugfs(/sys/kernel/debug)

Debugfs には、file_contextsgenfscon の両方でラベル付けできます。Android 7.0 から Android 10 までは、プラットフォームとベンダーの両方で debugfs というラベルを付けます。

Android 11 では、製品版デバイスで debugfs にアクセスしたりマウントしたりすることはできません。デバイス メーカーは debugfs を削除する必要があります。

Tracefs(/sys/kernel/debug/tracing)

Tracefs には、file_contextsgenfscon の両方でラベル付けできます。Android 7.0 では、プラットフォームのみで tracefs をラベル付けします。

おすすめの方法: プラットフォームのみで tracefs をラベル付けします。

Sysfs(/sys)

/sys 内のファイルには、file_contextsgenfscon の両方でラベル付けできます。Android 7.0 では、プラットフォームとベンダーの両方で、sysfs 内のファイルのラベル付けに file_contextsgenfscon を使用します。

おすすめの方法: プラットフォームでは、デバイス固有でない sysfs ノードにラベル付けします。それ以外の場合は、ベンダーだけがファイルにラベル付けします。

tmpfs(/dev)

/dev 内のファイルは file_contexts でラベル付けできます。Android 7.0 では、プラットフォームとベンダーの両方で、この場所のファイルにラベル付けします。

おすすめの方法: ベンダーは、/dev/vendor 内のファイルにのみラベル付けします(/dev/vendor/foo/dev/vendor/socket/bar など)。

Rootfs(/)

/ 内のファイルは file_contexts でラベル付けできます。Android 7.0 では、プラットフォームとベンダーの両方で、この場所のファイルにラベル付けします。

おすすめの方法: / 内のファイルにはシステムのみでラベル付けします。

データ(/data)

データには、file_contextsseapp_contexts を組み合わせてラベル付けします。

おすすめの方法: ベンダーが /data/vendor 以外でラベル付けすることを禁止します。プラットフォームだけで /data の他の領域にラベル付けします。

互換性属性

SELinux ポリシーは、特定のオブジェクト クラスと権限のための、ソースタイプとターゲット タイプ間のインタラクションです。SELinux ポリシーの影響を受けるすべてのオブジェクト(プロセス、ファイルなど)のタイプが 1 つだけであっても、そのタイプに複数の属性が存在することがあります。

ポリシーは、ほとんどの場合、既存のタイプに基づいて記述されています。

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 はアクセス権を失います。

属性に基づいてポリシーを定義すると、基盤となるオブジェクトに、プラットフォームとベンダーコードの両方のポリシーに対応する属性を持つタイプを付与できます。これをすべてのタイプで行うことで、コンクリート タイプが使用されることのない、属性に基づくポリシーを効果的に作成できます。実際には、これはポリシー内のプラットフォームとベンダーの両方に適用される部分でのみ必要です。この部分は、ベンダー ポリシーの一部として作成されるプラットフォーム パブリック ポリシーとして定義され、提供されます。

バージョニングされた属性としてパブリック ポリシーを定義することにより、ポリシーの互換性に関する以下の 2 つの目標が達成されます。

  • プラットフォームのアップデート後もベンダーコードが機能し続けること。この目標は、ベンダーコードが依存していたオブジェクトに対応するオブジェクトのコンクリート タイプに属性を追加し、アクセスを保持することで達成されます。
  • ポリシーのサポートを終了できること。この目標は、ポリシーセットを属性ごとに明確に区分し、その属性に対応するバージョンのサポートが終了した時点で削除できるようにすることで達成されます。ベンダー ポリシーにまだ古いポリシーが含まれていても、アップグレードされた時点で自動的に削除されることがわかるので、プラットフォームでの開発を続行できます。

ポリシーの作成容易性

個々のバージョン変更について把握しなくてもポリシー開発を行えるように、Android 8.0 には、プラットフォーム パブリック ポリシーのタイプとその属性とのマッピングが含まれています。タイプ foo は属性 foo_vN にマッピングされます。ここで、N はターゲットとなるバージョンです。vNPLATFORM_SEPOLICY_VERSION ビルド変数に対応し、その形式は MM.NN です。MM はプラットフォーム SDK 番号に対応し、NN はプラットフォーム sepolicy 固有のバージョンです。

パブリック ポリシーの属性はバージョニングされず、API として存在します。この API に基づいてプラットフォーム ポリシーとベンダー ポリシーを作成し、2 つのパーティション間のインターフェースの安定性を維持できます。プラットフォーム ポリシーとベンダー ポリシーの作成者は、それが現在作成されたものであるかのように、ポリシーの作成を続行できます。

allow source_foo target_bar:class perm; としてエクスポートされたプラットフォーム パブリック ポリシーは、ベンダー ポリシーの一部として組み込まれます。これは、コンパイル(対応するバージョンを含む)の際に、デバイスのベンダー部分に配置されるポリシーに変換されます(変換された Common Intermediate Language(CIL)で示されます)。

 (allow source_foo_vN target_bar_vN (class (perm)))

ベンダー ポリシーはプラットフォームに先行することがないため、以前のバージョンを考慮する必要はありません。一方、プラットフォーム ポリシーは、ベンダー ポリシーがどの時点のものかを把握し、そのタイプの属性を組み込んで、バージョニングされた属性に対応するポリシーを設定する必要があります。

ポリシーの相違

各タイプの末尾に _vN を追加して属性を自動的に作成しても、異なるバージョン間でタイプに属性をマッピングできなければ効果がありません。Android では、属性のバージョン間のマッピングと、それらの属性に対するタイプのマッピングが維持されます。これは、前述のマッピング ファイルとステートメント(CIL など)によって行われます。

(typeattributeset foo_vN (foo))

プラットフォームのアップグレード

このセクションでは、プラットフォームのアップグレード シナリオについて詳しく説明します。

同じタイプ

このシナリオは、ポリシーのバージョン間でオブジェクトのラベルが変更されない場合に該当します。 これはソースタイプとターゲット タイプでも同じで、/dev/binder で見られます。ここでは、すべてのリリースについて binder_device とラベル付けされています。変換されたポリシーでは次のようになります。

binder_device_v1 … binder_device_vN

v1 から v2 にアップグレードする場合、プラットフォーム ポリシーに次のものを含める必要があります。

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 へのアクセスを可能にするルールに依存しているため、そのルールを新しいタイプの属性として含める必要があります。

v1 から v2 にアップグレードする場合、プラットフォーム ポリシーに次のものを含める必要があります。

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 の削除)

v1 から v2 にアップグレードする場合、プラットフォーム ポリシーに次のものを含める必要があります。

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 タイプ)

v1 から v2 にアップグレードする場合、プラットフォーム ポリシーに次のものを含める必要があります。

# 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 …)
新しいクラス / 権限

このシナリオは、プラットフォームのアップグレードによって、以前のバージョンには存在しなかった新しいポリシー コンポーネントが導入された場合に該当します。たとえば、権限の追加、検索、一覧表示を作成する servicemanager オブジェクト マネージャーが Android によって追加されたとき、servicemanager に登録しようとするベンダー デーモンは、利用できない権限を必要としていました。Android 8.0 では、プラットフォーム ポリシーのみが新しいクラスと権限を追加できます。

ベンダー ポリシーによって作成または拡張されたすべてのドメインが新しいクラスを支障なく使用できるようにするには、プラットフォーム ポリシーに次のようなルールを含める必要があります。

allow {domain -coredomain} *:new_class perm;

そのためには、ベンダー イメージがアクセス権を取得できるように、すべてのインターフェース(パブリック ポリシー)タイプに対してアクセスを許可するポリシーが必要になる可能性があります。その結果として許容できないセキュリティ ポリシーが(servicemanager の変更の例のように)作成される場合は、ベンダーのアップグレードを強制的に行うことがあります。

クラス / 権限の削除

このシナリオは、オブジェクト マネージャー(ZygoteConnection オブジェクト マネージャーなど)が削除されたときに問題が発生しないようにする場合に該当します。オブジェクト マネージャーのクラスと権限は、そのベンダー バージョンによって使用されなくなるまで、ポリシーで定義されたままにすることができます。そのためには、対応するマッピング ファイルに定義を追加します。

新しいタイプまたはラベルが変更されたタイプに関するベンダーのカスタマイズ

新しいベンダータイプは、新しいプロセス、バイナリ、デバイス、サブシステム、保存データを記述するために必要であることから、ベンダー ポリシー開発の中核になっています。そのため、ベンダーが定義するタイプの作成を許可することが不可欠です。

ベンダー ポリシーは常にデバイス上で最も古いポリシーであることから、すべてのベンダータイプをポリシー内の属性に自動的に変換する必要はありません。プラットフォームは、ベンダー ポリシーでラベル付けされているものを認識しないので、それらに依存しません。ただし、プラットフォームは、パブリック タイプ(domainsysfs_type など)でラベル付けされているオブジェクトの操作に使用される属性とパブリック タイプを提供する必要があります。プラットフォームがこれらのオブジェクトを正しく操作し続けるには、属性とタイプを適切に適用し、カスタマイズ可能なドメイン(init など)に特定のルールを追加する必要があります。

Android 9 での属性の変更

Android 9 にアップグレードするデバイスでは次の属性を使用できますが、Android 9 でリリースされるデバイスでは使用できません。

違反者属性

Android 9 には、次のようなドメイン関連の属性が含まれています。

  • data_between_core_and_vendor_violatorsvendorcoredomains 間のパスを通じてファイルを共有しないという要件に違反するすべてのドメインの属性。プラットフォーム プロセスとベンダー プロセスは、ディスク上のファイルを使用して通信するべきではありません(不安定な ABI)。おすすめの方法:
    • ベンダーコードでは /data/vendor を使用します。
    • システムでは /data/vendor を使用しません。
  • system_executes_vendor_violators。ベンダー バイナリを実行しないという要件に違反するすべてのシステム ドメイン(initshell domains を除く)の属性。ベンダー バイナリを実行することは不安定な API の原因になります。プラットフォームでは、ベンダー バイナリを直接実行すべきではありません。おすすめの方法:
    • ベンダー バイナリに対するプラットフォームのそのような依存関係には、HIDL HAL が優先します。

      または

    • ベンダー バイナリへのアクセスを必要とする coredomains は、ベンダー パーティションに移動することにより、coredomain ではなくなります。

信頼できない属性

任意のコードをホストする信頼できないアプリは、HwBinder サービスにアクセスするべきではありません。ただし、そのようなアプリによるアクセスが十分に安全であると見なされる場合は別です(下記の安全なサービスを参照)。これには、主に 2 つの理由があります。

  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 Binder サービスによっても提供されています。
  • hal_omx_hwservice。これは、アプリがアクセスを許可されている mediacodec Binder サービスの HwBinder バージョンです。
  • hal_codec2_hwservice。これは hal_omx_hwservice の新しいバージョンです。

使用可能な属性

安全と見なされていないすべての hwservices には、属性 untrusted_app_visible_hwservice が与えられています。対応する HAL サーバーには属性 untrusted_app_visible_halserver が与えられています。Android 9 でリリースされるデバイスでは、どちらの untrusted 属性も使用しないでください。

おすすめの方法:

  • 信頼できないアプリは、代替策として、ベンダー HIDL HAL と通信するシステム サービスと通信する必要があります。たとえば、アプリは binderservicedomainmediaserver(つまり 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 アーキテクチャ モデルの目標が達成されます。

属性チェーンへのマッピング

ポリシー バージョンへのマッピングに属性を使用する場合、1 つのタイプは 1 つの属性または複数の属性にマッピングされます。これにより、そのタイプによってラベル付けされたオブジェクトに、以前のタイプに対応する属性を通じてアクセスできるようになります。

ポリシー作成者にバージョン情報が見えないようにするという目標を守るために、バージョニングされた属性が自動的に生成され、適切なタイプに割り当てられます。一般的な静的なタイプのケースでは、単純に type_footype_foo_v1 にマッピングされます。

sysfssysfs_Amediaserveraudioserver といったオブジェクト ラベルの変更では、このマッピングの作成が重要です(上記の例を参照)。プラットフォーム ポリシーを維持するには、オブジェクトの移行ポイントでマッピングをどのように作成するかを決定する必要があります。これには、オブジェクトと割り当てられているラベルとの関係を把握することと、それがいつ行われるかを判断することが求められます。下位互換性を確保するには、uprev する可能性がある唯一のパーティションであるプラットフォーム側で、この複雑性を管理する必要があります。

バージョンの uprev

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 です。uprev は必ずしも整数であるとは限りません。たとえば、バージョンへの MR バンプによって system/sepolicy/public で互換性のない変更が必要になり、それが API バンプではない場合、その sepolicy バージョンは vN.1 になる場合があります。開発ブランチのバージョンは、出荷されるデバイスで絶対に使用されることがない 10000.0 です。

Android では、uprev の際に最も古いバージョンのサポートを終了する場合があります。Android では、あるバージョンのサポート終了のタイミングを判断するため、その Android バージョンを実行していて、まだプラットフォームのメジャー アップデートを受け取っているベンダー ポリシーが含まれているデバイスの数を収集する場合があります。特定のバージョンのデバイス数が特定のしきい値を下回ると、そのバージョンのサポートは終了します。

複数の属性がパフォーマンスに及ぼす影響

https://github.com/SELinuxProject/cil/issues/9 に記述されているように、1 つのタイプに多数の属性を割り当てると、ポリシーのキャッシュミスが発生した場合にパフォーマンスの問題が発生します。

これは Android で問題として確認されたため、Android 8.0 で変更が行われ、ポリシー コンパイラによってポリシーに追加された属性と、使用されていない属性が削除されました。これらの変更により、パフォーマンス低下の問題が解決されました。

system_ext と product のパブリック ポリシー

Android 11 以降、system_ext パーティションと product パーティションは、指定されたパブリック タイプをベンダー パーティションにエクスポートできます。プラットフォーム パブリック ポリシーと同様に、ベンダーはバージョニングされた属性に自動的に変換されるタイプとルールを使用します(例: type から type_NN はベンダー パーティションをビルドするプラットフォームのバージョン)。

system_ext パーティションと product パーティションが同じプラットフォーム バージョン N に基づいている場合、ビルドシステムが system_ext/etc/selinux/mapping/N.cilproduct/etc/selinux/mapping/N.cil へのベース マッピング ファイルを生成します。これらには、type から type_N への ID マッピングが含まれています。ベンダーは、バージョニングされた属性 type_N を使用して type にアクセスできます。

system_ext パーティションと product パーティションのみが更新された場合(例: N から N+1 またはそれ以降に更新)、ベンダーは N のままとなり、system_ext パーティションと product パーティションのタイプにアクセスできなくなります。このような破綻を防ぐために、system_ext パーティションと product パーティションでは、具体的なタイプから type_N 属性へのマッピング ファイルを用意する必要があります。N+1(またはそれ以降)の system_ext パーティションと product パーティションで N ベンダーをサポートする場合は、各パートナーでマッピング ファイルのメンテナンスを行ってください。

これを行うにあたり、パートナーには以下のことが求められます。

  1. 生成されたベース マッピング ファイルを N の system_ext パーティションと product パーティションからソースツリーにコピーすること。
  2. 必要に応じてマッピング ファイルを修正すること。
  3. N+1(またはそれ以降)の system_ext パーティションと product パーティションにマッピング ファイルをインストールすること。

たとえば、N system_ext に foo_type という 1 つのパブリック タイプがあるとします。すると、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 を区別しやすくするため、システムでは SELinux コンテキスト ファイルをそれぞれ異なる方法でビルドして、それらを分離しています。

ファイルのコンテキスト

Android 8.0 では、file_contexts について次のような変更が行われました。

  • デバイスの起動時に追加のコンパイルによって発生するオーバーヘッドを回避するために、バイナリ形式の file_contexts がなくなりました。代わりに {property, service}_contexts のような読み取り可能な正規表現のテキスト ファイルが使用されます(7.0 以前と同様)。
  • file_contexts は 2 つのファイルに分割されています。
    • plat_file_contexts
      • /vendor パーティションのラベル付け部分以外はデバイス固有のラベルがない Android プラットフォームの file_context。sepolicy ファイルが適切に機能するように、このパーティションに正確にラベル付けする必要があります。
      • このファイルは、デバイス上の /system/etc/selinux/plat_file_contextssystem パーティションに配置し、起動時にベンダーの 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 は 2 つのファイルに分割されています。

  • plat_property_contexts
    • デバイス固有のラベルがない、Android プラットフォームの property_context
    • このファイルは、/system/etc/selinux/plat_property_contextssystem パーティションに配置し、起動時にベンダーの property_contexts とともに init によって読み込む必要があります。
  • vendor_property_contexts
    • デバイスの Boardconfig.mk ファイルの BOARD_SEPOLICY_DIRS で指定されたディレクトリにある property_contexts を組み合わせることで構築される、デバイス固有の property_context
    • このファイルは、/vendor/etc/selinux/vendor_property_contextsvendor パーティションに配置し、起動時にプラットフォームの property_context とともに init によって読み込む必要があります。

サービスのコンテキスト

Android 8.0 では、service_contexts は次のファイルに分割されています。

  • plat_service_contexts
    • servicemanager 用の Android プラットフォーム固有の service_contextservice_context にはデバイス固有のラベルがありません。
    • このファイルは、/system/etc/selinux/plat_service_contextssystem パーティションに配置し、起動時にベンダーの service_contexts とともに servicemanager によって読み込む必要があります。
  • vendor_service_contexts
    • デバイスの Boardconfig.mk ファイルの BOARD_SEPOLICY_DIRS で指定されたディレクトリにある service_contexts を組み合わせることで構築される、デバイス固有の service_context
    • このファイルは、/vendor/etc/selinux/vendor_service_contextsvendor パーティションに配置し、起動時にプラットフォームの service_contexts とともに servicemanager によって読み込む必要があります。
    • servicemanager は起動時にこのファイルを検索しますが、TREBLE デバイスのコンプライアンスを完全に確保するには、vendor_service_contexts が存在してはなりません。これは、vendor プロセスと system プロセス間のすべてのインタラクションが hwservicemanager/hwbinder を経由する必要があるためです。
  • plat_hwservice_contexts
    • デバイス固有のラベルがない hwservicemanager 用の Android プラットフォームの hwservice_context
    • このファイルは、/system/etc/selinux/plat_hwservice_contextssystem パーティションに配置し、起動時に vendor_hwservice_contexts とともに hwservicemanager によって読み込む必要があります。
  • vendor_hwservice_contexts
    • デバイスの Boardconfig.mk ファイルの BOARD_SEPOLICY_DIRS で指定されたディレクトリにある hwservice_contexts を組み合わせることで構築される、デバイス固有の hwservice_context
    • このファイルは、/vendor/etc/selinux/vendor_hwservice_contextsvendor パーティションに配置し、起動時に plat_service_contexts とともに hwservicemanager によって読み込む必要があります。
  • vndservice_contexts
    • デバイスの Boardconfig.mk ファイルの BOARD_SEPOLICY_DIRS で指定されたディレクトリにある vndservice_contexts を組み合わせることで構築される、vndservicemanager 用のデバイス固有の service_context
    • このファイルは、/vendor/etc/selinux/vndservice_contextsvendor パーティションに配置し、起動時に vndservicemanager によって読み込む必要があります。

Seapp のコンテキスト

Android 8.0 では、seapp_contexts は 2 つのファイルに分割されています。

  • plat_seapp_contexts
    • デバイス固有の変更がない、Android プラットフォームの seapp_context
    • このファイルは、/system/etc/selinux/plat_seapp_contexts.system パーティションに配置する必要があります。
  • vendor_seapp_contexts
    • デバイスの Boardconfig.mk ファイルの BOARD_SEPOLICY_DIRS で指定されたディレクトリにある seapp_contexts を組み合わせることで構築される、プラットフォームの seapp_context のデバイス固有の拡張機能。
    • このファイルは、/vendor/etc/selinux/vendor_seapp_contextsvendor パーティションに配置する必要があります。

MAC 権限

Android 8.0 では、mac_permissions.xml は 2 つのファイルに分割されています。

  • プラットフォームの mac_permissions.xml
    • デバイス固有の変更がない、Android プラットフォームの mac_permissions.xml
    • このファイルは、/system/etc/selinux/.system パーティションに配置する必要があります。
  • プラットフォーム以外の mac_permissions.xml
    • デバイスの Boardconfig.mk ファイルの BOARD_SEPOLICY_DIRS で指定されたディレクトリにある mac_permissions.xml から構築される、プラットフォームの mac_permissions.xml のデバイス固有の拡張機能。
    • このファイルは、/vendor/etc/selinux/.vendor パーティションに配置する必要があります。