בקרת גישה שרירותית (DAC)

לרוב, אובייקטים ושירותים של מערכת קבצים שנוספו לגרסה היציבה זקוקים למזהים ייחודיים נפרדים, שנקראים מזהי Android‏ (AID). בשלב זה, משאבים רבים כמו קבצים ושירותים משתמשים ב-AIDs ליבה (שהוגדרו על ידי Android) ללא צורך. במקרים רבים אפשר להשתמש ב-AIDs של יצרן ציוד מקורי (שהוגדרו על ידי יצרן ציוד מקורי) במקום זאת.

בגרסאות קודמות של Android (Android 7.x וגרסאות ישנות יותר), מנגנון ה-AIDs הורחב באמצעות קובץ android_filesystem_config.h ספציפי למכשיר כדי לציין את היכולות של מערכת הקבצים ו/או AIDs מותאמים אישית של יצרני ציוד מקורי (OEM). עם זאת, המערכת הזו לא הייתה אינטואיטיבית כי היא לא תמכה בשמות נוחים למזהי AID של OEM, והייתם צריכים לציין את המספר הגולמי בשדות של משתמשים וקבוצות, בלי אפשרות לשייך שם ידידותי למזהה ה-AID המספרי.

בגרסאות חדשות יותר של Android (Android 8.0 ואילך) יש תמיכה בשיטה חדשה להרחבת היכולות של מערכת הקבצים. השיטה החדשה תומכת באפשרויות הבאות:

  • מספר מיקומי מקור לקובצי תצורה (מאפשר להרחיב את הגדרות ה-build).
  • בדיקת תקינות של ערכי AID של יצרן ציוד מקורי (OEM) בזמן ה-build.
  • יצירת כותרת OEM AID בהתאמה אישית שאפשר להשתמש בה בקובצי מקור לפי הצורך.
  • שיוך של שם ידידותי לערך ה-AID בפועל של יצרן הציוד המקורי. תמיכה בארגומנטים של מחרוזות לא מספריות למשתמש ולקבוצה, כלומר "foo" במקום "2901".

שיפורים נוספים כוללים הסרה של מערך android_ids[] מ-system/core/libcutils/include/private/android_filesystem_config.h. המערך הזה קיים עכשיו ב-Bionic כמערך שנוצר באופן פרטי לחלוטין, עם פונקציות גישה עם getpwnam() ו-getgrnam(). (התוצאה הלוואי של השיטה הזו היא יצירת קובצי בינארי יציבים כש-AIDs הליבה משתנים). תוכלו למצוא כלים וקובץ README עם פרטים נוספים במאמר build/make/tools/fs_config.

הוספת מזהי Android‏ (AID)

בגרסה 8.0 של Android הוסר מערך android_ids[] מפרויקט הקוד הפתוח של Android‏ (AOSP). במקום זאת, כל השמות התואמים ל-AID נוצרים מקובץ הכותרת system/core/libcutils/include/private/android_filesystem_config.h בזמן יצירת המערך android_ids[] של Bionic. כל define שתואם ל-AID_* מזוהה על ידי הכלים, ו-* הופך לשם באותיות קטנות.

לדוגמה, ב-private/android_filesystem_config.h:

#define AID_SYSTEM 1000

הופך ל-

  • שם חיבה: system
  • uid: ‏ 1000
  • gid: 1000

כדי להוסיף AID חדש של הליבה של AOSP, פשוט מוסיפים את #define לקובץ הכותרת android_filesystem_config.h. ה-AID נוצר בזמן ה-build וזמין לממשקים שמשתמשים בארגומנטים של משתמשים וקבוצות. הכלי מאמת שה-AID החדש לא נמצא בטווח של האפליקציה או של יצרן הציוד המקורי. הוא גם מתייחס לשינויים בטווחים האלה, ועליו להגדיר מחדש באופן אוטומטי כשיש שינויים או טווחים חדשים שמוגדרים לשימוש יצרן הציוד המקורי.

הגדרת AIDs

כדי להפעיל את המנגנון החדש של AIDs, מגדירים את הערך TARGET_FS_CONFIG_GEN בקובץ BoardConfig.mk. המשתנה הזה מכיל רשימה של קובצי תצורה, ומאפשר לצרף קבצים לפי הצורך.

לפי הסכמה, קובצי התצורה נקראים config.fs, אבל בפועל אפשר להשתמש בכל שם. קובצי config.fs הם בפורמט ini של Python ConfigParser, והם כוללים קטע caps (להגדרת יכולות של מערכת הקבצים) וקטע AIDs (להגדרת AIDs של יצרני ציוד מקורי).

הגדרת הקטע של המגבלות

