במאמר הסבר על דוחות של HWASan מוסבר איך לקרוא קריסות של HWASan.
AddressSanitizer (HWASan) עם תמיכה בחומרה הוא כלי לזיהוי שגיאות בזיכרון, בדומה ל-AddressSanitizer. HWASan משתמש בהרבה פחות RAM בהשוואה ל-ASan, ולכן הוא מתאים לניקוי של המערכת כולה. HWASan זמין רק ב-Android מגרסה 10 ומעלה, ורק בחומרת AArch64.
למרות ש-HWASan שימושי בעיקר לקוד C/C++, הוא יכול לעזור גם בניפוי באגים בקוד Java שגורם לקריסות ב-C/C++ שמשמש להטמעה של ממשקי Java. הוא שימושי כי הוא מאתר שגיאות בזיכרון כשהן קורות, ומפנה אתכם ישירות לקוד שאחראי לשגיאה.
בהשוואה ל-ASan הקלאסי, ל-HWASan יש:
- תקורה דומה של CPU (~2x)
- תקורה דומה של גודל הקוד (40-50%)
- תקורה נמוכה בהרבה של RAM (10% עד 35%)
HWASan מזהה את אותה קבוצת באגים כמו ASan:
- גלישה על גדות הזיכרון (overflow) או חוסר בזיכרון (underflow) במאגרים של מחסנית וערימה
- שימוש בערימה אחרי שחרור
- שימוש ב-Stack מחוץ להיקף
- שחרור כפול של זיכרון/שחרור זיכרון לא מנוהל
בנוסף, HWASan מזהה שימוש במחסנית אחרי החזרה.
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 מחוץ לקופסה. אין תמיכה ב-HWASan בענפים ספציפיים של Android 10.
התמיכה ב-HWASan במרחב המשתמש זמינה החל מ-Android 11.
אם אתם עובדים עם ליבה אחרת, כדי להשתמש ב-HWASan, ליבת Linux צריכה לקבל מצביעים מתויגים בארגומנטים של קריאות המערכת. התמיכה הזו הוטמעה בערכות התיקונים הבאות של upstream:
- ממשק ABI של כתובות מתויגות ב-arm64
- arm64: untag user pointers passed to the kernel
- 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, הרבה מהמורכבות של הבנייה נעלמת:
- אין צורך להריץ את הפקודה make פעמיים.
- גרסאות build מצטברות פועלות באופן אוטומטי.
- אין צורך להפעיל פלאש בנתוני המשתמש.
גם חלק מההגבלות של AddressSanitizer כבר לא קיימות:
- יש תמיכה בקבצים הפעלה סטטיים.
- אפשר לדלג על ניקוי של כל יעד מלבד libc. בניגוד ל-ASan, אין דרישה שאם ספרייה עוברת סניטציה, גם כל קובץ הפעלה שמקשר אליה יעבור סניטציה.
אפשר לעבור בין HWASan לבין תמונות רגילות באותו מספר build (או במספר גבוה יותר) באופן חופשי. אין צורך למחוק את המכשיר.
כדי לדלג על ניקוי של מודול, משתמשים ב-LOCAL_NOSANITIZE := hwaddress
(Android.mk) או ב-sanitize: { hwaddress: false }
(Android.bp).
ניקוי של יעדים בודדים
אפשר להפעיל את HWASan לכל יעד בנפרד בגרסה רגילה (לא מחוטאת), כל עוד גם libc.so
מחוטא. מוסיפים את hwaddress: true
לבלוק sanitize ב-"libc_defaults"
ב-bionic/libc/Android.bp. אחר כך חוזרים על הפעולה ביעד שעליו עובדים.
הערה: ניקוי של libc מאפשר תיוג של הקצאות זיכרון בערימה בכל המערכת, וגם בדיקה של התגים לפעולות זיכרון בתוך libc.so
. יכול להיות שהכלי יזהה באגים גם בקבצים בינאריים שלא הופעל בהם HWASan, אם הגישה הבעייתית לזיכרון היא ב-libc.so
(לדוגמה, pthread_mutex_unlock()
ב-delete()
ed mutex).
אין צורך לשנות קובצי build אם הפלטפורמה כולה בנויה באמצעות HWASan.
מעקבי ערימה משופרים
HWASan משתמש בכלי מהיר לביטול ההרשמה שמבוסס על מצביעי מסגרות כדי לתעד את מעקב המחסנית לכל אירוע של הקצאת זיכרון וביטול הקצאת זיכרון בתוכנית. ב-Android, מצביעים על מסגרות מופעלים בקוד AArch64 כברירת מחדל, ולכן זה עובד מצוין בפועל. אם אתם צריכים לבטל את הפעולה באמצעות קוד מנוהל, צריך להגדיר את HWASAN_OPTIONS=fast_unwind_on_malloc=0
בסביבת התהליך. הערה: מעקבים של גישה שגויה לזיכרון משתמשים ב-unwinder 'איטי' כברירת מחדל. ההגדרה הזו משפיעה רק על מעקבים של הקצאה וביטול הקצאה. האפשרות הזו יכולה להיות מאוד
אינטנסיבית מבחינת השימוש במעבד, בהתאם לעומס.
סימבוליזציה
מידע נוסף זמין בקטע סימבוליזציה במאמר בנושא הבנת דוחות HWASan.
HWASan באפליקציות
בדומה ל-AddressSanitizer, HWASan לא יכול לראות את קוד Java, אבל הוא יכול לזהות באגים בספריות JNI. עד Android 14, הפעלת אפליקציות של HWASan במכשיר שאינו HWASan לא נתמכה.
במכשיר עם HWASan, אפשר לבדוק אפליקציות באמצעות HWASan על ידי בניית הקוד שלהן עם ב-Make, או עם בדגלי קומפילציה.SANITIZE_TARGET:=hwaddress
-fsanitize=hwaddress
במכשיר שאין בו HWASan (עם Android מגרסה 14 ואילך), צריך להוסיף הגדרה לקובץ wrap.sh:
LD_HWASAN=1
מידע נוסף מופיע במסמכי התיעוד למפתחים.