Scudo הוא מקצה זיכרון דינמי במצב משתמש, או מקצה ערימה , שנועד להיות עמיד בפני פגיעויות הקשורות לעימה (כגון גלישת חיץ מבוססת ערימה , שימוש לאחר פנוי ופנוי כפול ) תוך שמירה על ביצועים. הוא מספק את הפרימיטיבים הסטנדרטיים להקצאה והקצאה של C (כגון malloc ו-free), כמו גם את הפרימיטיבים C++ (כגון חדש ומחק).
Scudo הוא יותר מקל מאשר גלאי שגיאות זיכרון מלא כמו AddressSanitizer (ASan) .
מאז יציאת אנדרואיד 11, נעשה שימוש ב-scudo עבור כל הקוד המקורי (למעט במכשירים עם זיכרון נמוך, שבהם עדיין נעשה שימוש ב-jemalloc). בזמן הריצה, כל ההקצאות וההקצאות של ערימות מקוריות מטופלות על ידי Scudo עבור כל קובצי ההפעלה והתלות בספרייה שלהם, והתהליך מופסק אם מזוהה שחיתות או התנהגות חשודה בערימה.
Scudo הוא קוד פתוח וחלק מפרויקט המהדר-rt של LLVM. התיעוד זמין בכתובת https://llvm.org/docs/ScudoHardenedAllocator.html . זמן הריצה של Scudo נשלח כחלק משרשרת הכלים של אנדרואיד והתמיכה נוספה ל- Soong and Make כדי לאפשר הפעלה קלה של המקצה בבינארי.
אתה יכול להפעיל או לבטל את ההפחתה הנוספת בתוך המקצה באמצעות האפשרויות המתוארות להלן.
התאמה אישית
ניתן להגדיר כמה פרמטרים של המקצה על בסיס כל תהליך באמצעות מספר דרכים:
- באופן סטטי: הגדר פונקציה
__scudo_default_options
בתוכנית שמחזירה את מחרוזת האפשרויות לניתוח. לפונקציה זו חייב להיות אב הטיפוס הבא:extern "C" const char *__scudo_default_options()
. - באופן דינמי: השתמש במשתנה הסביבה
SCUDO_OPTIONS
המכיל את מחרוזת האפשרויות שיש לנתח. אפשרויות המוגדרות כך עוקפות כל הגדרה שנעשתה באמצעות__scudo_default_options
.
האפשרויות הבאות זמינות.
אוֹפְּצִיָה | ברירת מחדל של 64 סיביות | ברירת מחדל של 32 סיביות | תיאור |
---|---|---|---|
QuarantineSizeKb | 256 | 64 | גודל ההסגר (ב-KB) המשמש לעיכוב ההקצאה בפועל של נתחים. ערך נמוך יותר עשוי להפחית את השימוש בזיכרון אך להפחית את יעילות ההפחתה; ערך שלילי נופל בחזרה לברירות המחדל. הגדרה של זה וגם ThreadLocalQuarantineSizeKb לאפס משביתה את ההסגר לחלוטין. |
QuarantineChunksUpToSize | 2048 | 512 | הגודל (בבתים) שאליו ניתן להכניס נתחים להסגר. |
ThreadLocalQuarantineSizeKb | 64 | 16 | הגודל (ב-KB) של מטמון לכל חוט שמשתמשים בו כדי להוריד את ההסגר הגלובלי. ערך נמוך יותר עשוי להפחית את השימוש בזיכרון אך עשוי להגביר את המחלוקת על ההסגר העולמי. הגדרה של זה וגם QuarantineSizeKb לאפס משביתה את ההסגר לחלוטין. |
DeallocationTypeMismatch | false | false | מאפשר דיווח על שגיאות על malloc/מחק, חדש/חינם, חדש/מחק[] |
DeleteSizeMismatch | true | true | מאפשר דיווח על שגיאות על אי התאמה בין גדלים של חדש למחיקה. |
ZeroContents | false | false | מאפשר אפס תוכן נתח בהקצאה והקצאה. |
allocator_may_return_null | false | false | מציין שהמקצה יכול להחזיר null כאשר מתרחשת שגיאה הניתנת לשחזור, במקום לסיים את התהליך. |
hard_rss_limit_mb | 0 | 0 | כאשר ה-RSS של התהליך מגיע לגבול זה, התהליך מסתיים. |
soft_rss_limit_mb | 0 | 0 | כאשר ה-RSS של התהליך מגיע לגבול זה, הקצאות נוספות נכשלות או מחזירות null (בהתאם לערך של allocator_may_return_null ), עד שה-RSS יורד בחזרה כדי לאפשר הקצאות חדשות. |
allocator_release_to_os_interval_ms | לא | 5000 | משפיע רק על מקצה 64 סיביות. אם מוגדר, מנסה לשחרר זיכרון לא בשימוש למערכת ההפעלה, אך לא לעתים קרובות יותר מהמרווח הזה (במילישניות). אם הערך שלילי, הזיכרון לא משוחרר למערכת ההפעלה. |
abort_on_error | true | true | אם מוגדר, הכלי קורא abort() במקום _exit() לאחר הדפסת הודעת השגיאה. |
מַתַן תוֹקֵף
נכון לעכשיו, אין בדיקות CTS במיוחד עבור סקודו. במקום זאת, ודא שבדיקות CTS עוברות עם או בלי Scudo מופעל עבור בינארי נתון כדי לוודא שזה לא משפיע על המכשיר.
פתרון תקלות
אם מזוהה בעיה שאינה ניתנת לשחזור, המקצה מציג הודעת שגיאה לתיאור השגיאה הסטנדרטי ולאחר מכן מסיים את התהליך. עקבות מחסנית שמובילות לסיום מתווספות ביומן המערכת. הפלט מתחיל בדרך כלל ב- Scudo ERROR:
ואחריו סיכום קצר של הבעיה יחד עם מצביעים כלשהם.
להלן רשימה של הודעות השגיאה הנוכחיות והגורמים האפשריים שלהן:
-
corrupted chunk header
: אימות סכום הבדיקה של כותרת החלק נכשל. זה כנראה נובע מאחד משני דברים: הכותרת הוחלפה (חלקית או מלאה), או שהמצביע שהועבר לפונקציה אינו חלק. -
race on chunk header
: שני שרשורים שונים מנסים לתמרן את אותה כותרת בו-זמנית. זה בדרך כלל סימפטומטי של מצב מרוץ או חוסר נעילה כללי בעת ביצוע פעולות על הנתח הזה. -
invalid chunk state
: הנתח אינו במצב הצפוי לפעולה נתונה, לדוגמה, הוא לא מוקצה כאשר מנסים לשחרר אותו, או שהוא אינו בהסגר כאשר מנסים למחזר אותו. פנוי כפול הוא הסיבה האופיינית לשגיאה זו. -
misaligned pointer
: דרישות יישור בסיסיות נאכפות היטב: 8 בתים בפלטפורמות של 32 סיביות ו-16 בתים בפלטפורמות של 64 סיביות. אם מצביע המועבר לפונקציות שלנו אינו מתאים לאלה, המצביע המועבר לאחת הפונקציות אינו מיושר. -
allocation type mismatch
: כאשר אפשרות זו מופעלת, פונקציית ביטול הקצאה שנקראת על נתח צריכה להתאים לסוג הפונקציה שנקראה כדי להקצות אותה. סוג זה של חוסר התאמה עלול לגרום לבעיות אבטחה. -
invalid sized delete
: כאשר נעשה שימוש באופרטור המחיקה בגודל C++14, והבדיקה האופציונלית מופעלת, יש אי התאמה בין הגודל שהועבר בעת ביטול ההקצאה של נתח לבין הגודל שהתבקש בעת הקצאתו. זו בדרך כלל בעיית מהדר או בלבול סוג באובייקט המוקצה. -
RSS limit exhausted
: חריגה מה-RSS המקסימלי שצוין באופן אופציונלי.
אם אתה מבצע ניפוי באגים של קריסה במערכת ההפעלה עצמה, אתה יכול להשתמש ב- HWASan OS build . אם אתה מנקה באגים קריסה באפליקציה, אפשר להשתמש גם בבניית אפליקציה של HWASan .