AddressSnitizer

AddressSanitizer (ASan) הוא כלי מהיר מבוסס מהדר לאיתור באגי זיכרון בקוד מקורי.

ASan מזהה:

  • הצפת מאגר מחסנית וערימה
  • שימוש בערימה לאחר חינם
  • שימוש בערימה מחוץ לטווח
  • כפול חופשי/חופשי פרא

ASan פועל על ARM של 32 סיביות ו-64 סיביות, בתוספת x86 ו-x86-64. תקרת המעבד של ASan היא בערך פי 2, תקורה בגודל הקוד היא בין 50% לפי 2, ותקורת זיכרון גדולה (תלוי בדפוסי ההקצאה שלך, אבל בסדר גודל של פי 2).

אנדרואיד 10 והענף הראשי של AOSP ב-AArch64 תומכים ב-ASan (HWASan) מואצת בחומרה , כלי דומה עם תקורה נמוכה יותר של זיכרון RAM ומגוון גדול יותר של באגים שזוהו. HWASan מזהה שימוש בערימה לאחר ההחזרה, בנוסף לבאגים שזוהו על ידי ASan.

ל-HWASan יש תקורה בגודל מעבד וקוד דומים, אך תקורה קטנה בהרבה של זיכרון RAM (15%). HWASan אינו דטרמיניסטי. ישנם רק 256 ערכי תג אפשריים, כך שיש סבירות אחידה של 0.4% להחמצת באג כלשהו. ל-HWASan אין את האזורים האדומים בגודל מוגבל של ASan לזיהוי הצפות והסגר בקיבולת מוגבלת לזיהוי שימוש-לאחר-חופשי, כך שאין זה משנה ל-HWASan כמה גדול ההצפה או לפני כמה זמן הוקצו הזיכרון. זה הופך את HWASan לטוב יותר מ-ASan. תוכל לקרוא עוד על העיצוב של HWASan או על השימוש ב- HWASan באנדרואיד .

ASan מזהה הצפות מחסניות/גלובליות בנוסף להצפת ערימות, והיא מהירה עם תקורה מינימלית של זיכרון.

מסמך זה מתאר כיצד לבנות ולהפעיל חלקים/כל אנדרואיד עם ASan. אם אתה בונה אפליקציית SDK/NDK עם ASan, ראה במקום חיטוי כתובת .

חיטוי קובצי הפעלה בודדים עם ASan

הוסף LOCAL_SANITIZE:=address או sanitize: { address: true } לכלל הבנייה של קובץ ההפעלה. אתה יכול לחפש בקוד דוגמאות קיימות או למצוא את חומרי החיטוי הזמינים האחרים.

כאשר מתגלה באג, ASan מדפיסה דוח מילולי הן לפלט הסטנדרטי והן ל- logcat ולאחר מכן קורסת את התהליך.

חיטוי ספריות משותפות עם ASan

בשל האופן שבו ASan עובד, ספרייה שנבנתה עם ASan יכולה לשמש רק קובץ הפעלה שנבנה עם ASan.

כדי לחטא ספרייה משותפת שנמצאת בשימוש במספר קובצי הפעלה, שלא כולם בנויים עם ASan, אתה צריך שני עותקים של הספרייה. הדרך המומלצת לעשות זאת היא להוסיף את הדברים הבאים ל- Android.mk עבור המודול המדובר:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

זה מכניס את הספרייה ל- /system/lib/asan במקום /system/lib . לאחר מכן, הפעל את קובץ ההפעלה שלך עם:

LD_LIBRARY_PATH=/system/lib/asan

עבור דמוני מערכת, הוסף את הדברים הבאים לקטע המתאים של /init.rc או /init.$device$.rc .

setenv LD_LIBRARY_PATH /system/lib/asan

ודא שהתהליך משתמש בספריות מ- /system/lib/asan כשהוא קיים על ידי קריאת /proc/$PID/maps . אם לא, ייתכן שיהיה עליך להשבית את SELinux:

adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID
# if it is a system service, or may be adb shell stop; adb shell start.

עקבות מחסנית טובים יותר

ASan משתמש ב-Unwinder מהיר המבוסס על מצביעי מסגרת כדי להקליט עקבות מחסנית עבור כל הקצאת זיכרון ואירוע ביטול הקצאה בתוכנית. רוב האנדרואיד בנוי ללא מצביעי מסגרת. כתוצאה מכך, לעתים קרובות אתה מקבל רק פריימים משמעותיים אחד או שניים. כדי לתקן זאת, בנה מחדש את הספרייה עם ASan (מומלץ!), או עם:

LOCAL_CFLAGS:=-fno-omit-frame-pointer
LOCAL_ARM_MODE:=arm

