הארכת תיוג זיכרון זרוע

Arm v9 מציגה Arm Memory Tagging Extension (MTE), מימוש חומרה של זיכרון מתויג.

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

באנדרואיד 12, מקצה הזיכרון של הליבה ומרחב המשתמש יכול להגדיל כל הקצאה עם מטא נתונים. זה עוזר לזהות באגים ללא שימוש וללא גלישה, שהם המקור הנפוץ ביותר לבאגי בטיחות בזיכרון בבסיסי הקוד שלנו.

מצבי הפעלה של MTE

ל-MTE שלושה מצבי פעולה:

  • מצב סינכרוני (SYNC)
  • מצב אסינכרוני (ASYNC)
  • מצב א-סימטרי (ASYMM)

מצב סינכרוני (SYNC)

מצב זה מותאם לנכונות זיהוי באגים על ביצועים וניתן להשתמש בו ככלי זיהוי באגים מדויק, כאשר תקורה של ביצועים גבוהים יותר מקובלת. כאשר מופעל, MTE SYNC פועל כאמצעי אבטחה. במקרה של חוסר התאמה בתג, המעבד מבטל את הביצוע באופן מיידי ומסיים את התהליך עם SIGSEGV (קוד SEGV_MTESERR ) ומידע מלא על הגישה לזיכרון והכתובת התקלה.

אנו ממליצים להשתמש במצב זה במהלך בדיקה כחלופה ל-HWASan/KASAN או בייצור כאשר תהליך היעד מייצג משטח התקפה פגיע. בנוסף, כאשר מצב ASYNC הצביע על נוכחות של באג, ניתן לקבל דוח באג מדויק על ידי שימוש בממשקי ה-API של זמן הריצה כדי להעביר את הביצוע למצב SYNC.

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

מצב אסינכרוני (ASYNC)

מצב זה מותאם לביצועים מעל לדיוק של דוחות באגים וניתן להשתמש בו כזיהוי תקורה נמוכה עבור באגי בטיחות בזיכרון.
במקרה של חוסר התאמה של תג, המעבד ממשיך בביצוע עד לכניסת הליבה הקרובה ביותר (לדוגמה, פסיקת מערכת הפעלה או טיימר), שם הוא מסיים את התהליך עם SIGSEGV (קוד SEGV_MTEAERR ) מבלי להקליט את הכתובת הפגומה או את הגישה לזיכרון.
אנו ממליצים להשתמש במצב זה בייצור על בסיסי קוד שנבדקו היטב שבהם ידוע כי צפיפות באגי הבטיחות בזיכרון נמוכה, דבר אשר מושג על ידי שימוש במצב SYNC במהלך הבדיקה.

מצב א-סימטרי (ASYMM)

תכונה נוספת ב-Arm v8.7-A, מצב MTE Asymmetric מספק בדיקה סינכרונית של קריאות זיכרון, ובדיקה אסינכרונית של כתיבה בזיכרון, עם ביצועים דומים לאלו של מצב ASYNC. ברוב המצבים, מצב זה מהווה שיפור לעומת מצב ASYNC, ואנו ממליצים להשתמש בו במקום ASYNC בכל פעם שהוא זמין.

מסיבה זו, אף אחד מממשקי ה-API המתוארים להלן לא מזכיר את המצב האסימטרי. במקום זאת, ניתן להגדיר את מערכת ההפעלה כך שתשתמש תמיד במצב אסימטרי כאשר מתבקש אסינכרוני. אנא עיין בסעיף "הגדרת רמת ה-MTE המועדפת הספציפית למעבד" לקבלת מידע נוסף.

MTE במרחב המשתמש

הסעיפים הבאים מתארים כיצד ניתן להפעיל MTE עבור תהליכי מערכת ויישומים. MTE מושבת כברירת מחדל, אלא אם אחת מהאפשרויות שלהלן מוגדרת עבור תהליך מסוים (ראה אילו רכיבים MTE מופעל להלן ).

הפעלת MTE באמצעות מערכת הבנייה

כמאפיין כלל תהליך, MTE נשלט על ידי הגדרת זמן הבנייה של קובץ ההפעלה הראשי. האפשרויות הבאות מאפשרות לשנות הגדרה זו עבור קובצי הפעלה בודדים, או עבור ספריות משנה שלמות בעץ המקור. מתעלמים מההגדרה בספריות, או בכל יעד שאינו בר הפעלה או בדיקה.

