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

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

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

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

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

הגדרת מזהי 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)
כדי להפריד בין כמה אותיות רישיות, משתמשים ברווחים.

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

הגדרת המדור 'המלצות מבוססות-AI'

הקטע 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)
  • חלוקת מוצרים
    • ‫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.

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

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

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

כדי להגדיר 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, כדי להשתמש במזהי AID של יצרני ציוד מקורי (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 לא רק מאפשרות קריאה בזמן ריצה של ספריות וקבצים, אלא שהמארח יכול להשתמש באותם קבצים בזמן הבנייה כדי ליצור תמונות של מערכת הקבצים כמו ${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 נכלל אוטומטית כדי לספק את פקודות ה-define במניפסט (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() חייבות להבטיח גישה.