自主存取控制 (DAC)

新增到建置中的檔案系統物件和服務經常需要單獨的、唯一的 ID,稱為 Android ID (AID)。目前,許多資源(例如文件和服務)不必要地使用核心(Android 定義的)AID;在許多情況下,您可以使用 OEM(OEM 定義的)AID 來代替。

早期版本的 Android(Android 7.x 及更低版本)使用特定於裝置的android_filesystem_config.h檔案擴展了 AID 機制,以指定檔案系統功能和/或自訂 OEM AID。然而,該系統並不直觀,因為它不支援為 OEM AID 使用好聽的名稱,需要您為使用者和群組欄位指定原始數字,而無法將友善名稱與數字 AID 關聯起來。

較新版本的 Android(Android 8.0 及更高版本)支援擴展檔案系統功能的新方法。這種新方法支援以下內容:

  • 設定檔的多個來源位置(啟用可擴充的建置配置)。
  • OEM AID 值的建置時健全性檢查。
  • 產生可根據需要在來源檔案中使用的自訂 OEM AID 標頭。
  • 友善名稱與實際 OEM AID 值的關聯。支援使用者和群組的非數字字串參數,即“foo”而不是“2901”。

其他改進包括從system/core/libcutils/include/private/android_filesystem_config.h中刪除android_ids[]陣列。該數組現在作為完全私有的生成數組存在於 Bionic 中,透過getpwnam()getgrnam()進行存取。 (這具有在修改核心 AID 時產生穩定二進位檔案的副作用。)有關更多詳細資訊的工具和自述文件,請參閱build/make/tools/fs_config

新增 Android ID (AID)

Android 8.0 從 Android 開源專案 (AOSP) 中刪除了android_ids[]陣列。所有 AID 友善的名稱都是在產生 Bionic android_ids[]陣列時從system/core/libcutils/include/private/android_filesystem_config.h頭檔產生的。任何與AID_*相符的define都會被工具拾取,並且*成為小寫名稱。

例如,在private/android_filesystem_config.h中:

#define AID_SYSTEM 1000

變成:

  • 友善名稱:系統
  • uid: 1000
  • 組號:1000

要新增新的 AOSP 核心 AID,只需將#define新增至android_filesystem_config.h頭檔中即可。 AID 將在建置時生成,並可供使用使用者和群組參數的介面使用。該工具驗證新的 AID 不在 APP 或 OEM 範圍內;它還考慮對這些範圍的更改,並應根據更改或新的 OEM 保留範圍自動重新配置。

配置AID

若要啟用新的 AID 機制,請在BoardConfig.mk檔案中設定TARGET_FS_CONFIG_GEN 。該變數保存設定檔列表,使您能夠根據需要附加文件。

按照慣例,設定檔使用名稱config.fs ,但實際上您可以使用任何名稱。 config.fs檔案採用Python ConfigParser ini 格式,包含 caps 部分(用於設定檔系統功能)和 AIDs 部分(用於設定 OEM AID)。

配置 caps 部分

caps 部分支援在建置中的檔案系統物件上設定檔案系統功能(檔案系統本身也必須支援此功能)。

由於在 Android 中以 root 身分執行穩定服務會導致相容性測試套件 (CTS)失敗,因此先前在執行進程或服務時保留功能的要求涉及設定功能,然後使用setuid / setgid到適當的 AID 來運行。使用 caps,您可以跳過這些要求並讓核心為您完成。當控制權交給main()時,您的進程已經具備了所需的功能,因此您的服務可以使用非 root 使用者和群組(這是啟動特權服務的首選方式)。

caps 部分使用以下語法:

部分價值定義
[path]要設定的檔案系統路徑。以 / 結尾的路徑被視為目錄,否則它是一個檔案。

在不同檔案中指定具有相同[path]的多個部分是錯誤的。在 Python 版本 <= 3.2 中,同一檔案可能包含覆蓋前一部分的部分;在Python 3.2中,它被設定為嚴格模式。
mode八進位檔案模式至少 3 位數字的有效八進位檔案模式。若指定 3,則以 0 為前綴,否則以原樣使用模式。
user AID_<用戶> C define有效的AID 或友善的名稱(例如AID_RADIOradio都是可接受的)。若要定義自訂 AID,請參閱設定 AID 部分
group AID_<群組>與用戶相同。
caps帽* bionic/libc/kernel/uapi/linux/capability.h中宣告的名稱,不含前導CAP_ 。允許混合大小寫。帽子也可以是原始的:
  • 二進位(0b0101)
  • 八進位 (0455)
  • 整數 (42)
  • 十六進位 (0xFF)
使用空格分隔多個大寫字母。

有關使用範例,請參閱使用檔案系統功能

配置AID部分