הקטע caps תומך בהגדרת יכולות של מערכת קבצים באובייקטים של מערכת הקבצים בתוך ה-build (גם מערכת הקבצים עצמה צריכה לתמוך בפונקציונליות הזו).

מכיוון שהפעלת שירות יציב בתור root ב-Android גורמת לערכת בדיקות התאימות (CTS) להיכשל, הדרישות הקודמות לשמירה על יכולת בזמן הפעלת תהליך או שירות כללו הגדרת יכולות ואז שימוש ב-setuid/setgid כדי להפעיל את ה-AID המתאים. באמצעות כובע, אפשר לדלג על הדרישות האלה ולאפשר לליבה לבצע את הפעולה בשבילכם. כשהשליטה מועברת ל-main(), לתהליך כבר יש את היכולות הנדרשות כדי שהשירות יוכל להשתמש במשתמש ובקבוצה שאינם משתמש root (זוהי הדרך המועדפת להפעלת שירותים עם הרשאות).

התחביר של הקטע caps הוא:

קטע ערך הגדרה
[path] הנתיב למערכת הקבצים שרוצים להגדיר. נתיב שמסתיים ב-/ נחשב לתיקייה, אחרת הוא נחשב לקובץ.

אסור לציין כמה קטעים עם אותו [path] בקבצים שונים. בגרסאות Python בגרסה 3.2 ואילך, אותו הקובץ יכול להכיל קטעים שמבטלים את הקטע הקודם. בגרסה Python 3.2, הוא מוגדר למצב קפדני.
mode מצב קובץ אוקטלי אופן קובץ אוקטלי חוקי בן לפחות 3 ספרות. אם מציינים 3, מופיע בתחילת הערך 0. אחרת, המערכת משתמשת במצב כפי שהוא.
user AID_<user> אפשר להזין את הערך C define עבור מזהה AID תקף או את השם הקליט (למשל, אפשר להזין את הערכים AID_RADIO ו-radio). כדי להגדיר AID מותאם אישית, עיינו בקטע הגדרת הקטע AID.
group AID_‎<group>‎ זהה למשתמש.
caps cap* השם כפי שהוצהר ב-bionic/libc/kernel/uapi/linux/capability.h, ללא ה-CAP_ המוביל. מותר להשתמש באותיות רישיות ורגילות. אפשר גם להשתמש ב-Caps בפורמט הגולמי:
  • בינארי (0b0101)
  • אוקטלי (0455)
  • int (42)
  • הקסדצימלי (0xFF)
מפרידים בין כמה אותיות רישיות באמצעות רווחים.

דוגמה לשימוש מפורטת במאמר שימוש ביכולות של מערכת הקבצים.

הגדרת הקטע AID

הקטע AID מכיל מזהי AID של יצרני ציוד מקורי, והוא משתמש בתחביר הבא:

קטע ערך הגדרה
[AID_<name>] השדה <name> יכול להכיל תווים מהקבוצה: אותיות גדולות, ספרות וקווים תחתונים. הגרסה באותיות קטנות משמשת בתור השם הידידותי. קובץ הכותרת שנוצר להכללת הקוד משתמש ב-AID_<name> המדויק.

אסור לציין כמה קטעים עם אותו AID_<name> (ללא קשר לאותיות רישיות, עם אותן אילוצים כמו [path]). השדה

<name> חייב להתחיל בשם של מחיצה כדי לוודא שהוא לא יהיה בקונפליקט עם מקורות שונים.
value <number> מחרוזת מספרים תקינה בסגנון 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)
  • מחיצת System_ext
    • AID_SYSTEM_EXT_RESERVED_START‏(7500) – AID_SYSTEM_EXT_RESERVED_END‏(7999)

דוגמאות לשימוש זמינות במאמרים הגדרת שמות של מזהי AID של יצרן ציוד מקורי ושימוש במזהי AID של יצרן ציוד מקורי.

דוגמאות לשימוש

בדוגמאות הבאות מוסבר איך מגדירים מזהה OEM AID ומשתמשים בו, ואיך מפעילים את היכולות של מערכת הקבצים. שמות AID של יצרן ציוד מקורי ([AID_name]) חייבים להתחיל בשם של מחיצה, כמו vendor_, כדי לוודא שהם לא יהיו בקונפליקט עם שמות עתידיים של AOSP או עם מחיצות אחרות.

הגדרת שמות של מזהי AID של יצרני ציוד מקורי

כדי להגדיר AID של OEM, יוצרים קובץ 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 בהתאמה אישית בגרסה חדשה.

שימוש במזהי AID של יצרני ציוד מקורי

כדי להשתמש ב-AID של יצרן ציוד מקורי, צריך לכלול את oemaids_headers ב-Makefile המשויך בקוד C, להוסיף את #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. לדוגמה:

  • בפקודה chown ב-some/init.rc:
    chown vendor_foo /vendor/some/vendor_foo/file
    
  • ב-service ב-some/init.rc:
    service vendor_foo /vendor/bin/foo_service
        user vendor_foo
        group vendor_foo
    

