任意アクセス制御(DAC)

ファイル システムのオブジェクトやサービスをビルドに追加する際、Android ID(AID)と呼ばれる一意の ID が必要となることがよくあります。現在、ファイルやサービスなど、多くのリソースでコア AID(Android が定義する AID)が不必要に使用されていますが、ほとんどの場合、代わりに OEM AID(OEM が定義する AID)を使用できます。

以前のバージョンの Android(Android 7.x 以前)では、デバイス固有の android_filesystem_config.h ファイルを使用して AID メカニズムを拡張することで、ファイル システム機能やカスタム OEM AID を指定していました。しかし、このシステムの場合、OEM AID に対してナイスネームを使用することができず、直感的ではありませんでした。user フィールドや group フィールドに未加工の数値を指定しなければならず、その数値 AID に対してわかりやすい名前を関連付ける方法もありませんでした。

新しいバージョンの Android(Android 8.0 以降)では、ファイル システム機能を拡張するための新しい方法がサポートされています。この新しい方法では、以下がサポートされます。

  • 構成ファイルを複数の場所に配置できます(幅広いビルド構成が可能になります)。
  • ビルド時に OEM AID 値のサニティ チェックを実行できます。
  • 必要に応じて、カスタム OEM AID ヘッダーを生成し、ソースファイル内で使用できます。
  • わかりやすい名前と実際の OEM AID 値を関連付けることができます。user や group に対して数値以外の文字列引数を使用できます(たとえば、「2901」ではなく「foo」を使用できます)。

もう一つの改良点として、system/core/libcutils/include/private/android_filesystem_config.h から android_ids[] 配列が削除されています。この配列は現在、Bionic 内の完全非公開生成配列として存在しており、getpwnam()getgrnam() によるアクセサが実装されています(この改良点には、コア AID を編集すると永続的バイナリが生成されるという副作用があります)。ツールの使用方法や、詳細が記載された README ファイルについては、build/make/tools/fs_config をご覧ください。

Android ID(AID)を追加する

Android 8.0 以降、Android オープンソース プロジェクト(AOSP)から android_ids[] 配列が削除されました。代わりに、Bionic の android_ids[] 配列を生成する際、必ず、AID フレンドリーな名前が system/core/libcutils/include/private/android_filesystem_config.h ヘッダー ファイルから生成されるようになっています。AID_* に合致する define がツールによってピックアップされ、* の部分を小文字にした名前が生成されます。

たとえば、private/android_filesystem_config.h 内に次の行があるとします。

#define AID_SYSTEM 1000

この行から、以下の値が生成されます。

  • わかりやすい名前: system
  • uid: 1000
  • gid: 1000

新しい AOSP コア AID を追加する場合は、#defineandroid_filesystem_config.h ヘッダー ファイルに追加するだけで済みます。ビルド時に AID が生成され、user 引数や group 引数を使用するインターフェースで利用できます。ツールによって、新しい AID が APP や OEM の範囲外にあるか検証されます。このツールは各範囲の変更を認識し、範囲の変更や新しい OEM 予約範囲に基づいて自動的に再構成を実行します。

AID を設定する

新しい AID メカニズムを有効にするには、BoardConfig.mk ファイル内で TARGET_FS_CONFIG_GEN を設定します。この変数は構成ファイルのリストを格納できるため、必要なだけファイルを追加できます。

一般的に、構成ファイルの名前としては config.fs が使用されますが、実際には任意の名前を使用できます。config.fs ファイルは Python ConfigParser ini 形式で、ファイル システム機能を設定する caps セクションと OEM AID を設定する AID セクションがあります。

caps セクションを設定する

caps セクションは、ビルド内のファイル システム オブジェクトに対するファイル システム機能の設定をサポートしています(ファイル システム自体がこの機能をサポートしている必要があります)。

永続的サービスを Android の root として実行すると、互換性テストスイート(CTS)が失敗します。そのため、これまでは、プロセスやサービスの実行中にファイル システム機能を保持する要件として、機能をセットアップしてから、setuid / setgid を使用して対象の AID を実行する必要がありました。caps を使用すると、このような要件を回避して、カーネルに処理させることができます。制御が main() に渡されたときには、プロセスに必要な機能がすでに有効になっているため、サービスは非 root のユーザーやグループを使用できます(特権サービスを開始する場合、この方法をおすすめします)。

caps セクションでは以下の構文を使用します。

セクション 定義
[path] 設定するファイル システムのパス。「/」で終わるパスはディレクトリを示し、それ以外のパスはファイルを示します。

