כשכלי HWASan מזהה באג בזיכרון, התהליך מסתיים באמצעות abort()
, ומדפיס דוח ב-stderr וב-logcat. כמו כל קריסות קוד מקורי ב-Android, שגיאות HWASan מופיעות ב-/data/tombstones
.
דוח לדוגמה
בהשוואה לקריסות רגילות של קוד נייטיב, ב-HWAsan יש מידע נוסף בשדה Abort message בחלק העליון של סטטוס ה-tombstone. לפניכם דוגמה לקריסה מבוססת-ערימת זיכרון. בהערה מוסבר מה עושים במקרה של באגים ב-stack.
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** Build fingerprint: 'google/flame_hwasan/flame:Tiramisu/MASTER/7956676:userdebug/dev-keys' Revision: 'DVT1.0' ABI: 'arm64' Timestamp: 2019-04-24 01:13:22+0000 pid: 11154, tid: 11154, name: sensors@1.0-ser >>> /vendor/bin/hw/android.hardware.sensors@1.0-service <<< signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr -------- Abort message: '==9569==ERROR: HWAddressSanitizer: tag-mismatch on address 0x00433ae20045 at pc 0x00623ae2a9cc READ of size 1 at 0x00433ae20045 tags: 5b/83 (ptr/mem) in thread T0 #0 0x7240450c68 (/system/lib64/vndk-sp-R/libcutils.so+0x8c68) #1 0x723dffd490 (/vendor/lib64/sensors.ssc.so+0x34490) #2 0x723e0126e0 (/vendor/lib64/sensors.ssc.so+0x496e0) [...] [0x00433ae20040,0x00433ae20060) is a small unallocated heap chunk; size: 32 offset: 5 Cause: use-after-free 0x00433ae20045 is located 5 bytes inside of 10-byte region [0x00433ae20040,0x00433ae2004a) freed by thread T0 here: #0 0x72404d1b18 (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0x10b18) #1 0x723af23040 (/vendor/lib64/libgralloccore.so+0x5040) #2 0x723af23fa4 (/vendor/lib64/libgralloccore.so+0x5fa4) [...] previously allocated here: #0 0x72404ce554 (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0xd554) #1 0x7240115654 (/apex/com.android.runtime/lib64/bionic/libc.so+0x43654) #2 0x7240450ac8 (/system/lib64/vndk-sp-R/libcutils.so+0x8ac8) [...] hwasan_dev_note_heap_rb_distance: 1 1023 hwasan_dev_note_num_matching_addrs: 0 hwasan_dev_note_num_matching_addrs_4b: 0 Thread: T0 0x006a00002000 stack: [0x007fc1064000,0x007fc1864000) sz: 8388608 tls: [0x00737702ffc0,0x007377033000) Memory tags around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1f90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae1ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x006f33ae2000: 08 00 08 00 [83] 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x006f33ae2080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Tags for short granules around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1ff0: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. =>0x006f33ae2000: 72 .. d0 .. [..] .. .. .. .. .. .. .. .. .. .. .. 0x006f33ae2010: .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags Registers where the failure occurred (pc 0x00623ae2a9cc): x0 0000007fc18623ec x1 5b0000433ae20045 x2 0000000000000013 x3 ffffffffffffffff x4 ffffffffffffffff x5 0000007fc1861da3 x6 6f7420676e696f47 x7 45522061206f6420 x8 0000000000000000 x9 0200006b00000000 x10 00000007fc18623f x11 5b0000433ae20040 x12 6f64206f7420676e x13 0a44414552206120 x14 0000000000000010 x15 ffffffffffffffff x16 000000737169ac94 x17 0000000000000007 x18 0000007377bd8000 x19 0000007fc1862498 x20 0200006b00000000 x21 0000007fc18624a8 x22 0000000000000001 x23 0000000000000000 x24 0000000000000000 x25 0000000000000000 x26 0000000000000000 x27 0000000000000000 x28 0000000000000000 x29 0000007fc1862410 x30 000000623ae2a9d0 sp 0000007fc18623d0 SUMMARY: HWAddressSanitizer: tag-mismatch (/system/lib64/vndk-sp-R/libcutils.so+0x8c68) [ … regular crash dump follows …]
הדוח הזה דומה לדוח של AddressSanitizer. בניגוד לשגיאות האלה, כמעט כל הבאגים ב-HWAsan הם שגיאות של אי-התאמה בין תגים, כלומר גישה לזיכרון שבה תג של מצביע לא תואם לתג הזיכרון התואם. יכול להיות שמדובר באחד מהפרטים הבאים:
- גישה מחוץ למגבלות ב-stack או ב-heap
- שגיאת שימוש לאחר שחרור בערימה
- שגיאת שימוש לאחר חזרה ב-stack
קטעים
בהמשך מוסבר על כל אחד מהקטעים בדוח HWASan.
שגיאת גישה
מכיל מידע על הגישה השגויה לזיכרון, כולל:
- סוג הגישה (
READ
לעומתWRITE
) - גודל הגישה (כמה בייטים ניסו לגשת אליהם)
- מספר השרשור של הגישה
- תגי מצביע וזיכרון (לניפוי באגים מתקדם)
גישה למעקב אחר סטאק
ניתוח סטאק של הגישה השגויה לזיכרון. מידע נוסף זמין במאמר סמליזציה.
הסיבה
הסיבה האפשרית לגישה לקויה. אם יש כמה מועמדים, הם מפורטים לפי הסדר של הסבירות היורדת. מופיע לפני המידע המפורט על הסיבה האפשרית. בעזרת HWASan אפשר לאבחן את הגורמים הבאים:
- שימוש אחרי תקופת הניסיון בחינם
- אי-התאמה של תגים ב-Stack, שיכולה להיות שימוש ב-Stack אחרי חזרה, שימוש ב-Stack אחרי היקף או שימוש מחוץ למגבלות
- זליגת נתונים במאגר הנתונים הזמני של אשכול
- Overflow גלובלי
מידע על הזיכרון
תיאור של מה ש-HWASan יודע על הזיכרון שאליו מתבצעת הגישה, והוא עשוי להשתנות בהתאם לסוג הבאג:
סוג הבאג | הסיבה | פורמט הדוח |
---|---|---|
אי התאמה בין תגים | שימוש אחרי תקופת הניסיון בחינם | יש להשתמש בפורמט הדוח הזה:<address> is located N bytes inside of M-byte region [<start>, <end>) freed by thread T0 here: |
זליגת נתונים במאגר הנתונים הזמני של אשכול | שימו לב שזו יכולה להיות גם זרימה נמוכה מדי.<address> is located N bytes to the right of M-byte region [<start>, <end>) allocated here: |
|
חוסר התאמה בתגים של סטאק | בדוחות Stack אין הבחנה בין שגיאות של זליגת נתונים (overflow) או מחסור בנתונים (underflow) לבין באגים מסוג שימוש לאחר חזרה (use-after-return). בנוסף, כדי למצוא את הקצאת ה-stack שמקורת השגיאה, נדרש שלב של סימון אופליין. הסבר על דוחות סטאק | |
Invalid free | שימוש אחרי תקופת הניסיון בחינם | באג של 'שחרור כפול'. אם זה קורה בזמן סגירת התהליך, יכול להיות שמדובר בהפרת ODR.
<address> is located N bytes inside of M-byte region [<start>, <end>) freed by thread T0 here: |
לא ניתן לתאר את הכתובת | זיכרון ששוחרר ללא צורך (זיכרון שלא הוקצה בעבר), או שחרור כפול של זיכרון אחרי שהזיכרון שהוקצה הוצא מהמאגר הפנוי של HWASan. | |
0x… הוא זיכרון צל של HWAsan | זיכרון פנוי לא ידוע, כי האפליקציה ניסתה לפנות זיכרון פנימי של HWASan. |
Deallocation stack trace
מעקב לאחור (stack trace) של המיקום שבו הוקצה הזיכרון. האפשרות הזו מוצגת רק עבור באגים מסוג use-after-free או invalid-free. מידע נוסף זמין במאמר סמליזציה.
דוח קריסות של מקבץ הקצאות
מעקב אחר סטאק של המיקום שבו הוקצה הזיכרון. מידע נוסף זמין במאמר סמליזציה.
מידע מתקדם על ניפוי באגים
הדוח HWASan כולל גם מידע מתקדם על ניפוי באגים, כולל (בסדר):
- רשימת השרשור בתהליך
- רשימת השרשור בתהליך
- הערך של תגי הזיכרון ליד הזיכרון הפגום
- הדמפ של הרשומות בנקודת הגישה לזיכרון
גרסת dump של תג זיכרון
אפשר להשתמש ב-dump של זיכרון התג כדי לחפש הקצאות זיכרון בקרבת מקום עם אותו תג כמו תג הסמן. התגים האלה יכולים להצביע על גישה מחוץ לתחום עם סטייה גדולה. תג אחד תואם ל-16 בייטים של זיכרון. תג ההפניה הוא 8 הביטים העליונים של הכתובת. נתוני הדמפ של זיכרון התגים יכולים לספק רמזים. לדוגמה, הנתונים הבאים הם זליגת נתונים ממאגר (buffer overflow) שמופיעה בצד שמאל:
tags: ad/5c (ptr/mem) [...] Memory tags around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1ff0: 0e 0e 0e 57 20 20 20 20 20 2e 5e 5e 5e 5e 5e b5 =>0x006f33ae2000: f6 f6 f6 f6 f6 4c ad ad ad ad ad ad [5c] 5c 5c 5c 0x006f33ae2010: 5c 04 2e 2e 2e 2e 2e 2f 66 66 66 66 66 80 6a 6a Tags for short granules around the buggy address (one tag corresponds to 16 bytes): 0x006f33ae1ff0: ab 52 eb .. .. .. .. .. .. .. .. .. .. .. .. .. =>0x006f33ae2000: .. .. .. .. .. .. .. .. .. .. .. .. [..] .. .. .. 0x006f33ae2010: .. 5c .. .. .. .. .. .. .. .. .. .. .. .. .. ..
שימו לב לרצף של 6 × 16 = 96 בייטים של תגי ad
שמשמאל ותואמים לתג המצביע.
אם הגודל של ההקצאה הוא לא כפולה של 16, היתרה של הגודל מאוחסנת בתור תג זיכרון והתג מאוחסן בתור תג גרגיר קצר. בדוגמה הקודמת, אחרי ההקצאה המודגשת בכתב מודגש עם התג ad
, יש הקצאה של 84 בייטים לתג 5c
: 5 × 16 + 4 = 84.
תג זיכרון אפס (לדוגמה, tags: ad/00 (ptr/mem)
) מציין באג של שימוש ב-stack אחרי חזרה.
קובץ dump של הרישום
הדוח של יצירת תמונת המצב של הרישום בדוחות HWASan תואם להוראה שביצעה את הגישה לזיכרון הלא חוקית. אחרי הדמפ הזה מופיע דמפ נוסף של הרישום מהטיפול הרגיל באותות ב-Android. מתעלמים מהאשפה השנייה, כי היא נוצרה כשהתרחשה קריאה ל-HWASan abort()
והיא לא רלוונטית לבאג.
סימבוליזציה
כדי לקבל שמות של פונקציות ומספרי שורות בנתוני מעקב ה-stack (ולקבל שמות של משתנים עבור באגים מסוג 'שימוש אחרי היקף'), צריך לבצע שלב של סימון אופליין.
הגדרה בפעם הראשונה: התקנה של llvm-symbolizer
לדוגמה, צריך להתקין את llvm-symbolizer
במערכת ולאפשר גישה אליו דרך $PATH
. ב-Debian, אפשר להתקין אותו באמצעות sudo apt install llvm
.
קבלת קובצי סמלים
כדי ליצור סמלים, אנחנו דורשים קובצי בינארי לא מדוללים שמכילים סמלים. המיקום שלהם תלוי בסוג ה-build:
- בגרסאות build מקומיות, קובצי הסמלים נמצאים בתיקייה
out/target/product/<product>/symbols/
. - בגרסאות build של AOSP (לדוגמה, גרסאות build שעברן הפעלה באמצעות Android Flash Tool), הגרסאות האלה נמצאות ב-Android CI. בArtifacts של ה-build יש קובץ
${PRODUCT}-symbols-${BUILDID}.zip
. - לגרסאות build פנימיות מהארגון, כדאי לעיין במסמכים של הארגון כדי לקבל עזרה בקבלת קובצי סמלים.
סימבוליזציה
hwasan_symbolize --symbols <DECOMPRESSED_DIR>/out/target/product/*/symbols < crash
הסבר על דוחות סטאק
באגים שמתרחשים במשתני סטאק מופיעים בדוח HWASan עם פרטים כמו:
Cause: stack tag-mismatch Address 0x007d4d251e80 is located in stack of thread T64 Thread: T64 0x0074000b2000 stack: [0x007d4d14c000,0x007d4d255cb0) sz: 1088688 tls: [0x007d4d255fc0,0x007d4d259000) Previously allocated frames: record_addr:0x7df7300c98 record:0x51ef007df3f70fb0 (/apex/com.android.art/lib64/libart.so+0x570fb0) record_addr:0x7df7300c90 record:0x5200007df3cdab74 (/apex/com.android.art/lib64/libart.so+0x2dab74) [...]
כדי לעזור לכם להבין באגים ב-stack, HWASan עוקב אחרי מסגרות stack קודמות. המערכת של HWASan לא ממירה אותם לתוכן שאנשים יכולים להבין בדוח הבאג, ולכן נדרש שלב סמליזציה נוסף.
הפרות של ODR
חלק מהבאגים מסוג 'שימוש לאחר שחרור' שדווחו על ידי HWASan עשויים להצביע על הפרה של כלל One Definition Rule (ODR). הפרה של ODR מתרחשת כאשר אותו משתנה מוגדר כמה פעמים באותה תוכנית. המשמעות היא גם שהמשתנה נהרס כמה פעמים, דבר שעלול להוביל לשגיאה מסוג use-after-free.
אחרי הסימולציה, הפרות של ODR מוצגות כשגיאה מסוג 'שימוש לאחר שחרור' עם __cxa_finalize
, גם ב-stack של הגישה הלא חוקית וגם ב-stack של freed here. הערך __dl__ZN6soinfo17call_constructorsEv
נמצא ב-stack שוקצה כאן, והוא אמור להצביע על המיקום בתוכנית שבו המשתנה מוגדר, גבוה יותר ב-stack.
אפשר להפר את ה-ODR אם משתמשים בספריות סטטיות. אם ספרייה סטטית שמגדירה משתנה גלובלי ב-C++ מקושרת לכמה ספריות משותפות או לקבצים להפעלה, יכול להיות שיהיו כמה הגדרות של אותו סמל באותו מרחב כתובות, וכתוצאה מכך תופיע שגיאת ODR.
פתרון בעיות
בקטע הזה מתוארות כמה שגיאות ומוסבר איך לטפל בהן.
ל-HWAddressSanitizer אין אפשרות לתאר את הכתובת בפירוט רב יותר
לפעמים יכול להיות שייגמר מקום ב-HWASan למידע על הקצאות זיכרון קודמות. במקרה כזה, הדוח מכיל רק מעקב סטאק אחד לגישה המיידית לזיכרון, ואחריו הערה:
HWAddressSanitizer can not describe address in more detail.
במקרים מסוימים, אפשר לפתור את הבעיה על ידי הפעלת הבדיקה כמה פעמים. אפשרות נוספת היא להגדיל את גודל ההיסטוריה של HWASan. אפשר לעשות זאת באופן גלובלי ב-build/soong/cc/sanitize.go
(מחפשים את hwasanGlobalOptions
) או בסביבת התהליך (אפשר לנסות את adb shell echo $HWASAN_OPTIONS
כדי לראות את ההגדרות הנוכחיות).
השגיאה הזו יכולה לקרות גם אם הזיכרון שאליו מתבצעת הגישה לא ממופה, או אם הוא הוקצה על ידי מנהל זיכרון שלא מודע ל-HWASan. במקרה כזה, התג mem
שמופיע בכותרת של תאונה הוא בדרך כלל 00
. אם יש לכם גישה למצבת הקבר המלאה, כדאי לעיין בדמפ של מפות הזיכרון כדי לברר לאיזה מיפוי (אם יש כזה) שייכת הכתובת.
באג בתצוגת עץ באותו שרשור
המשמעות היא שהיה באג במהלך יצירת דוח הקריסה של HWASan. בדרך כלל הסיבה לכך היא באג בסביבת זמן הריצה של HWASan. שליחת דיווח על באג עם הוראות לשחזור הבעיה, אם אפשר.