1. הפעלת MTE ב- Android.bp ( דוגמה ), עבור פרויקט מסוים:

מצב MTE הגדרה
MTE אסינכרוני
  sanitize: {
  memtag_heap: true,
  }
MTE סינכרוני
  sanitize: {
  memtag_heap: true,
  diag: {
  memtag_heap: true,
  },
  }

או ב- Android.mk:

מצב MTE הגדרה
Asynchronous MTE LOCAL_SANITIZE := memtag_heap
Synchronous MTE LOCAL_SANITIZE := memtag_heap
LOCAL_SANITIZE_DIAG := memtag_heap

2. הפעלת MTE בספריית משנה בעץ המקור באמצעות משתנה מוצר:

מצב MTE כלול רשימה אל תכלול רשימה
אסינכרון PRODUCT_MEMTAG_HEAP_ASYNC_INCLUDE_PATHS MEMTAG_HEAP_ASYNC_INCLUDE_PATHS PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
סינכרון PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS MEMTAG_HEAP_SYNC_INCLUDE_PATHS

אוֹ

מצב MTE הגדרה
MTE אסינכרוני MEMTAG_HEAP_ASYNC_INCLUDE_PATHS
MTE סינכרוני MEMTAG_HEAP_SYNC_INCLUDE_PATHS

או על ידי ציון נתיב אי הכללה של קובץ הפעלה:

מצב MTE הגדרה
MTE אסינכרוני PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS MEMTAG_HEAP_EXCLUDE_PATHS
MTE סינכרוני

דוגמה, (שימוש דומה ל- PRODUCT_CFI_INCLUDE_PATHS )

  PRODUCT_MEMTAG_HEAP_SYNC_INCLUDE_PATHS=vendor/$(vendor)
  PRODUCT_MEMTAG_HEAP_EXCLUDE_PATHS=vendor/$(vendor)/projectA \
                                    vendor/$(vendor)/projectB

הפעלת MTE באמצעות מאפייני מערכת

ניתן לעקוף את הגדרות הבנייה לעיל בזמן ריצה על ידי הגדרת מאפיין המערכת הבא:

arm64.memtag.process.<basename> = (off|sync|async)

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

לדוגמה, כדי להגדיר /system/bin/ping או /data/local/tmp/ping להשתמש ב-MTE אסינכרוני, השתמש adb shell setprop arm64.memtag.process.ping async .

הפעלת MTE באמצעות משתנה סביבה

דרך נוספת לעקוף את הגדרת הבנייה היא על ידי הגדרת משתנה הסביבה: MEMTAG_OPTIONS=(off|sync|async) אם מוגדרים גם משתנה הסביבה וגם מאפיין המערכת, המשתנה מקבל עדיפות.

הפעלת MTE עבור יישומים

אם לא צוין, MTE מושבת כברירת מחדל, אך אפליקציות שרוצות להשתמש ב-MTE יכולות לעשות זאת על ידי הגדרת android:memtagMode תחת התג <application> או <process> ב- AndroidManifest.xml .

android:memtagMode=(off|default|sync|async)

כאשר מוגדר בתג <application> , התכונה משפיעה על כל התהליכים המשמשים את האפליקציה, וניתן לעקוף אותה עבור תהליכים בודדים על ידי הגדרת התג <process> .

לצורך ניסוי, ניתן להשתמש בשינויי תאימות כדי להגדיר את ערך ברירת המחדל של תכונת memtagMode עבור יישום שאינו מציין ערך כלשהו במניפסט (או מציין default ).
ניתן למצוא אותם תחת System > Advanced > Developer options > App Compatibility Changes בתפריט ההגדרות הגלובלי. הגדרת NATIVE_MEMTAG_ASYNC או NATIVE_MEMTAG_SYNC מאפשרת MTE עבור יישום מסוים.
לחלופין, ניתן להגדיר זאת באמצעות הפקודה am באופן הבא:

$ adb shell am compat enable NATIVE_MEMTAG_[A]SYNC my.app.name

בניית תמונת מערכת MTE

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

אנו ממליצים בחום להפעיל MTE במצב סינכרוני בכל הקבצים הבינאריים המקוריים במהלך הפיתוח

SANITIZE_TARGET=memtag_heap SANITIZE_TARGET_DIAG=memtag_heap m

