SELinux をカスタマイズ

基本レベルの SELinux 機能を統合して結果をくまなく分析した後、Android オペレーティング システムにカスタマイズを適用する独自のポリシー設定を追加できます。追加するポリシーも Android 互換性プログラムの要件を満たす必要があり、デフォルトの SELinux 設定を削除することはできません。

メーカーは既存の SELinux ポリシーを削除しないでください。削除すると、Android SELinux の実装とその実装が管理するアプリに問題が発生する危険があります。同様に、サードパーティ アプリの場合も、コンプライアンスに従って正常に動作するようにするために改良が必要になることがあります。SELinux 対応デバイスでアプリを継続して動作させるために変更が必要になる事態は避けるべきです。

SELinux のカスタマイズを行う場合は、以下のことを行ってください。

  • すべての新しいデーモンについて SELinux ポリシーを作成する
  • 適切な場合は常に事前定義されたドメインを使用する
  • init サービスとして生成されたすべてのプロセスにドメインを割り当てる
  • ポリシーを作成する前にマクロについて熟知する
  • コアポリシーの変更を AOSP に送信する

また次のことは行わないでください。

  • 互換性のないポリシーを作成する
  • エンドユーザー ポリシーのカスタマイズを許可する
  • MDM ポリシーのカスタマイズを許可する
  • ポリシー違反に関してユーザーに不安を与える
  • バックドアを追加する

具体的な要件については、Android 互換性定義ドキュメントのカーネル セキュリティ機能のセクションをご覧ください。

SELinux では、許可リスト方式のアプローチが採用されています。つまり、すべてのアクセス権はポリシーによって明示的に許可されない限り、付与されません。Android のデフォルトの SELinux ポリシーで、すでに Android オープンソース プロジェクトがサポートされているため、SELinux 設定を変更する必要はありません。SELinux 設定をカスタマイズする場合は、既存のアプリに問題が発生しないように十分注意する必要があります。手順:

  1. 最新の Android カーネルを使用します。
  2. 最小権限の原則を採用します。
  3. Android に独自に追加した要素だけを扱います。デフォルトのポリシーは、Android オープンソース プロジェクトのコードベースと自動的に連動します。
  4. ソフトウェア コンポーネントを、1 つのタスクを実行するモジュールに分割します。
  5. それらのタスクを関連のない機能から分離する SELinux ポリシーを作成します。
  6. 作成したポリシーを /device/manufacturer/device-name/sepolicy ディレクトリ内の *.te ファイル(SELinux ポリシー ソースファイルの拡張)に格納し、BOARD_SEPOLICY 変数を使用してビルドに組み込みます。
  7. 新しいドメインは、最初は permissive にします。そのためには、ドメインの .te ファイル内で permissive 宣言を使用します。
  8. 結果を分析し、ドメインの定義を改良します。
  9. userdebug ビルドで拒否が発生しなくなったら、permissive 宣言を削除します。

SELinux ポリシーの変更を統合した後で、SELinux の互換性を維持するためのステップを開発ワークフローに追加してください。ソフトウェア開発プロセスでは、実際の実装ではなくソフトウェア モデルに変更があった場合にのみ SELinux ポリシーを変更するのが理想的です。

SELinux のカスタマイズを開始したら、最初に Android への追加に対する監査を行います。新しい機能を実行するコンポーネントを追加した場合は、enforcing モードを有効にする前に、そのコンポーネントが Android のセキュリティ ポリシーと、OEM が作成した関連ポリシーを遵守していることを確認します。

不要な問題の発生を防ぐには、制限を厳格にしすぎて互換性を低下させる(その結果、デバイスの機能を不完全にする)よりも、制限を緩和して互換性を高めるほうが得策です。むしろ、他のアプリにも役立つような変更であれば、デフォルトの SELinux ポリシーにパッチとして送信するべきです。デフォルトのセキュリティ ポリシーにパッチが適用されると、新しい Android がリリースされるたびに変更作業を行う必要がなくなります。

ポリシー ステートメントの例

SELinux は M4 コンピュータ言語に基づいているため、各種の効率的なマクロをサポートしています。

次の例では、すべてのドメインに /dev/null に対する読み取りアクセス権と書き込みアクセス権、/dev/zero に対する読み取りアクセス権を付与しています。

# Allow read / write access to /dev/null
allow domain null_device:chr_file { getattr open read ioctl lock append write};