או הגדר ASAN_OPTIONS=fast_unwind_on_malloc=0 בסביבת התהליך. האחרון יכול להיות מאוד אינטנסיבי במעבד, תלוי בעומס.

סימבוליזציה

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

  • ודא שהקובץ הבינארי llvm-symbolizer קיים ב- /system/bin . llvm-symbolizer בנוי ממקורות ב- third_party/llvm/tools/llvm-symbolizer .
  • סנן את הדוח באמצעות התסריט external/compiler-rt/lib/asan/scripts/symbolize.py .

הגישה השנייה יכולה לספק יותר נתונים (כלומר, מיקומי file:line ) בגלל הזמינות של ספריות מסומלות על המארח.

ASan באפליקציות

ASan לא יכול לראות לתוך קוד Java, אבל הוא יכול לזהות באגים בספריות JNI. לשם כך, אתה צריך לבנות את קובץ ההפעלה עם ASan, שבמקרה זה הוא /system/bin/app_process( 32|64 ) . זה מאפשר ASan בכל האפליקציות במכשיר בו זמנית, שזה עומס כבד, אבל מכשיר עם 2 GB RAM אמור להיות מסוגל להתמודד עם זה.

הוסף את LOCAL_SANITIZE:=address לכלל הבנייה app_process ב- frameworks/base/cmds/app_process . התעלם מהיעד app_process__asan באותו קובץ לעת עתה (אם הוא עדיין שם בזמן שאתה קורא את זה).

ערוך את קטע service zygote של קובץ system/core/rootdir/init.zygote( 32|64 ).rc המתאים כדי להוסיף את השורות הבאות לבלוק השורות המוזחות המכילות class main , שהוזחו גם הן באותה כמות:

    setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib
    setenv ASAN_OPTIONS allow_user_segv_handler=true

בנה, סינכרון adb, אתחול פלאש מהיר ואתחול מחדש.

שימוש במאפיין לעטוף

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

ניתן לעשות זאת על ידי הפעלת האפליקציה שלך עם wrap. תכונה. הדוגמה הבאה מפעילה את אפליקציית Gmail תחת ASan:

adb root
adb shell setenforce 0  # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"

בהקשר זה, asanwrapper משכתב את /system/bin/app_process ל- /system/bin/asan/app_process , אשר נבנה עם ASan. זה גם מוסיף /system/lib/asan בתחילת נתיב החיפוש הדינמי של הספרייה. בדרך זו ספריות המכונות ASan מ- /system/lib/asan מועדפות על פני ספריות רגילות ב- /system/lib כאשר הן פועלות עם asanwrapper .

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

SANITIZE_TARGET

אנדרואיד 7.0 ומעלה כולל תמיכה בבניית כל פלטפורמת האנדרואיד עם ASan בבת אחת. (אם אתה בונה מהדורה גבוהה יותר מאנדרואיד 9, HWASan היא בחירה טובה יותר.)

הפעל את הפקודות הבאות באותו עץ בנייה.

make -j42
SANITIZE_TARGET=address make -j42

במצב זה, userdata.img מכיל ספריות נוספות ויש להברב אותו גם למכשיר. השתמש בשורת הפקודה הבאה:

fastboot flash userdata && fastboot flashall

זה בונה שתי קבוצות של ספריות משותפות: רגיל ב- /system/lib (הזמנת ה-make הראשונה), ו-ASan-מכשיר ב- /data/asan/lib (הזמנת ה-make השנייה). קובצי הפעלה מה-build השני מחליפים את אלו מה-build הראשון. קובצי הפעלה המכילים ASan מקבלים נתיב חיפוש אחר בספריה הכולל /data/asan/lib לפני /system/lib באמצעות /system/bin/linker_asan ב- PT_INTERP .

מערכת הבנייה אוספת ספריות אובייקט ביניים כאשר הערך $SANITIZE_TARGET השתנה. זה מאלץ בנייה מחדש של כל היעדים תוך שמירה על קבצים בינאריים מותקנים תחת /system/lib .

לא ניתן לבנות כמה יעדים עם ASan:

  • קובצי הפעלה מקושרים סטטית
  • LOCAL_CLANG:=false
  • LOCAL_SANITIZE:=false עבור SANITIZE_TARGET=address

קובצי הפעלה כמו אלה מדלגים ב- SANITIZE_TARGET build, והגרסה מהפעלת ה-make הראשונה נשארת ב- /system/bin .

ספריות כאלה בנויות ללא ASan. הם יכולים להכיל קוד ASan מהספריות הסטטיות שבהן הם תלויים.

מסמכים תומכים