כמו בכל משתנה במערכת הבנייה, SANITIZE_TARGET יכול לשמש כמשתנה סביבה או כהגדרת make (לדוגמה, בקובץ product.mk ).
שים לב שזה מאפשר MTE עבור כל התהליכים המקוריים, אך לא עבור יישומים (שמחולקים מ- zygote64 ) שעבורם ניתן להפעיל MTE לפי ההוראות למעלה .

הגדרת רמת ה-MTE המועדפת הספציפית למעבד

בחלק מהמעבדים הביצועים של MTE במצבי ASYMM או אפילו SYNC עשויים להיות דומים לאלו של ASYNC. זה עושה את זה כדאי לאפשר בדיקות מחמירות יותר על אותם מעבדים כאשר מתבקש מצב בדיקה פחות קפדני, על מנת לזכות ביתרונות זיהוי השגיאות של הבדיקות המחמירות ללא חסרונות הביצועים.
כברירת מחדל, תהליכים שהוגדרו לפעול במצב ASYNC יפעלו במצב ASYNC בכל המעבדים. כדי להגדיר את הליבה להריץ תהליכים אלה במצב SYNC במעבדים ספציפיים, יש לכתוב את סינכרון הערך לערך sysfs /sys/devices/system/cpu/cpu<N>/mte_tcf_preferred בזמן האתחול. ניתן לעשות זאת עם סקריפט init. לדוגמה, כדי להגדיר מעבדים 0-1 להפעיל תהליכים במצב ASYNC במצב SYNC, ומעבדים 2-3 לשימוש בהפעלה במצב ASYMM, ניתן להוסיף את הדברים הבאים לסעיף init של סקריפט init של הספק:

  write /sys/devices/system/cpu/cpu0/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu1/mte_tcf_preferred sync
  write /sys/devices/system/cpu/cpu2/mte_tcf_preferred asymm
  write /sys/devices/system/cpu/cpu3/mte_tcf_preferred asymm

מצבות מתהליכי מצב ASYNC הפועלים במצב SYNC יכילו עקבות מחסנית מדויקת של מיקום שגיאת הזיכרון. עם זאת, הם לא יכללו מעקב אחר הקצאה או מחסנית. עקבות מחסנית אלו זמינות רק אם התהליך מוגדר לפעול במצב SYNC.

int mallopt(M_THREAD_DISABLE_MEM_INIT, level)

כאשר level היא 0 או 1.
משבית את אתחול הזיכרון ב-malloc, ונמנע משינוי תגי זיכרון אלא אם כן נחוץ לתקינות.

int mallopt(M_MEMTAG_TUNING, level)

איפה level היא:

  • M_MEMTAG_TUNING_BUFFER_OVERFLOW
  • M_MEMTAG_TUNING_UAF

בוחר אסטרטגיית הקצאת תגים.

  • הגדרת ברירת המחדל היא M_MEMTAG_TUNING_BUFFER_OVERFLOW .
  • M_MEMTAG_TUNING_BUFFER_OVERFLOW - מאפשר זיהוי דטרמיניסטי של באגים ליניאריים של גלישת מאגר ו-underflow על ידי הקצאת ערכי תג ברורים להקצאות סמוכות. למצב זה יש סיכוי מופחת מעט לזהות באגים לאחר שימוש ללא שימוש, מכיוון שרק מחצית מערכי התג האפשריים זמינים עבור כל מיקום זיכרון. אנא זכור ש-MTE אינו יכול לזהות גלישה בתוך אותו גרגיר תג (נתח מיושר של 16 בתים), ויכול לפספס הצפות קטנות אפילו במצב זה. הצפה כזו לא יכולה להיות הגורם לשחיתות בזיכרון, מכיוון שהזיכרון בתוך גרגיר אחד לעולם אינו משמש להקצאות מרובות.
  • M_MEMTAG_TUNING_UAF - מאפשר תגיות אקראית באופן עצמאי עבור הסתברות אחידה של ~93% לזיהוי באגים מרחביים (הצפת מאגר) וזמניים (שימוש לאחר חינמי).

בנוסף לממשקי ה-API שתוארו לעיל, משתמשים מנוסים עשויים לרצות להיות מודעים לנקודות הבאות:

  • הגדרת אוגר החומרה PSTATE.TCO יכולה לדכא זמנית את בדיקת התגים ( דוגמה ). לדוגמה, בעת העתקת טווח זיכרון עם תוכן תג לא ידוע, או טיפול בצוואר בקבוק ביצועים בלולאה חמה.
  • בעת שימוש M_HEAP_TAGGING_LEVEL_SYNC , מטפל התרסקות המערכת מספק מידע נוסף כגון מעקבי הקצאה וביטול הקצאה. פונקציונליות זו דורשת גישה לסיביות התג והיא מופעלת על ידי העברת הדגל SA_EXPOSE_TAGBITS בעת הגדרת המטפל באותות. כל תוכנית שמגדירה את מטפל האותות שלה ומאצילה קריסות לא ידועות למערכת אחת, מומלץ לעשות את אותו הדבר.

