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

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

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

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

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

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

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

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

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

#define AID_SYSTEM 1000

הופך ל:

  • שם שקל להבין: מערכת
  • uid: 1000
  • gid: 1000

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

הגדרת מזהי AID

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

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

הגדרת הקטע 'מכסימום הוצאות'

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

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

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

מדור ערך הגדרה
[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_ בהתחלה. מותר להשתמש באותיות רישיות וקטנות. הכתוביות יכולות להיות גם: הנתונים הגולמיים:
  • בינארי (0b0101)
  • אוקטלי (0455)
  • ‫int (42)
  • הקסדצימלי (0xFF)
כדי להפריד בין כמה אותיות רישיות, משתמשים ברווחים.

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

הגדרת הקטע 'המלצות לשיפור'

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

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

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

<name> חייב להתחיל בשם של מחיצה כדי למנוע התנגשות עם מקורות שונים.
value <number> מחרוזת מספרים בסגנון C (הקסדצימלי, אוקטלי, בינארי ודצימלי).

זו שגיאה לציין כמה קטעים עם אותו ערך של אפשרות.

צריך לציין את אפשרויות הערכים בטווח שמתאים למחיצה שבה נעשה שימוש ב-<name>. רשימת המחיצות התקפות והטווחים התואמים שלהן מוגדרת ב-system/core/libcutils/include/private/android_filesystem_config.h. האפשרויות הן:
  • Vendor Partition
    • ‫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)
  • Product Partition
    • ‫AID_PRODUCT_RESERVED_START(7000) - AID_PRODUCT_RESERVED_END(7499)
  • System_ext Partition
    • ‫AID_SYSTEM_EXT_RESERVED_START(7500) - AID_SYSTEM_EXT_RESERVED_END(7999)

דוגמאות לשימוש אפשר למצוא במאמרים הגדרת שמות של מזהי OEM AID ושימוש במזהי OEM AID.

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

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

הגדרת שמות של מזהי אפליקציות 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)

כדי להשתמש במזהה 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. לדוגמה:

  • בפקודה 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 בפועל של יצרן הציוד המקורי. אפשר להשתמש בארגומנטים של מחרוזות לא מספריות עבור משתמש וקבוצה, כלומר, "vendor_foo" במקום "2901".

המרת מזהי AID לשמות שקל להבין

ב-Android 8.x, כדי להשתמש ב-מזהי OEM, היה צריך להשתמש ב-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 כדי להוסיף תמיכה בחסימת מצב שינה בספרייה device/vendor/device. חשוב לזכור:

  • כל רשומה במבנה היא המצב, ה-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.
  • נדרשים עותקים פרטיים של הסניף של יצרן המכשיר של system/core/include/private/android_filesystem_config.h עם תוכן נוסף ביעדים קיימים כדי לעבור אל device/vendor/device/android_filesystem_config.h.
  • שומרת לעצמה את הזכות להחיל בקרת גישה מחייבת (MAC) של SELinux על קובצי הגדרה במערכת היעד. בהטמעות שכוללות קובצי הפעלה מותאמים אישית של היעד באמצעות fs_config(), צריך לוודא שיש גישה.