במאמר הסבר על דוחות HWASan מוסבר איך לקרוא קריסות של HWASan.
AddressSanitizer (HWASan) בסיוע חומרה הוא כלי לזיהוי שגיאות בזיכרון, בדומה ל-AddressSanitizer. ב-HWASan נעשה שימוש בפחות זיכרון RAM בהשוואה ל-ASAN, ולכן הוא מתאים לניקוי של כל המערכת. HWASan זמין רק ב-Android מגרסה 10 ואילך, ורק בחומרה מסוג AArch64.
הכלי שימושי בעיקר לקוד C/C++, אבל הוא יכול גם לעזור בניפוי באגים בקוד Java שגורם לקריסות ב-C/C++ שמשמשים להטמעת ממשקי Java. הכלי הזה שימושי כי הוא מזהה שגיאות בזיכרון בזמן שהן מתרחשות, ומפנה ישירות לקוד שאחראי להן.
בהשוואה ל-ASan הקלאסי, ל-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 לקבל מצביע מתויג בארגומנטים של קריאה למערכת. התמיכה בכך הופעלה בחבילות התיקונים הבאות ב-upstream:
- arm64 tagged address ABI
- 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 פעמיים.
- גרסאות build מצטברות פועלות באופן מובנה.
- אין צורך לבצע איפוס נתוני המשתמש.
גם חלק מההגבלות של 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.
מעקבי ערימה משופרים
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 ואילך), צריך להוסיף את ההגדרה LD_HWASAN=1
לקובץ wrap.sh.
למידע נוסף, אפשר לעיין במסמכי התיעוד למפתחי אפליקציות.