זיכרון הפעלה בלבד (XOM) עבור AArch64 בינאריים

קטעי קוד הניתנים להפעלה עבור קבצים בינאריים של מערכת AArch64 מסומנים כברירת מחדל לביצוע בלבד (לא ניתנים לקריאה) כאמצעי הקשחה מפני התקפות שימוש חוזר בקוד בדיוק בזמן. קוד שמערבב נתונים וקוד יחד וקוד שבודק בכוונה את הקטעים הללו (מבלי למפות מחדש את מקטעי הזיכרון כקריאים) אינם פועלים עוד. אפליקציות עם יעד SDK של 10 (רמת API 29 ומעלה) מושפעות אם האפליקציה מנסה לקרוא קטעי קוד של ספריות מערכת התומכות בזיכרון הפעלה בלבד (XOM) בזיכרון מבלי לסמן תחילה את הקטע כקריא.

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

יישום

AArch64 בינאריים שנוצרו על ידי המהדר מניחים שקוד ונתונים אינם מעורבים זה בזה. הפעלת תכונה זו אינה משפיעה לרעה על ביצועי המכשיר.

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

תמיכה והשפעה במכשיר

ייתכן שמכשירים עם חומרה מוקדמת יותר או גרעינים מוקדמים יותר (נמוכים מ-4.9) ללא התיקונים הנדרשים לא יתמכו באופן מלא או ייהנו מתכונה זו. התקנים ללא תמיכת ליבה עשויים שלא לאכוף גישה של משתמשים לזיכרון הפעלה בלבד, אולם קוד ליבה שבודק במפורש אם דף קריא עשוי עדיין לאכוף מאפיין זה, כגון process_vm_readv() .

יש להגדיר את דגל הליבה CONFIG_ARM64_UAO בליבה כדי להבטיח שהקרנל מכבד את דפי ארץ המשתמש המסומנים כ-execute-בלבד. מכשירי ARMv8 מוקדמים יותר, או התקני ARMv8.2 עם ביטול גישת משתמש (UAO) מושבת, עשויים שלא להפיק תועלת מלאה מכך וייתכן שעדיין יוכלו לקרוא דפי הפעלה בלבד באמצעות מערכות הפעלה.

שחזור קוד קיים

קוד שהועבר מ-AArch32 עשוי להכיל נתונים וקוד מעורבבים, מה שגורם לבעיות להתעורר. במקרים רבים, תיקון בעיות אלה הוא פשוט כמו העברת הקבועים למקטע .data בקובץ ה-assembly.

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

דוגמאות:

לקבצים בינאריים שנוצרו על ידי מהדר Clang לא יהיו בעיות עם שילוב של נתונים בקוד. אם כלול קוד שנוצר באוסף מהדרים של GNU (מספרייה סטטית), בדוק את הקובץ הבינארי של הפלט כדי לוודא שקבועים לא קובצו לקטעי קוד.

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

מפעיל

הפעלה בלבד מופעלת כברירת מחדל עבור כל הקבצים הבינאריים של 64 סיביות במערכת ה-build.

השבתה

אתה יכול להשבית את ההפעלה בלבד ברמת מודול, לפי עץ משנה שלם, או באופן גלובלי עבור מבנה שלם.

ניתן להשבית את XOM עבור מודולים בודדים שאינם ניתנים לשינוי מחדש, או שצריכים לקרוא את קוד ההפעלה שלהם, על ידי הגדרת המשתנים LOCAL_XOM ו- xom ל- false .

// Android.mk
LOCAL_XOM := false

// Android.bp
cc_binary { // or other module types
   ...
   xom: false,
}

אם זיכרון להפעלה בלבד מושבת בספרייה סטטית, מערכת הבנייה מיישמת זאת על כל המודולים התלויים של אותה ספרייה סטטית. אתה יכול לעקוף זאת באמצעות xom: true, .

כדי להשבית זיכרון לביצוע בלבד בספריית משנה מסוימת (לדוגמה, foo/bar/), העבר את הערך ל- XOM_EXCLUDE_PATHS .

make -j XOM_EXCLUDE_PATHS=foo/bar

לחלופין, תוכל להגדיר את המשתנה PRODUCT_XOM_EXCLUDE_PATHS בתצורת המוצר שלך.

אתה יכול להשבית קבצים בינאריים לביצוע בלבד באופן גלובלי על ידי העברת ENABLE_XOM=false לפקודת make שלך.

make -j ENABLE_XOM=false

מַתַן תוֹקֵף

אין בדיקות CTS או אימות זמינות עבור זיכרון להפעלה בלבד. אתה יכול לאמת קבצים בינאריים באופן ידני באמצעות readelf ובדיקת דגלי הפלחים.