Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

SELinux を検証する

Android では OEM に対し、SELinux の実装を徹底してテストすることを強くおすすめしています。SELinux を実装するメーカーは、まずデバイスのテストプールに新しいポリシーを適用する必要があります。

新しいポリシーを適用したら、getenforce コマンドを実行して、SELinux が正しいモードで実行されていることを確認します。

このコマンドにより、Enforcing モードか Permissive モードのどちらかのグローバル SELinux モードが出力されます。各ドメインの SELinux モードを確認するには、対応するファイルを調べるか、/platform/system/sepolicy/tools/ の適切なフラグ(-p)を使用して最新バージョンの sepolicy-analyze を実行する必要があります。

拒否を確認する

エラーを確認します。エラーはイベントログとして dmesglogcat にルーティングされ、デバイス上でローカルで確認できます。メーカーは、dmesg への SELinux の出力をデバイス上で調べ、公開リリース前に permissive モードで設定を調整して、最終的に enforcing モードに切り替える必要があります。SELinux ログメッセージには avc: が含まれているため、grep で簡単に見つけることができます。cat /proc/kmsg を実行して、残っている拒否ログをキャプチャしたり、cat /sys/fs/pstore/console-ramoops を実行して前回のブートから拒否ログをキャプチャしたりできます。

メーカーはこの出力を確認することで、システム ユーザーまたはシステム コンポーネントによる SELinux ポリシー違反を簡単に特定できます。特定した不正な動作を修正するには、ソフトウェアと SELinux ポリシーのいずれかまたは両方に変更を加えます。

具体的には、このログメッセージには、どのプロセスが enforcing モードで違反となるか、そしてその違反の理由が示されます。次に例を示します。

avc: denied  { connectto } for  pid=2671 comm="ping" path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket

この出力は次のように解釈できます。

  • 上記の { connectto } は、実行されたアクションを表します。 末尾の tclassunix_stream_socket)と合わせて確認することで、何に対して何が実行されたかが大まかにわかります。このケースでは、何かが unix ストリーム ソケットへの接続を試みていました。
  • scontext (u:r:shell:s0) は、どのコンテキストでこのアクションが開始されたかを示します。このケースでは、シェルとして実行された何かがアクションを実行しています。
  • tcontext (u:r:netd:s0) は、アクションのターゲットのコンテキストを示します。このケースでは、netd がオーナーである unix_stream_socket がコンテキストになっています。
  • 上の行の comm="ping" を確認すると、拒否が生成された時点で何が実行されていたかについて、さらにヒントが得られます。このケースでは、有益なヒントが示されています。

別の例を示します。

adb shell su root dmesg | grep 'avc: '

出力:

<5> type=1400 audit: avc:  denied  { read write } for  pid=177
comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0
tcontext=u:object_r:kmem_device:s0 tclass=chr_file

この拒否で重要となる要素を以下に示します。

  • アクション - 試行されたアクションがかっこ内に示されています(read write または setenforce)。
  • 実行元 - scontext(ソース コンテキスト)のエントリは、実行元(このケースでは rmt_storage デーモン)を表します。
  • オブジェクト - tcontext(ターゲット コンテキスト)のエントリは、アクションの対象となったオブジェクトを表します。このケースでは kmem です。
  • 結果 - tclass(ターゲット クラス)のエントリは、アクションの対象となったオブジェクトのタイプを示します。このケースでは chr_file(キャラクター デバイス)です。

permissive に切り替える

SELinux の適用は、userdebug ビルドまたは eng ビルドで ADB を使用して無効にできます。それには、まず adb root を実行して ADB を root に切り替えます。次に、次のコマンドを実行して SELinux の適用を無効にします。

adb shell setenforce 0

または、(デバイス起動時の初期に)カーネル コマンドラインで次のコマンドを実行します。

androidboot.selinux=permissive
androidboot.selinux=enforcing

audit2allow を使用する

selinux/policycoreutils/audit2allow ツールは、dmesg 拒否を対応する SELinux ポリシー ステートメントに変換します。それにより、SELinux の開発が大幅に効率化されます。 audit2allow は、デバイスの出荷時には Android ソースツリーの一部として存在し、ソースから Android をビルドするときに自動的にコンパイルされます。

これを使用するには、次のコマンドを実行します。

adb pull /sys/fs/selinux/policy
adb logcat -b all -d | audit2allow -p policy

その場合も、権限を追加する際にはその権限が過度なものではないか注意する必要があります。たとえば、先ほど示した rmt_storage 拒否を audit2allow にフィードすると、次のような SELinux ポリシー ステートメントが結果として示されます。

#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };

これでは、カーネルメモリに書き込む権限が rmt に付与され、大きなセキュリティ ホールが生まれてしまいます。多くの場合、audit2allow ステートメントは出発点にすぎません。これらのステートメントを導入した場合は、必要に応じてソースドメインとターゲットのラベルを変更し、適切なマクロを利用して、適切なポリシーを完成させます。調査した拒否によっては、ポリシーの変更ではなく、不適切なアプリケーションの変更が必要になることもあります。