במאמר הסבר על דוחות HWASan מוסבר איך לקרוא קריסות של HWASan.
AddressSanitizer (HWASan) הוא כלי לזיהוי שגיאות בזיכרון, בדומה ל-AddressSanitizer. ב-HWASan נעשה שימוש בפחות זיכרון RAM בהשוואה ל-ASAN, ולכן הוא מתאים לניקוי של כל המערכת. התכונה HWASan זמינה רק ב-Android מגרסה 10 ואילך, ורק בחומרה מסוג AArch64.
הכלי שימושי בעיקר לקוד C/C++, אבל הוא יכול גם לעזור בניפוי באגים בקוד Java שגורם לקריסות ב-C/C++ שמשמש להטמעת ממשקי Java. הכלי הזה שימושי כי הוא מזהה שגיאות בזיכרון בזמן שהן מתרחשות, ומפנה ישירות לקוד שאחראי להן.
אפשר להטמיע קובצי אימג' של HWASan שנוצרו מראש במכשירי Pixel נתמכים מ-ci.android.com (הוראות מפורטות להגדרה).
בהשוואה לאלן הקלאסי, יש ל-HWASan:
- תקורה דומה של המעבד (CPU) (כ-2x)
- יתרת קוד דומה (40-50%)
- עלות אחסון קטנה בהרבה ב-RAM (10% עד 35%)
HWASan מזהה את אותה קבוצת באגים כמו ASan:
- זליגה/חוסר מקום במאגרים של סטאק ושל אשכול
- שימוש בערימה (heap) אחרי 'free'
- שימוש ב-Stack מחוץ להיקף
- Double free/wild free
בנוסף, HWASan מזהה שימוש ב-stack אחרי החזרה.
HWASan (כמו ASan) תואם ל-UBSan, ניתן להפעיל את שניהם ביעד מסוים בו-זמנית.
פרטי הטמעה והגבלות
HWASan מבוסס על הגישה של תיוג זיכרון, שבה ערך תג אקראי קטן משויך גם למצביעים וגם לטווח של כתובות זיכרון. כדי שגישה לזיכרון תהיה חוקית, צריך שיהיו התאמה בין התגים של הסמן לבין תגי הזיכרון. HWASan מסתמך על התכונה ARMv8 top byte ignore (TBI), שנקראת גם תיוג כתובות וירטואליות, כדי לאחסן את תג המצביע בביטים הגבוהים ביותר של הכתובת.
תוכלו לקרוא מידע נוסף על העיצוב של HWASan באתר התיעוד של Clang.
מעצם הגדרתו, ל-HWAsan אין אזורי סכנה בגודל מוגבל כמו ב-ASan לזיהוי זליגות, או מקום מוגבל בבידוד כמו ב-ASan לזיהוי שימוש לאחר תקופת הניסיון. לכן, HWASan יכול לזהות באג לא משנה כמה גדולה החריגה או כמה זמן חלף מאז שהזיכרון הוקצה מחדש. ל-HWASan יש יתרון גדול על פני ASan.
עם זאת, ל-HWASan יש מספר מוגבל של ערכי תגים אפשריים (256), כלומר יש 0.4% סיכוי לפספס באג במהלך הפעלה אחת של התוכנית.
הדרישות
גרסאות עדכניות (4.14 ומעלה) של הליבה המשותפת של Android תומכות ב-HWASan המקורי. ההסתעפויות הספציפיות ל-Android 10 לא תומכות ב-HWASan.
התמיכה במרחב המשתמש ב-HWASan זמינה החל מ-Android 11.
אם אתם עובדים עם ליבה אחרת, HWASan מחייב את ליבה של Linux לקבל מצביעים מתויגים בארגומנטים של קריאות מערכת. תמיכה בכך הוטמעה ב-patchsets הבאים ב-upstream:
- ABI של כתובת מתויגת של Arm64
- arm64: ביטול תיוג של מצביעי משתמש שמועברים לליבה
- mm: Avoid creating virtual address aliases in brk()/mmap()/mremap()
- arm64: אימות כתובות מתויגות ב-access_ok() שנקראות משרשורי ליבה
אם אתם מבצעים פיתוח באמצעות ערכת כלים מותאמת אישית, חשוב לוודא שהיא כוללת את כל השינויים עד ל-commit של LLVM c336557f.
שימוש ב-HWASan
כדי ליצור את כל הפלטפורמה באמצעות HWASan, משתמשים בפקודות הבאות:
lunch aosp_walleye-userdebug # (or any other product)
export SANITIZE_TARGET=hwaddress
m -j
לנוחות, אפשר להוסיף את ההגדרה SANITIZE_TARGET להגדרת מוצר, בדומה להגדרה aosp_coral_hwasan.
משתמשים שמכירים את AddressSanitizer לא צריכים להתמודד עם הרבה מהמורכבות של ה-build:
- אין צורך להריץ את make פעמיים.
- פיתוחים מצטברים עובדים באופן עצמאי.
- אין צורך לבצע איפוס נתוני המשתמש.
חלק מההגבלות של AddressSanitizer נעלמו גם הן:
- יש תמיכה בקובצי הפעלה סטטיים.
- מותר לוותר על חיטוי עבור כל יעד מלבד libc. בשונה מ-ASan, אין דרישה שאם ספרייה עוברת חיטוי, היא חייבת להיות גם בקובץ הפעלה שמקשר אליה.
אפשר לעבור בקלות בין קובצי אימג' של HWASan לבין קובצי אימג' רגילים עם אותו מספר build (או מספר build גבוה יותר). אין צורך לאפס את נתוני המכשיר.
כדי לדלג על ניטרול של מודול, משתמשים ב-LOCAL_NOSANITIZE := hwaddress
(Android.mk) או ב-sanitize: { hwaddress: false }
(Android.bp).
טיהור יעדים ספציפיים
אפשר להפעיל את HWASan לכל יעד ב-build רגיל (ללא סניטיזציה), כל עוד גם libc.so
עובר סניטיזציה. מוסיפים את hwaddress: true
לבלוק הטיהור ב-"libc_defaults"
ב-bionic/libc/Android.bp. לאחר מכן, מבצעים את אותה פעולה ביעד שבו אתם עובדים.
חשוב לדעת שטיהור libc מאפשר תיוג של הקצאות זיכרון ב-heap ברמת המערכת, וגם בדיקה של התגים לפעולות זיכרון בתוך libc.so
. כך אפשר לזהות באגים גם בקובצי בינארי שלא הופעל בהם HWASan, אם הגישה השגויה לזיכרון נמצאת ב-libc.so
(למשל: pthread_mutex_unlock()
על מנעול משולב (mutex) delete()
).
אם הפלטפורמה כולה נוצרה באמצעות HWASan, אין צורך לשנות קובצי build.
Flashstation
למטרות פיתוח, אפשר להשתמש ב-Flashstation כדי להריץ אימג' של AOSP עם תמיכה ב-HWAsan במכשיר Pixel עם מרכז האתחול (bootloader) פתוח. בוחרים את היעד _hwasan, למשל aosp_flame_hwasan-userdebug. למידע נוסף, תוכלו לעיין במסמכי התיעוד של NDK בנושא HWASan למפתחי אפליקציות.
מעקבי ערימה משופרים
HWASan משתמש ב-unwinder מהיר שמבוסס על מצביע מסגרת כדי לתעד מעקב סטאק לכל אירוע הקצאה וביטול הקצאה של זיכרון בתוכנית. ב-Android אפשר להשתמש בסמנים של פריימים בקוד AArch64 כברירת מחדל,
כך שהשיטה הזו עובדת מצוין. אם אתם צריכים לבצע ביטול של קוד מנוהל, צריך להגדיר את HWASAN_OPTIONS=fast_unwind_on_malloc=0
בסביבת התהליך. הערה: נתוני מעקב של סטאק גישה לזיכרון שגוי משתמשים ב-unwinder 'איטי' כברירת מחדל. ההגדרה הזו משפיעה רק על נתוני מעקב של הקצאה וביטול הקצאה. האפשרות הזו עשויה להיות מאוד תובענית על המעבד, בהתאם לעומס.
ייצוג
מידע נוסף זמין בקטע סמלים במאמר 'הסבר על דוחות HWASan'.
HWASan באפליקציות
בדומה ל- AddressSanitizer, ל-HWASan אין אפשרות לראות את קוד Java, אבל הוא יכול לזהות באגים בספריות JNI. עד Android 14, לא הייתה תמיכה בהפעלת אפליקציות HWASan במכשיר שאינו HWASan.
במכשיר HWASan, אפשר לבדוק אפליקציות באמצעות HWASan על ידי בניית הקוד שלהן באמצעות SANITIZE_TARGET:=hwaddress
ב-Make, או -fsanitize=hwaddress
בדגלי מהדר.
במכשיר שאינו HWASan (עם Android מגרסה 14 ואילך), צריך להוסיף הגדרה של קובץ wrap.sh
LD_HWASAN=1
.
פרטים נוספים זמינים במסמכי התיעוד למפתחי אפליקציות.