複数のファイルで同じ [path] を使用して複数のセクションを指定するとエラーになります。Python バージョン 3.2 以前の場合、1 つのファイル内に、以前のセクションをオーバーライドするセクションを含めることができます。Python 3.2 の場合、strict モードに設定されています。
mode 8 進数のファイルモード 有効なファイルモード(パーミッション)の 8 進数表記(3 桁以上)。3 を指定した場合は、先頭に 0 が付きます。それ以外の場合は、モード値がそのまま使用されます。
user AID_<ユーザー> 有効な AID の C define、あるいは、わかりやすい名前(たとえば、AID_RADIOradio のどちらでも使用できます)。カスタム AID を定義する場合は、AID セクションを設定するをご覧ください。
group AID_<グループ> ユーザーと同じです。
caps cap* bionic/libc/kernel/uapi/linux/capability.h 内で宣言されている名前(先頭の CAP_ を削除します)。大文字と小文字を混ぜて使用できます。caps には、以下の未加工数値を使用することもできます。
  • 2 進数(0b0101)
  • 8 進数(0455)
  • int(42)
  • 16 進数(0xFF)
caps が複数ある場合は、空白文字を使用して区切ります。

使用例については、ファイル システム機能を使用するをご覧ください。

AID セクションを設定する

AID セクションは OEM AID を格納し、以下の構文を使用します。

セクション 定義
[AID_<name>] <name> には、一部の大文字、数字、アンダースコアを使用できます。小文字バージョンは、わかりやすい名前として使用されます。コードをインクルードするために生成されるヘッダー ファイルでは、AID_<name> がそのまま使用されます。

同じ AID_<name> を使用して複数のセクションを指定するとエラーになります([path] と同様、大文字と小文字は区別されません)。

<name> は、別のソースと競合しないように、パーティション名で開始する必要があります。
value <数値> 有効な C スタイルの数値列(16 進数、8 進数、2 進数、10 進数)。

同じ value オプションを使用して複数のセクションを指定するとエラーになります。

value オプションは、<name> で使用するパーティションに対応する範囲で指定する必要があります。有効なパーティションとその対応範囲のリストは、system/core/libcutils/include/private/android_filesystem_config.h で定義されています。以下のオプションがあります。
  • ベンダー パーティション
    • AID_OEM_RESERVED_START(2900) - AID_OEM_RESERVED_END(2999)
    • AID_OEM_RESERVED_2_START(5000) - AID_OEM_RESERVED_2_END(5999)
  • システム パーティション
    • AID_SYSTEM_RESERVED_START(6000) - AID_SYSTEM_RESERVED_END(6499)
  • ODM パーティション
    • AID_ODM_RESERVED_START(6500) - AID_ODM_RESERVED_END(6999)
  • プロダクト パーティション
    • AID_PRODUCT_RESERVED_START(7000) - AID_PRODUCT_RESERVED_END(7499)
  • System_ext パーティション
    • AID_SYSTEM_EXT_RESERVED_START(7500) - AID_SYSTEM_EXT_RESERVED_END(7999)

使用例については、OEM AID 名を定義するOEM AID を使用するをご覧ください。

使用例

以下では、OEM AID を定義して使用する方法と、ファイル システム機能を有効にする方法について、例に基づいて説明します。OEM AID 名([AID_<名前>])は、将来の AOSP 名や他のパーティションと競合しないように、「vendor_」などのパーティション名で始める必要があります。

OEM AID 名を定義する

OEM AID を定義するには、config.fs ファイルを作成して、AID 値を設定します。たとえば、device/x/y/config.fs 内で次のように設定します。

[AID_VENDOR_FOO]
value: 2900

ファイルを作成したら、BoardConfig.mk 内で、TARGET_FS_CONFIG_GEN 変数がこのファイルをポイントするように設定します。たとえば、device/x/y/BoardConfig.mk 内で次のように設定します。

TARGET_FS_CONFIG_GEN += device/x/y/config.fs

これにより、新しいビルドでは、システム全体でカスタム AID を使用できるようになります。

OEM AID を使用する

OEM AID を使用するには、C コードで、関連付けられた Makefile 内に oemaids_headers を組み込んで、#include "generated_oem_aid.h" を追加し、宣言された ID の使用を開始します。たとえば、my_file.c に次のように追加します。

#include "generated_oem_aid.h"
…

