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 מהספריות הסטטיות שבהן הם תלויים.