# Allow read-only access to /dev/zero
allow domain zero_device:chr_file { getattr open read ioctl lock };

これと同じステートメントを、SELinux の *_file_perms マクロ(短縮形)で記述できます。

# Allow read / write access to /dev/null
allow domain null_device:chr_file rw_file_perms;

# Allow read-only access to /dev/zero
allow domain zero_device:chr_file r_file_perms;

ポリシーの例

DHCP 用の完全なポリシーの例を示します。

type dhcp, domain;
permissive dhcp;
type dhcp_exec, exec_type, file_type;
type dhcp_data_file, file_type, data_file_type;

init_daemon_domain(dhcp)
net_domain(dhcp)

allow dhcp self:capability { setgid setuid net_admin net_raw net_bind_service
};
allow dhcp self:packet_socket create_socket_perms;
allow dhcp self:netlink_route_socket { create_socket_perms nlmsg_write };
allow dhcp shell_exec:file rx_file_perms;
allow dhcp system_file:file rx_file_perms;
# For /proc/sys/net/ipv4/conf/*/promote_secondaries
allow dhcp proc_net:file write;
allow dhcp system_prop:property_service set ;
unix_socket_connect(dhcp, property, init)

type_transition dhcp system_data_file:{ dir file } dhcp_data_file;
allow dhcp dhcp_data_file:dir create_dir_perms;
allow dhcp dhcp_data_file:file create_file_perms;

allow dhcp netd:fd use;
allow dhcp netd:fifo_file rw_file_perms;
allow dhcp netd:{ dgram_socket_class_set unix_stream_socket } { read write };
allow dhcp netd:{ netlink_kobject_uevent_socket netlink_route_socket
netlink_nflog_socket } { read write };

ポリシーの例を細かく分けて見てみましょう。

最初の行の型宣言では、DHCP デーモンが基本セキュリティ ポリシーから継承します(domain)。前のステートメントの例のように、DHCP は /dev/null に対して読み取りと書き込みを行えます。

2 行目では、DHCP が permissive ドメインとして指定されています。

init_daemon_domain(dhcp) の行は、DHCP が init から生成され、通信が可能であることを示しています。

net_domain(dhcp) の行では、DHCP が TCP パケットの読み取りと書き込み、ソケット経由の通信、DNS リクエストの実行などの一般的なネットワーク機能を net ドメインから使用することを許可しています。

allow dhcp proc_net:file write; の行では、DHCP が /proc 内の特定のファイルに書き込めることを示しています。この行は、SELinux でファイルのきめ細かいラベル付けが可能であることを示しています。ここでは proc_net ラベルを使用して、書き込みアクセス権の対象を /proc/sys/net 以下のファイルに限定しています。

allow dhcp netd:fd use; で始まる最終ブロックは、アプリの相互の通信がどのように許可されるかを示しています。このポリシーは、ファイル記述子、FIFO ファイル、データグラム ソケット、UNIX ストリーム ソケットを介して DHCP と netd が互いに通信できることを示しています。DHCP は、データグラム ソケットと UNIX ストリーム ソケットに対しては読み取りと書き込みのみが可能です。作成したり開いたりすることはできません。

使用可能なコントロール

クラス 権限
ファイル
ioctl read write create getattr setattr lock relabelfrom relabelto append
unlink link rename execute swapon quotaon mounton
ディレクトリ
add_name remove_name reparent search rmdir open audit_access execmod
ソケット
ioctl read write create getattr setattr lock relabelfrom relabelto append bind
connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg
name_bind
ファイル システム
mount remount unmount getattr relabelfrom relabelto transition associate
quotamod quotaget
プロセス
fork transition sigchld sigkill sigstop signull signal ptrace getsched setsched
getsession getpgid setpgid getcap setcap share getattr setexec setfscreate
noatsecure siginh setrlimit rlimitinh dyntransition setcurrent execmem
execstack execheap setkeycreate setsockcreate
セキュリティ
compute_av compute_create compute_member check_context load_policy
compute_relabel compute_user setenforce setbool setsecparam setcheckreqprot
read_policy
機能
chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap
linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock
ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin
sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write
audit_control setfcap

もっと見る

その他

neverallow ルール

SELinux の neverallow ルールは、発生してはならない動作を禁止します。互換性テストにより、SELinux neverallow ルールをすべてのデバイスに確実に適用できるようになりました。