MTE בקרנל

כדי להפעיל את KASAN המואצת ב-MTE עבור הליבה, הגדר את הליבה עם CONFIG_KASAN=y , CONFIG_KASAN_HW_TAGS=y . הגדרות אלה מופעלות כברירת מחדל בליבת GKI, החל מ- Android 12-5.10 .
ניתן לשלוט בכך בזמן האתחול באמצעות הארגומנטים הבאים של שורת הפקודה:

  • kasan=[on|off] - הפעל או השבת את KASAN (ברירת מחדל: on )
  • kasan.mode=[sync |async ] - בחר בין מצב סינכרוני ואסינכרוני (ברירת מחדל: sync )
  • kasan.stacktrace=[on|off] - האם לאסוף עקבות מחסנית (ברירת מחדל: on )
    • איסוף עקבות מחסנית דורש גם stack_depot_disable=off .
  • kasan.fault=[report|panic] - האם להדפיס רק את הדוח, או גם להיבהל מהקרנל (ברירת מחדל: report ). ללא קשר לאפשרות זו, בדיקת התגים מושבתת לאחר השגיאה הראשונה שדווחה.

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

אנו ממליצים בחום להשתמש במצב ASYNC בייצור. זה מספק כלי תקורה נמוך לזיהוי נוכחותם של באגי בטיחות בזיכרון בתהליך, כמו גם הגנה מעמיקה נוספת. לאחר זיהוי באג, המפתח יכול למנף את ממשקי ה-API של זמן הריצה כדי לעבור למצב SYNC ולקבל עקבות מחסנית מדויקת מקבוצת משתמשים שנדגמה.

אנו ממליצים בחום להגדיר את רמת ה-MTE המועדפת הספציפית למעבד עבור ה-SoC. למצב Asymm יש בדרך כלל את אותם מאפייני ביצועים כמו ASYNC, והוא כמעט תמיד עדיף על פניו. ליבות קטנות לפי הסדר מציגות לעתים קרובות ביצועים דומים בכל שלושת המצבים, וניתן להגדיר אותן כך שיעדיפו SYNC.

מפתחים צריכים לבדוק את נוכחותן של קריסות על ידי בדיקת /data/tombstones , logcat או על ידי ניטור צינור הספק DropboxManager לאיתור באגים של משתמשי קצה. למידע נוסף על איתור באגים בקוד מקורי של Android, עיין במידע כאן .

רכיבי פלטפורמה התומכים ב-MTE

באנדרואיד 12, מספר רכיבי מערכת קריטיים לאבטחה משתמשים ב-MTE ASYNC כדי לזהות קריסות של משתמשי קצה ולפעול כשכבה נוספת של הגנה מעמיקה. רכיבים אלו הם:

  • דמוני רשת וכלי עזר (למעט netd )
  • Bluetooth, SecureElement, NFC HALs ויישומי מערכת
  • statsd daemon
  • system_server
  • zygote64 (כדי לאפשר ליישומים להצטרף לשימוש ב-MTE)

יעדים אלו נבחרו על סמך הקריטריונים הבאים:

  • תהליך מיוחס (מוגדר כתהליך שיש לו גישה למשהו שאין לדומיין unprivileged_app SELinux)
  • מעבד קלט לא אמין ( כלל שני )
  • האטה קבילה בביצועים (האטה לא יוצרת זמן אחזור גלוי למשתמש)

אנו מעודדים את הספקים לאפשר MTE בייצור עבור רכיבים נוספים, בהתאם לקריטריונים שהוזכרו לעיל. במהלך הפיתוח אנו ממליצים לבדוק את הרכיבים הללו באמצעות מצב SYNC, כדי לזהות באגים המתוקנים בקלות, ולהעריך את ההשפעה של ASYNC על הביצועים שלהם.
בעתיד, אנדרואיד מתכננת להרחיב את רשימת רכיבי המערכת שבהם MTE מופעל, בהנחיית מאפייני הביצועים של עיצובי החומרה הקרובים.