AID 部分包含 OEM AID 並使用下列語法:

部分價值定義
[AID_<name>] <name>可以包含大寫字母、數字和底線字元。小寫版本用作友善名稱。產生的用於程式碼包含的頭檔使用確切的AID_<name>

使用相同的AID_<name>指定多個部分是錯誤的(不區分大小寫,具有與[path]相同的約束)。

<name>必須以分割名稱開頭,以確保它不會與不同的來源發生衝突。
value <數字>有效的 C 樣式數字字串(十六進位、八進位、二進位和十進位)。

使用相同的值選項指定多個部分是錯誤的。

值選項必須在與<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)
  • 系統擴充分區
    • AID_SYSTEM_EXT_RESERVED_START(7500) - AID_SYSTEM_EXT_RESERVED_END(7999)

有關使用範例,請參閱定義 OEM AID 名稱使用 OEM AID

使用範例

以下範例詳細介紹如何定義和使用 OEM AID 以及如何啟用檔案系統功能。 OEM AID 名稱 ( [AID_ name ] ) 必須以分區名稱(例如「 vendor_ 」)開頭,以確保它們不會與未來的 AOSP 名稱或其他分區衝突。

定義 OEM AID 名稱

若要定義 OEM AID,請建立config.fs檔案並設定 AID 值。例如,在device/x/y/config.fs中,設定以下內容:

[AID_VENDOR_FOO]
value: 2900

建立檔案後,設定TARGET_FS_CONFIG_GEN變數並在BoardConfig.mk中指向它。例如,在device/x/y/BoardConfig.mk中,設定以下內容:

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

您的自訂 AID 現在可以在新版本中被整個系統使用。

使用 OEM 輔助工具

若要使用 OEM AID,請在 C 程式碼中將oemaids_headers包含在關聯的 Makefile 中,並新增#include "generated_oem_aid.h" ,然後開始使用宣告的識別碼。例如,在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
    

由於從友善名稱到 uid 的內部對應是由/vendor/etc/passwd/vendor/etc/group執行的,因此必須掛載供應商分區。

關聯友善名稱

Android 9 支援將友善名稱與實際 OEM AID 值關聯。您可以對使用者和群組使用非數字字串參數,即“ vendor_ foo”而不是“2901”。

從 AID 轉換為友善名稱

對於OEM AID ,Android 8.x 要求將oem_####getpwnam和類似函數一起使用,以及在透過getpwnam處理尋找的位置(例如init腳本)。在 Android 9 中,您可以使用 Bionic 中的getpwnamgetgrnam朋友將 Android ID (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

建立檔案後,將TARGET_FS_CONFIG_GEN設定為指向BoardConfig.mk中的該檔案。例如,在device/x/y/BoardConfig.mk中,設定以下內容:

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

當執行服務vendor_ foo時,它以CAP_SYS_ADMINCAP_SYS_NICE功能啟動,沒有setuidsetgid呼叫。另外, vendor_ foo服務的SELinux策略不再需要setuidsetgid能力,可以刪除。

配置覆蓋 (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 能夠處理兩個不同表中的目錄和檔案。 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_PACKAGES包含fs_config_dirs和/或fs_config_files ,以便可以將它們分別安裝到/system/etc/fs_config_dirs/system/etc/fs_config_files 。建置系統在$(TARGET_DEVICE_DIR)中搜尋自訂android_filesystem_config.h ,其中BoardConfig.mk存在。如果此檔案存在於其他位置,請將板配置變數TARGET_ANDROID_FILESYSTEM_CONFIG_H設定為指向該位置。

設定檔系統

在 Android 6.0 及更高版本中設定檔系統:

  1. 建立$(TARGET_DEVICE_DIR)/android_filesystem_config.h檔案。
  2. fs_config_dirs和/或fs_config_files新增至板設定檔中的PRODUCT_PACKAGES (例如$(TARGET_DEVICE_DIR)/device.mk )。

覆蓋範例

此範例顯示了用於覆蓋system/bin/glgps守護程式以在device/ vendor / device目錄中新增喚醒鎖定支援的修補程式。請記住以下幾點:

  • 每個結構條目都是模式、uid、gid、功能和名稱。 system/core/include/private/android_filesystem_config.h自動包含以提供清單 #defines ( 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運行。依賴system/code/include/private_filesystem_config.h的檔案或目錄結構或fs_config裝置製造商私有執行檔必須新增libcutils庫相依性。
  • 需要設備製造商的system/core/include/private/android_filesystem_config.h的私有分支副本以及現有目標上的額外內容以移動到device/ vendor / device /android_filesystem_config.h
  • 保留將 SELinux 強制存取控制 (MAC) 套用至目標系統上的設定檔的權利,包含使用fs_config()的自訂目標執行檔的實作必須確保存取。