次のガイドラインは、メーカーがカスタマイズ中に neverallow ルールに関連するエラーを回避するために役立ちます。ここに示すルール番号は Android 5.1 に対応しているため、リリースに応じて変わる場合があります。

ルール 48: neverallow { domain -debuggerd -vold -dumpstate -system_server } self:capability sys_ptrace;
ptrace の man ページをご覧ください。sys_ptrace 機能により、任意のプロセスに対して ptrace を実行できます。他のプロセスに対する大幅な制御が可能になるため、ルールで概要が示されている指定されたシステム コンポーネントに対してのみ適用する必要があります。この機能が必要になるのは、ほとんどの場合、ユーザー向けビルド用ではないものや、不要な機能が存在するときです。不要なコンポーネントを削除してください。

ルール 76: neverallow { domain -appdomain -dumpstate -shell -system_server -zygote } { file_type -system_file -exec_type }:file execute;
このルールは、システム上で任意のコードが実行されることを防止するものです。特に、/system のコードだけが実行されることがアサートされているため、確認付きブートなどのメカニズムによってセキュリティが保証されます。この neverallow ルールに関する問題が発生した場合の最良の解決策は、問題のあるコードを /system パーティションに移動することです。

Android 8.0 以降で SEPolicy をカスタマイズ

このセクションでは、Android 8.0 以降でのベンダー SELinux ポリシーに関するガイドラインを示します。Android オープンソース プロジェクト(AOSP)SEPolicy と SEPolicy 拡張の詳細も含まれています。複数のパーティションと Android バージョンにわたって SELinux ポリシーの互換性を維持する方法の詳細については、互換性をご覧ください。

ポリシーの配置

Android 7.0 以前では、デバイス メーカーが BOARD_SEPOLICY_DIRS にポリシー(さまざまなデバイスタイプで AOSP ポリシーを強化するためのポリシーなど)を追加できました。Android 8.0 以上では、BOARD_SEPOLICY_DIRS にポリシーを追加すると、ポリシーはベンダー イメージのみに配置されます。

Android 8.0 以上では、ポリシーは AOSP 内の次の場所に存在します。

  • system/sepolicy/public。ベンダー固有のポリシーで使用するためにエクスポートされたポリシーが含まれています。すべてが Android 8.0 の互換性インフラストラクチャに配置されます。パブリック ポリシーはリリース間で維持されるため、カスタマイズされたポリシーに /public の任意のポリシーを含めることができます。そのため、/public に配置できるポリシーのタイプは、さらに制限されます。これはプラットフォームのエクスポートされたポリシー API として考えることができます。/system/vendor 間のインターフェースを扱うものがすべてここに含まれます。
  • system/sepolicy/private。システム イメージが機能するために必要なポリシーが含まれますが、その情報はベンダー イメージ ポリシーには認識されません。
  • system/sepolicy/vendor/vendor に配置されるが、(デバイス固有のディレクトリではなく)コア プラットフォーム ツリーに存在するコンポーネント用のポリシーが含まれています。これは、ビルドシステムによるデバイスとグローバル コンポーネントの区別を表すアーティファクトであり、概念的には以下に示すデバイス固有のポリシーの一部となります。
  • device/manufacturer/device-name/sepolicy。デバイス固有のポリシーが含まれています。デバイスに応じたポリシーのカスタマイズも含まれます。Android 8.0 以上では、ベンダー イメージのコンポーネント用のポリシーに相当します。

Android 11 以降では、system_ext パーティションと product パーティションにパーティション固有のポリシーを含めることもできます。system_ext ポリシーと product ポリシーもパブリックとプライベートに分割され、ベンダーは system_ext と product のパブリック ポリシー(システム ポリシーなど)を使用できます。

  • SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS。ベンダー固有のポリシーで使用するためにエクスポートされたポリシーが含まれます。system_ext パーティションにインストールされています。
  • SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS。system_ext イメージの機能に必要なポリシーが含まれますが、どのベンダー イメージかは、ポリシーは認識できません。system_ext パーティションにインストールされています。
  • PRODUCT_PUBLIC_SEPOLICY_DIRS。ベンダー固有のポリシーで使用するためにエクスポートされたポリシーが含まれます。product パーティションにインストールされています。
  • PRODUCT_PRIVATE_SEPOLICY_DIRS。product イメージの機能に必要なポリシーが含まれますが、どのベンダー イメージかは、ポリシーは認識できません。product パーティションにインストールされています。