If (ipc->uid == AID_VENDOR_FOO) {
  // Do something
...

関連付けられた Android.bp ファイルに次のように追加します。

header_libs: ["oemaids_headers"],

Android.mk ファイルを使用している場合は、次のように追加します。

LOCAL_HEADER_LIBRARIES := oemaids_headers

わかりやすい名前を使用する

Android 9 以降、AID 名をサポートするすべてのインターフェースで、わかりやすい名前を使用できるようになりました。たとえば、以下のようになります。

  • some/init.rcchown コマンド:
    chown vendor_foo /vendor/some/vendor_foo/file
    
  • some/init.rcservice:
    service vendor_foo /vendor/bin/foo_service
        user vendor_foo
        group vendor_foo
    

/vendor/etc/passwd/vendor/etc/group によって、わかりやすい名前から uid への内部マッピングが実行されるため、ベンダー パーティションをマウントする必要があります。

わかりやすい名前を関連付ける

Android 9 以降、わかりやすい名前と実際の OEM AID 値との関連付けがサポートされるようになりました。user や group に対して、数値以外の文字列引数を使用できます(例: 「2901」ではなく「vendor_foo」など)。

AID からわかりやすい名前に変換する

OEM AID に関して、Android 8.x では、getpwnam などの関数や、getpwnam によるルックアップを処理する場所(init スクリプトなど)で、oem_#### を使用する必要がありました。Android 9 以降は、Bionic 内で getpwnamgetgrnam のような関数を使用して、Android ID(AID)をわかりやすい名前に変換したり、逆に、わかりやすい名前を AID に変換したりできるようになりました。

ファイル システム機能を使用する

ファイル システム機能を有効にするには、config.fs ファイル内に caps セクションを作成します。たとえば、device/x/y/config.fs 内に次のセクションを追加します。

[system/bin/foo_service]
mode: 0555
user: AID_VENDOR_FOO
group: AID_SYSTEM
caps: SYS_ADMIN | SYS_NICE

ファイルを作成したら、BoardConfig.mk 内で、TARGET_FS_CONFIG_GEN がこのファイルをポイントするように設定します。たとえば、device/x/y/BoardConfig.mk 内で次のように設定します。

TARGET_FS_CONFIG_GEN += device/x/y/config.fs

サービス vendor_foo が実行されると、setuidsetgid を呼び出すことなく、CAP_SYS_ADMIN 機能と CAP_SYS_NICE 機能が有効になります。また、vendor_foo サービスの SELinux ポリシーで setuid 機能と setgid 機能が不要になるため、両機能をポリシーから削除できます。

オーバーライドを設定する(Android 6.x~7.x)

Android 6.0 において、fs_config とそれに関連する構造定義(system/core/include/private/android_filesystem_config.h)が system/core/libcutils/fs_config.c に移動しました。これにより、/system/etc/fs_config_dirs/system/etc/fs_config_files にバイナリ ファイルをインストールすることで、構成の更新やオーバーライドができるようになりました。追加の glob 表現を使用する可能性があるディレクトリやファイルに対して独立したマッチング ツールや解析ルールを使用することで、Android は、2 つの異なるテーブル内のディレクトリやファイルを処理できるようになりました。system/core/libcutils/fs_config.c 内の構造定義は、ディレクトリやファイルのランタイム読み取りが可能になりました。また、ビルド時にホストが同じファイルを使用して、ファイル システム イメージを ${OUT}/system/etc/fs_config_dirs${OUT}/system/etc/fs_config_files としてビルドできるようになりました。

このようにファイル システムを拡張するオーバーライド方法は、Android 8.0 で導入されたモジュール式構成システムに取って代わられましたが、現在でも、必要に応じて以前の方法を使用することができます。以下では、オーバーライド ファイルを生成してインクルードし、ファイル システムを設定する方法について説明します。

オーバーライド ファイルを生成する

build/tools/fs_config 内の fs_config_generate ツールを使用することで、/system/etc/fs_config_dirs/system/etc/fs_config_files というバイナリ ファイルのペアを生成できます。このツールは、libcutils ライブラリ関数(fs_config_generate())を使用して DAC 要件をバッファに格納し、インクルード ファイルのルールを定義して DAC ルールを制度化します。

使用するには、オーバーライドとして機能するインクルード ファイルを device/vendor/device/android_filesystem_config.h 内に作成します。このファイルでは、system/core/include/private/android_filesystem_config.h 内で定義した structure fs_path_config 形式を使用し、以下のように、ディレクトリ シンボルやファイル シンボルの構造初期化を指定する必要があります。

  • ディレクトリには android_device_dirs[] を使用します。
  • ファイルには android_device_files[] を使用します。

android_device_dirs[]android_device_files[] を使用しない場合は、NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRSNO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES を定義できます(下記のを参照)。また、ボード構成の TARGET_ANDROID_FILESYSTEM_CONFIG_H で、android_filesystem_config.h の適用ベース名を使用して、オーバーライド ファイルを指定することもできます。

オーバーライド ファイルをインクルードする

ファイルをインクルードするには、PRODUCT_PACKAGESfs_config_dirsfs_config_files(いずれか一方でも可)が含まれていて、/system/etc/fs_config_dirs/system/etc/fs_config_files にそれぞれインストールできることを確認します。ビルドシステムは、BoardConfig.mk が存在する $(TARGET_DEVICE_DIR) を対象に、カスタム android_filesystem_config.h の検索を行います。このファイルが他の場所にある場合は、その場所をポイントするようにボード構成変数 TARGET_ANDROID_FILESYSTEM_CONFIG_H を設定してください。

ファイル システムを設定する

Android 6.0 以降でファイル システムを設定するには:

  1. $(TARGET_DEVICE_DIR)/android_filesystem_config.h ファイルを作成します。
  2. ボード構成ファイルの PRODUCT_PACKAGES fs_config_dirsfs_config_files(いずれか一方でも可)を追加します(ボード構成ファイルの例: $(TARGET_DEVICE_DIR)/device.mk)。

オーバーライドの例

system/bin/glgps デーモンをオーバーライドして、device/vendor/device ディレクトリにウェイクロック サポートを追加するパッチの例を以下に示します。以下の点にご注意ください。

  • 各構造エントリは、mode、uid、gid、caps(機能)、名前です。system/core/include/private/android_filesystem_config.h が自動的にインクルードされ、マニフェストの #define(AID_ROOTAID_SHELLCAP_BLOCK_SUSPEND)を指定します。
  • android_device_files[] セクションには、指定がない場合に system/etc/fs_config_dirs へのアクセスを抑制するアクションが含まれています。これは、ディレクトリ オーバーライドの対象となるコンテンツがない場合の追加的な DAC 保護として機能します。ただし、保護能力は弱いため、/system を制御したユーザーは通常、あらゆる操作が可能になります。
diff --git a/android_filesystem_config.h b/android_filesystem_config.h
new file mode 100644
index 0000000..874195f
--- /dev/null
+++ b/android_filesystem_config.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+/* This file is used to define the properties of the filesystem
+** images generated by build tools (eg: mkbootfs) and
+** by the device side of adb.
+*/
+
+#define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
+/* static const struct fs_path_config android_device_dirs[] = { }; */
+
+/* Rules for files.
+** These rules are applied based on "first match", so they
+** should start with the most specific path and work their
+** way up to the root. Prefixes ending in * denotes wildcard
+** and will allow partial matches.
+*/
+static const struct fs_path_config android_device_files[] = {
+  { 00755, AID_ROOT, AID_SHELL, (1ULL << CAP_BLOCK_SUSPEND),
"system/bin/glgps" },
+#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
+  { 00000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_dirs" },
+#endif
+};

diff --git a/device.mk b/device.mk
index 0c71d21..235c1a7 100644
--- a/device.mk
+++ b/device.mk
@@ -18,7 +18,8 @@ PRODUCT_PACKAGES := \
     libwpa_client \
     hostapd \
     wpa_supplicant \
-    wpa_supplicant.conf
+    wpa_supplicant.conf \
+    fs_config_files

 ifeq ($(TARGET_PREBUILT_KERNEL),)
 ifeq ($(USE_SVELTE_KERNEL), true)

以前のリリースからファイル システムを移行する

Android 5.x 以前からファイル システムを移行する場合は、Android 6.x に関する以下の点に留意してください。

  • 一部のインクルード、構造、インライン定義が削除されます。
  • libcutils は、system/core/include/private/android_filesystem_config.h から直接実行するのではなく、参照する必要があります。デバイス メーカーの非公開実行ファイルが、ファイル構造やディレクトリ構造、あるいは fs_config に関して system/code/include/private_filesystem_config.h に依存している場合は、libcutils ライブラリ依存関係を追加する必要があります。
  • 既存のターゲットに対する追加コンテンツを含む system/core/include/private/android_filesystem_config.h のデバイス メーカー非公開ブランチコピーは、device/vendor/device/android_filesystem_config.h に移動する必要があります。
  • ターゲット システムの構成ファイルに対して SELinux 強制アクセス制御(MAC)を適用する権限を有します。そのため、fs_config() を使用してカスタム ターゲット実行ファイルを組み込んでいる実装の場合、アクセスを確保する必要があります。