מכיוון שהמיפוי הפנימי משם ידידותי ל-uid מתבצע על ידי /vendor/etc/passwd ו-/vendor/etc/group, צריך לטעון את המחיצה של הספק.

שיוך שמות שקל להבין

ב-Android 9 יש תמיכה בשיוך שם ידידותי לערך ה-AID בפועל של יצרן הציוד המקורי (OEM). אפשר להשתמש בארגומנטים של מחרוזות לא מספריות למשתמש ולקבוצה, כלומר "vendor_foo" במקום "2901".

המרה מ-AID לשמות ידידותיים

ב-Android 8.x, מזהי AID של יצרני ציוד מקורי נדרשו להשתמש ב-oem_#### עם getpwnam ופונקציות דומות, וגם במקומות שמטפלים בחיפושים באמצעות getpwnam (כמו סקריפטים של init). ב-Android 9, אפשר להשתמש בחברים getpwnam ו-getgrnam ב-Bionic כדי להמיר מזהי Android‏ (AID) לשמות ידידותיים ולהפך.

שימוש ביכולות של מערכת הקבצים

כדי להפעיל את היכולות של מערכת הקבצים, יוצרים קטע caps בקובץ config.fs. לדוגמה, בקובץ 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_ADMIN ו-CAP_SYS_NICE בלי קריאות ל-setuid ול-setgid. בנוסף, מדיניות SELinux של השירות vendor_foo כבר לא זקוקה ליכולות 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 לטפל בתיקיות ובקבצים בשתי טבלאות שונות. הגדרות המבנה ב-system/core/libcutils/fs_config.c לא רק מאפשרות קריאה של ספריות וקבצים בסביבת זמן הריצה, אלא המארח יכול להשתמש באותם קבצים במהלך זמן ה-build כדי ליצור קובצי אימג' של מערכת קבצים כמו ${OUT}/system/etc/fs_config_dirs ו-${OUT}/system/etc/fs_config_files.

שיטת ההחרגה להרחבת מערכת הקבצים הוחלפה במערכת תצורה מודולרית שהוצגה ב-Android 8.0, אבל עדיין אפשר להשתמש בשיטה הישנה אם רוצים. בקטעים הבאים מוסבר איך ליצור קבצים של שינוי ברירת המחדל, לכלול אותם ולהגדיר את מערכת הקבצים.

יצירת קובצי שינוי

אפשר ליצור את הקבצים הבינאריים הממוזנים /system/etc/fs_config_dirs ו-/system/etc/fs_config_files באמצעות הכלי fs_config_generate ב-build/tools/fs_config. הכלי משתמש בפונקציית ספרייה libcutils‏ (fs_config_generate()) כדי לנהל את דרישות ה-DAC במאגר, ומגדיר כללים לקובץ include כדי להטמיע את כללי ה-DAC.

כדי להשתמש בה, יוצרים קובץ include ב-device/vendor/device/android_filesystem_config.h שמשמש כביטול. הקובץ צריך להיות בפורמט structure fs_path_config שמוגדר ב-system/core/include/private/android_filesystem_config.h, עם אתחול המבנה הבא לסמלי ספריות וקבצים:

  • בספריות, צריך להשתמש ב-android_device_dirs[].
  • לקבצים, צריך להשתמש ב-android_device_files[].

אם לא משתמשים ב-android_device_dirs[] וב-android_device_files[], אפשר להגדיר את NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS ואת NO_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, בהתאמה. מערכת ה-build מחפשת את android_filesystem_config.h המותאם אישית ב-$(TARGET_DEVICE_DIR), שבו נמצא 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 כדי להוסיף תמיכה ב-wake lock בספרייה device/vendor/device. חשוב לזכור:

  • כל רשומה ב-structure היא המצב, uid,‏ gid, היכולות והשם. הקטע system/core/include/private/android_filesystem_config.h נכלל באופן אוטומטי כדי לספק את ההגדרות של #defines במניפסט (AID_ROOT, ‏ AID_SHELL,‏ CAP_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 file system
+** 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.
  • כדי לעבור אל device/vendor/device/android_filesystem_config.h, נדרשים עותקים של ההסתעפות הפרטית של יצרן המכשיר של system/core/include/private/android_filesystem_config.h עם תוכן נוסף ביעדים קיימים.
  • שומרת לעצמה את הזכות להחיל אמצעי בקרה חובה על גישה (MAC) של SELinux על קובצי תצורה במערכת היעד. הטמעות שכוללות קובצי הפעלה מותאמים אישית של יעד באמצעות fs_config() חייבות להבטיח גישה.