סקודו

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

Scudo הוא יותר מקל מאשר גלאי שגיאות זיכרון מלא כמו AddressSanitizer (ASan) .

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

באנדרואיד 10, היה צורך להפעיל את scudo על בסיס בינארי על ידי הגדרת האפשרות LOCAL_SANITIZE := scudo scudo בקובץ .mk או את ה- sanitize: { scudo: true, } בקובץ .bp.

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 במיוחד עבור Scudo. במקום זאת, ודא שבדיקות 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 .