注: GSI を使用する場合、OEM の system_ext パーティションと product パーティションはマウントされません。OEM の system_ext と product のパブリック ポリシーを使用するベンダーの sepolicy のルールは、OEM 固有の型定義が見つからないため NOP になります。
注: system_ext と product のパブリック ポリシーを使用する際は、特に注意してください。 パブリック ポリシーは、system_ext/product と vendor との間でエクスポートされた API として機能します。互換性の問題は、パートナー自身で管理する必要があります。

サポートされているポリシーのシナリオ

Android 8.0 以上を搭載したデバイスでは、ベンダー イメージは、OEM のシステム イメージと、Google が提供するリファレンス AOSP システム イメージで機能する必要があります(また、このリファレンス イメージの CTS にパスする必要があります)。これらの要件により、フレームワークとベンダーコードが明確に分離されます。このようなデバイスでは、以下のシナリオがサポートされます。

ベンダー イメージ専用の拡張機能

例: ベンダー イメージからのプロセスをサポートするベンダー イメージの vndservicemanager に新しいサービスを追加する場合。

以前の Android バージョンを搭載したデバイスと同様に、device/manufacturer/device-name/sepolicy にデバイス固有のカスタマイズを追加します。ベンダー コンポーネント間のみのインタラクションを管理する新しいポリシーには、device/manufacturer/device-name/sepolicy だけに存在するタイプを含める必要があります。ここに示すポリシーでは、ベンダーのコードの動作を許可しています。このポリシーはフレームワークのみの OTA の一部としては更新されず、リファレンス AOSP システム イメージと合わせて、デバイス上の結合されたポリシーに組み込まれます。

AOSP と連動するベンダー イメージのサポート

例: AOSP で定義された HAL を実装する新しいプロセス(ベンダー イメージから hwservicemanager に登録される)を追加する場合。

以前の Android バージョンを搭載したデバイスと同様に、device/manufacturer/device-name/sepolicy でデバイス固有のカスタマイズを実行します。system/sepolicy/public/ の一部としてエクスポートされたポリシーを使用できます。デバイスの出荷時には、ベンダー ポリシーの一部として扱われます。パブリック ポリシーから得られたタイプと属性は、neverallow による制限に従い、新しいベンダー固有の要素とのインタラクションを示す新しいルールで使用できます。ベンダー固有のケースと同様に、この新しいポリシーはフレームワークのみの OTA の一部としては更新されず、リファレンス AOSP システム イメージと合わせて、デバイス上の結合されたポリシーに組み込まれます。

システム イメージ専用の拡張機能

例: システム イメージからの他のプロセスによってのみアクセスされる新しいサービス(servicemanager に登録される)を追加する場合。

このポリシーを system/sepolicy/private に追加します。パートナー システム イメージにおいて機能を有効にするプロセスまたはオブジェクトをさらに追加することもできます。ただし、それらの新しい要素が、ベンダー イメージの新しいコンポーネントとのインタラクションを必要としない場合に限ります(具体的には、そうしたプロセスまたはオブジェクトは、ベンダー イメージからのポリシーがなくても完全に機能する必要があります)。system/sepolicy/public によってエクスポートされたポリシーは、この場合もベンダー イメージのみの拡張機能と同様に使用できます。このポリシーはシステム イメージの一部であり、フレームワークのみの OTA の一部として更新できますが、リファレンス AOSP システム イメージを使用する場合は組み込まれません。

拡張 AOSP コンポーネントに対応するベンダー イメージの拡張機能

例: AOSP システム イメージ内にも存在する拡張クライアント(拡張 system_server など)が使用できる新しい非 AOSP HAL。

システムとベンダー間のインタラクションに関するポリシーを、デバイスの出荷時にベンダー パーティションに存在する device/manufacturer/device-name/sepolicy ディレクトリに含める必要があります。これは、リファレンス AOSP イメージと連動するようにベンダー イメージのサポートを追加する上記のシナリオと似ていますが、変更された AOSP コンポーネントがシステム パーティションのその他の部分と適切に連動するために追加のポリシーも必要とする点が異なります(パブリック AOSP タイプのラベルが維持されている場合は不要です)。

パブリック AOSP コンポーネントとシステム イメージのみの拡張機能との間のインタラクションに関するポリシーが system/sepolicy/private に存在する必要があります。

AOSP インターフェースのみにアクセスできるシステム イメージの拡張機能

例: 新しい非 AOSP システム プロセスが、AOSP が依存する HAL にアクセスする必要がある場合。

