SELinux は、デフォルト拒否に設定されています。つまり、カーネルにフックを持つすべてのアクセスで、ポリシーによる明示的な許可が必要になります。これは、ポリシー ファイルが、ルール、タイプ、クラス、権限などに関する多量の情報で構成されることを意味します。このドキュメントでは SELinux の詳細は扱っていませんが、新しい Android デバイスを構築するには、ポリシールールの記述方法を理解することが今後は不可欠になります。SELinux については、すでに多くの情報が公開されています。推奨されるリソースについては、サポート ドキュメントをご覧ください。
キーファイル
SELinux を有効にするには、最新の Android カーネルを統合して、system/sepolicy ディレクトリにあるファイルを組み込みます。コンパイルすると、それらのファイルが SELinux カーネルのセキュリティ ポリシーを構成し、アップストリームの Android オペレーティング システムに対応します。
一般的に、system/sepolicy
ファイルは直接変更すべきではありません。代わりに、/device/manufacturer/device-name/sepolicy
ディレクトリにある独自のデバイス固有のポリシー ファイルを追加または編集します。Android 8.0 以降では、これらのファイルを変更した場合、ベンダー ディレクトリ内のポリシーだけに影響します。Android 8.0 以降のパブリック sepolicy の分離について詳しくは、Android 8.0+ での SEPolicy のカスタマイズをご覧ください。以下のファイルは、Android のバージョンにかかわらず変更できます。
ポリシー ファイル
末尾が *.te
であるファイルは、ドメインとそのラベルを定義する SELinux ポリシーのソースファイルです。/device/manufacturer/device-name/sepolicy
で新しいポリシー ファイルを作成することが必要になる場合もありますが、可能な限り既存のファイルの更新を試みてください。
コンテキスト ファイル
コンテキスト ファイルでは、オブジェクトのラベルを指定します。
file_contexts
はファイルにラベルを割り当てます。ユーザー空間のさまざまなコンポーネントで使用されます。新しいポリシーを作成した場合は、このファイルを作成または更新して、ファイルに新しいラベルを割り当てます。新しいfile_contexts
を適用するには、ファイルシステム イメージを再ビルドするか、再度ラベル付けするファイルでrestorecon
を実行します。file_contexts
への変更は、アップグレード時にアップグレードの一環として、システムとユーザーデータのパーティションに自動的に適用されます。また、アップグレード時に変更を他のパーティションにも自動的に適用するには、それらのパーティションが読み取り / 書き込みでマウントされた後でrestorecon_recursive
呼び出しを init.board.rc ファイルに追加します。genfs_contexts
は、拡張属性をサポートしていない、proc
やvfat
などのラベルをファイルシステムに割り当てます。この構成はカーネル ポリシーの一部として読み込まれますが、変更が in-core inode で有効にならない場合があります。変更を完全に適用するには、再起動またはファイル システムのマウント解除と再マウントが必要になります。context=mount
オプションを使用して、特定のマウントにvfat
などの特定のラベルを割り当てることもできます。property_contexts
は Android システム プロパティにラベルを割り当てて、どのプロセスがそれらのプロパティを設定するかを制御します。この構成は、起動時にinit
プロセスによって読み取られます。service_contexts
は Android バインダー サービスにラベルを割り当てて、どのプロセスがサービスのバインダ リファレンスを追加(登録)および検索(ルックアップ)できるかを制御します。この構成は、起動時にservicemanager
プロセスによって読み取られます。seapp_contexts
はアプリプロセスと/data/data
ディレクトリにラベルを割り当てます。この構成は、アプリを起動するたびにzygote
プロセスに、また起動時にinstalld
に読み取られます。mac_permissions.xml
は、署名と、必要に応じてパッケージ名に基づいて、アプリにseinfo
タグを割り当てます。seinfo
タグをseapp_contexts
ファイル内でキーとして使用すれば、seinfo
タグが付けられたすべてのアプリに特定のラベルを割り当てることができます。この構成は、起動時にsystem_server
によって読み取られます。keystore2_key_contexts
は Keystore 2.0 名前空間にラベルを割り当てます。これらの名前空間は keystore2 デーモンによって適用されます。キーストアは UID / AID ベースの名前空間を提供してきました。キーストア 2.0 は、さらに sepolicy で定義された名前空間を適用します。このファイルの形式と規則の詳細については、こちらをご覧ください。
BoardConfig.mk makefile
ポリシー ファイルとコンテキスト ファイルを編集または追加したら、sepolicy
サブディレクトリとそれぞれの新しいポリシー ファイルを参照するように /device/manufacturer/device-name/BoardConfig.mk
makefile を更新します。
BOARD_SEPOLICY
変数について詳しくは、system/sepolicy/README
ファイルをご覧ください。
BOARD_SEPOLICY_DIRS += \ <root>/device/manufacturer/device-name/sepolicy BOARD_SEPOLICY_UNION += \ genfs_contexts \ file_contexts \ sepolicy.te
再ビルドすると、デバイスで SELinux が有効になります。これで、カスタマイズの説明に沿って Android オペレーティング システムに追加した内容に応じて SELinux ポリシーをカスタマイズするか、検証の説明に沿って既存の設定を検証できます。
新しいポリシー ファイルと BoardConfig.mk の更新を導入すると、新しいポリシー設定は最終的なカーネル ポリシー ファイルに自動的に組み込まれます。デバイスで sepolicy をビルドする方法について詳しくは、sepolicy のビルドをご覧ください。
実装
SELinux を開始するには:
- カーネルで SELinux を有効にします:
CONFIG_SECURITY_SELINUX=y
- kernel_cmdline または bootconfig のパラメータを次のように変更します。
BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
またはBOARD_BOOTCONFIG := androidboot.selinux=permissive
これはデバイスのポリシー作成の初期段階でのみ使用します。ブートストラップ ポリシーを最初に作成した後、このパラメータを削除してデバイスを enforcing モードにしないと、CTS に失敗します。 - permissive モードでシステムを起動し、起動中にどのような拒否が発生するかを確認します。
Ubuntu 14.04 以降:adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
Ubuntu 12.04:adb pull /sys/fs/selinux/policy adb logcat -b all | audit2allow -p policy
- 警告の出力(例:
init: Warning! Service name needs a SELinux domain defined; please fix!
)を評価します。手順とツールについては検証をご覧ください。 - ラベル付けが必要な、デバイスとその他の新しいファイルを特定します。
- オブジェクトに既存のラベルまたは新しいラベルを割り当てます。
*_contexts
ファイルでそれまでのラベル付けの状況を確認し、ラベルの意味を理解したうえで新しいラベルを割り当てます。これにはポリシーに適合する既存のラベルを使用するのが理想ですが、新しいラベルと、そのラベルへのアクセスに関するルールが必要になる場合があります。適切なコンテキスト ファイルにラベルを追加します。 - 独自のセキュリティ ドメインを必要とするドメインまたはプロセスを特定します。
ドメインまたはプロセスを特定した場合は、必要に応じてまったく新しいポリシーを作成する必要があります。たとえば
init
から生成されたすべてのサービスには、独自のポリシーが必要です。次のコマンドにより、実行され続けているサービスを確認できます(実際には、すべてのサービスが実行され続ける必要があります)。
adb shell su -c ps -Z | grep init
adb shell su -c dmesg | grep 'avc: '
init.device.rc
を確認して、ドメインタイプがないドメインを特定します。それらに開発プロセスの早い段階でドメインを与え、init
にルールを追加しないようにします。ドメインを与えないと、init
のアクセスと独自のポリシーが適用されているものとの区別ができなくなります。BOARD_SEPOLICY_*
変数を使用するようにBOARD_CONFIG.mk
を設定します。設定方法について詳しくは、system/sepolicy
の README をご覧ください。- init.device.rc と fstab.device ファイルを調べ、すべての
mount
の使用が、適切にラベル付けされたファイルシステムに対応しているか、またはcontext= mount
オプションが指定されているかを確認します。 - すべての拒否を調べ、それぞれを適切に処理できる SELinux ポリシーを作成します。カスタマイズに示す例をご覧ください。
AOSP のポリシーから開始し、それに基づいてカスタマイズを行います。ポリシー戦略といくつかの手順の詳細については、SELinux ポリシーの記述をご覧ください。
ユースケース
独自のソフトウェアと関連する SELinux ポリシーを作成する場合に考慮すべきエクスプロイトの例を示します。
Symlink - symlink はファイルとして現れるため、多くの場合ファイルとして読み取られ、不正利用される可能性があります。たとえば init
など、権限のあるコンポーネントが特定のファイルの権限を変更し、それによって過度にアクセスが許可される場合があります。
攻撃者はそれらのファイルを、制御下にあるコードへの symlink に置き換えることで、任意のファイルを上書きできるようになります。しかしアプリケーションが symlink によるアクセスを行わないことがわかっていれば、それを行うことを SELinux を使用して禁止できます。
システム ファイル - システム サーバーだけが変更するべきシステム ファイルのためのクラスを考慮する必要があります。netd
、init
、vold
はルートとして実行されるため、そうしたシステム ファイルにアクセスできてしまいます。したがって、netd
が侵害されればそれらのファイルも侵害され、さらにはシステム サーバー自体も侵害される可能性があります。
SELinux では、それらのファイルをシステム サーバー データファイルとして識別できます。
そのため、それらのファイルに対する読み取り / 書き込みアクセス権を持つドメインは、システム サーバーだけになります。
netd
が侵害されてルートとして実行された場合でも、システム サーバー ドメインにドメインを切り替えてシステム ファイルにアクセスすることはできません。
アプリデータ - もう 1 つの例は、ルートとして実行される必要がある一方で、アプリデータにはアクセスするべきでない機能のクラスです。これは、広範なアサーションを作成できるようになるため、非常に便利です。たとえば、アプリケーション データに関連がない特定のドメインに対して、インターネットへのアクセスを禁止するといった使い方ができます。
setattr - chmod
や chown
などのコマンドには、関連付けられているドメインで setattr
を実行できるファイルを、特定しておくことができます。特定されたもの以外のファイルについては、ルートであっても、変更を禁止できます。その場合アプリケーションは、app_data_files
とラベル付けされたファイルに対して chmod
と chown
を実行できても、shell_data_files
または system_data_files
には実行できません。