הסבר על דוחות HWASan

כשכלי HWASan מזהה באג בזיכרון, התהליך מסתיים ב-abort(). הדוח מודפס ב-stderr וב-Logcat. כמו כל הקריסות המקוריות ב-Android, שגיאות HWASan עלולות נמצא תחת /data/tombstones.

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

דוח לדוגמה

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
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: '

[...]

[0x00433ae20040,0x00433ae20060) is a small unallocated heap chunk; size: 32 offset: 5








[ … regular crash dump follows …]

הפעולה הזו דומה מאוד לדוח AddressSanitizer. בניגוד אליהם, כמעט כל הבאגים של HWASan הם "tag-mismatch", כלומר גישה לזיכרון כאשר תג מצביע לא תואם לתג הזיכרון התואם. זה יכול להיות אחד מ-

  • גישה מחוץ לתחום במקבץ או בערימה
  • לשימוש אחרי בחינם בערימה
  • לשימוש אחרי ההחזרה על המקבץ

קטעים

בהמשך יש הסבר על כל אחד מהקטעים בדוח HWASan:

שגיאת גישה

מכיל מידע על גישה פגומה לזיכרון, כולל:

  • סוג הגישה ('READ' לעומת 'WRITE')
  • גודל הגישה (כמה בייטים בוצע ניסיון לגשת אליהם)
  • מספר ה-thread של הגישה
  • תגי מצביע וזיכרון (לניפוי באגים מתקדם)

גישה לדוח הקריסות

דוח קריסות של גישה גרועה לזיכרון. עיינו בקטע 'סמלים' כדי סימבולי.

הסיבה

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

  • שימוש אחרי שימוש בחינם
  • מחסנית tag-mismatch: זו יכולה להיות מחסנית use-after-return / use after-scope, או מחוץ לתחום
  • גלישת נתונים במאגר הנתונים הזמני
  • גלישה ברחבי העולם

מידע על הזיכרון

תיאור המידע ש-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:
חוסר התאמה בין תגים במקבץ בדוחות מקבץ אין הבחנה בין 'אפשרויות נוספות' / 'חסרים' ו- באגים שמשתמשים בהם אחרי החזרה. לחשבון נוסף לכך, כדי למצוא את הקצאת המחסנית שהיא מקור השגיאה, אופליין נדרש שלב סימולציית. הסבר על דוחות קריסות שבהמשך.
כלי חינמי לא תקף שימוש אחרי שימוש בחינם זהו באג כפול חינם. אם זה קורה כשמאפסים את התהליך, זה סימן לכך הפרה של ODR.
<address> is located N bytes inside of M-byte region [<start>, <end>)
  freed by thread T0 here:
לא ניתן לתאר את הכתובת בחינם (ללא זיכרון שלא הוקצה בעבר), או כפול חינם אחרי שהזיכרון שהוקצה הוצא מהמאגר החופשי של HWASan.
0x... הוא זיכרון הצל של HWAsan. האפליקציה ניסתה לפנות בחינם, ללא חשש זיכרון שהוא ל-HWASan.

דוח קריסות של מיקומים שרלוונטיים לעסק

דוח קריסות של המיקום שבו הזיכרון הוקצה. מוצג רק לשימוש לאחר שימוש ללא תשלום או באגים נטולי נתונים לא חוקיים. ראו קטע סמלים כדי לייצג סימולציה.

דוח קריסות של הקצאה

דוח קריסות של המקום שבו הוקצה הזיכרון. ראו קטע סמלים כדי לייצג סימולציה.

ניפוי באגים מתקדם מידע

דוח HWASan כולל גם כמה מידע מתקדם על תוצאות ניפוי הבאגים, כולל (לפי הסדר):

  1. רשימת השרשורים בתהליך
  2. רשימת השרשורים בתהליך
  3. הערך של תגי הזיכרון ליד הזיכרון שגורמת לבעיה
  4. תמונת ה-Dump של הרישום בנקודת הגישה לזיכרון

תמונת מצב של תג זיכרון

אפשר להשתמש בתיקיית הזיכרון של התג כדי לחפש הקצאות זיכרון בקרבת מקום עם אותו תג בתור מצביע התיוג. הגורמים האלה עלולים להוביל לגישה מחוץ לתחום עם היסט משמעותי. תג אחד תואם לערך 16 בייטים של הזיכרון; תג המצביע הוא 8 הביטים המובילים של הכתובת. תמונת מצב הזיכרון של התג לתת רמזים, עבור הדוגמה הבאה היא גלישה במאגר נתונים זמני מימין:

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 בייטים של תגי 'מודעה' בצד ימין שתואמים לתג המצביע).

אם גודל ההקצאה אינו כפולה של 16, יתרת הגודל תהיה מאוחסנים בתור תג הזיכרון והתג יישמרו כקובץ Shorts תג חלקיק. בדוגמה שלמעלה, מיד אחרי שההקצאה המודגשת תויגה אנחנו יש 5 × 16 + 4 = הקצאת 84 בייטים של תג 5c.

תג עם אפס זיכרון (לדוגמה: tags: ad/00 (ptr/mem)) בדרך כלל מציין באג-שימוש בסטאק אחרי החזרה.

רישום קובץ dump

תמונת המצב של רישום הנתונים בדוחות HWASan תואמת להוראה שביצעה בפועל לא תקין זיכרון גישה. אחריו מופיעה תמונת מצב אחרת של הרישום מ-handler הרגיל של Android - מתעלמים מ השני, הוא נלקח כאשר HWASan נקרא abort() והוא לא רלוונטי הבאג.

ייצוג

כדי לקבל שמות של פונקציות ומספרי שורות בדוחי קריסות (ולקבל שמות משתנים לשימוש אחרי ההיקף) באגים), נדרש שלב של סימולציית אופליין.

הגדרה בפעם הראשונה: התקנת llvm-symbolizer

כדי לסמל, המערכת צריכה להתקין את llvm-symbolizer ולוודא שאפשר לגשת אליו דרך $PATH. ב-Debian, אפשר מתקינים אותו באמצעות sudo apt install llvm.

קבלת קובצי סמלים

לצורך סימולזציה, אנחנו דורשים קבצים בינאריים לא מסולסלים שמכילים סמלים. המיקום שבו ניתן למצוא את המדדים האלה תלוי בסוג ה-build:

עבור גרסאות build מקומיות, ניתן למצוא את קובצי הסמלים out/target/product/<product>/symbols/.

עבור גרסאות build של AOSP (למשל, הבהוב מ-Flashstation), הפונקציה גרסאות build זמינות ב-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)
  [...]

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

הפרות ODR

חלק מהבאגים שאינם בשימוש לאחר השימוש שמדווחים על ידי HWASan יכולים גם להעיד על הפרה של כלל הגדרה אחת (ODR). הפרה של ODR מתרחשת כשאותו משתנה מוגדר כמה פעמים באותה תוכנית. כלומר, המשתנה מושמד כמה פעמים, וזה עלול להוביל שגיאת use-after-free.

לאחר הסימולציה, הפרות ODR מובילות למצב use-after-free עם __cxa_finalize, גם בסטאק הגישה הלא חוקית וגם במגש 'חינם' סטאק. הערכים הקודמים "הוקצו כאן" המקבץ מכיל __dl__ZN6soinfo17call_constructorsEv והוא צריך בנקודה שמגדירה את המשתנה במיקום גבוה יותר במקבץ.

אחת הסיבות להפרה של ה-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, יש לדווח על באג לספק הוראות לשחזור הבעיה, אם אפשר.