これはシステム イメージ専用の拡張機能の例に似ていますが、新しいシステム コンポーネントが system/vendor インターフェースを超えてインタラクションする可能性がある点が異なります。新しいシステム コンポーネント用のポリシーは system/sepolicy/private に配置する必要があります。これは、AOSP によって system/sepolicy/public ですでに確立されている(つまり、機能に必要なタイプと属性が含まれている)インターフェースを通じて行う場合にのみ許可されます。ポリシーをデバイス固有のポリシーに含めることはできますが、他の system/sepolicy/private タイプを使用したり、フレームワークのみのアップデートの結果として(ポリシーに影響する方法で)変更したりすることはできません。ポリシーをフレームワークのみの OTA で変更することはできますが、AOSP システム イメージを使用する場合は組み込まれません(AOSP システム イメージにも新しいシステム コンポーネントは組み込まれません)。

新しいシステム コンポーネントに対応するベンダー イメージの拡張機能

例: AOSP アナログがない(そのために独自のドメインを必要とする)クライアント プロセスで使用できる新しい非 AOSP HAL を追加する場合。

AOSP 拡張機能の例と同様に、システムとベンダー間のインタラクションに関するポリシーは、デバイスの出荷時にベンダー パーティションに存在する device/manufacturer/device-name/sepolicy ディレクトリに配置する必要があります(これは、システム ポリシーがベンダー固有の詳細情報を認識しないようにするためです)。system/sepolicy/public のポリシーを拡張する新しいパブリック タイプを追加することはできますが、既存の AOSP ポリシーに付加する形で追加する必要があります。つまり、AOSP パブリック ポリシーを削除してはなりません。これにより、system/sepolicy/private および device/manufacturer/device-name/sepolicy のポリシーに対して新しいパブリック タイプを使用できます。

system/sepolicy/public に追加するたびに、新しい互換性保証をマッピング ファイルで追跡する必要があり、また他の制限も加わるため、複雑性が増大することに注意してください。system/sepolicy/public には、新しいタイプと、対応する許可ルールのみを追加できます。属性とその他のポリシー ステートメントはサポートされません。さらに、新しいパブリック タイプは、/vendor ポリシーでオブジェクトに直接ラベル付けするためには使用できません。

サポートされていないポリシー シナリオ

Android 8.0 以降でリリースされるデバイスでは、以下のポリシーのシナリオと例はサポートされていません。

フレームワークのみの OTA 後に新しいベンダー イメージ コンポーネントに対する権限を必要とするシステム イメージへの拡張機能の追加

例: 独自のドメインを必要とする新しい非 AOSP システム プロセスが次回の Android リリースに追加され、新しい非 AOSP HAL へのアクセスを必要とする場合。

新しい(非 AOSP)システムとベンダー コンポーネント間のインタラクションと似ていますが、新しいシステムタイプがフレームワークのみの OTA で導入される点が異なります。新しいタイプを system/sepolicy/public 内のポリシーに追加することはできますが、既存のベンダー ポリシーは Android 8.0 システムのパブリック ポリシーのみをトラッキングしているため、新しいタイプを認識しません。AOSP は、ベンダーが提供するリソースを属性(hal_foo 属性など)を通じて公開することでこれを処理しますが、system/sepolicy/public では属性パートナー拡張機能がサポートされないため、この方法はベンダー ポリシーには使用できません。アクセスは既存のパブリック タイプによって可能にする必要があります。

例: システム プロセス(AOSP または非 AOSP)の変更によって、新しい非 AOSP ベンダー コンポーネントとのインタラクションを変更する必要が生じる場合。

システム イメージ上のポリシーは、特定のベンダーによるカスタマイズの情報なしで作成する必要があります。AOSP の特定のインターフェースに関するポリシーは、system/sepolicy/public 内の属性を通じて公開されます。これにより、ベンダー ポリシーはそれらの属性を使用する将来のシステム ポリシーをオプトインできます。ただし system/sepolicy/public の属性拡張機能はサポートされていないため、システム コンポーネントと新しいベンダー コンポーネント間のインタラクションを規定する(また、AOSP の system/sepolicy/public にすでに存在する属性によって処理されない)すべてのポリシーは、device/manufacturer/device-name/sepolicy に配置する必要があります。つまり、システムタイプは、フレームワークのみの OTA の一部として、ベンダータイプに付与されたアクセス権を変更することはできません。