ShadowCallStack (SCS) הוא מצב של הוספת רכיבים ל-LLVM שמגן מפני מחיקה של כתובת ההחזרה (כמו זליגה של מאגר ה-stack) על ידי שמירת כתובת ההחזרה של פונקציה ב-ShadowCallStack שהוקצה בנפרד בתחילת הפונקציה של פונקציות שאינן פונקציות עלים, וטעינה של כתובת ההחזרה מ-ShadowCallStack בסוף הפונקציה. כתובת ההחזרה מאוחסנת גם בסטאק הרגיל לצורך תאימות ל-unwinders, אבל לא נעשה בה שימוש אחר. כך מתקפות שמשתנות את כתובת ההחזרה בסטאק הרגיל לא משפיעות על תהליך הבקרה של התוכנית.
ב-aarch64, התכונה משתמשת ברשומה x18
כדי להפנות ל-ShadowCallStack, כלומר אין צורך לאחסן את ההפניות ל-ShadowCallStack בזיכרון.
כך אפשר להטמיע סביבת זמן ריצה שלא חושפת את הכתובת של ShadowCallStack לתוקפים שיכולים לקרוא זיכרון שרירותי.
הטמעה
ב-Android יש תמיכה ב-ShadowCallStack גם בליבה וגם במרחב המשתמש.
הפעלת SCS בליבה
כדי להפעיל את ShadowCallStack בליבה, מוסיפים את השורה הבאה לקובץ התצורה של הליבה:
CONFIG_SHADOW_CALL_STACK=y
הפעלת SCS במרחב המשתמש
כדי להפעיל את ShadowCallStack ברכיבים של מרחב המשתמש, מוסיפים את השורות הבאות לקובץ התוכנית של הרכיב:
sanitize: { scs: true }
ב-SCS מניחים שהרשם x18
שמור לאחסון הכתובת של ShadowCallStack, ולא משמש למטרות אחרות. כל ספריות המערכת מתורגמות כדי להקצות את המרשם x18
, אבל יכול להיות שיהיו בעיות אם SCS מופעל לרכיבים במרחב המשתמש שמבצעים פעולות שיתוף פעולה עם קוד מדור קודם בתהליך (לדוגמה, ספריות שאפשר לטעון על ידי אפליקציות של צד שלישי), שעלול למחוק את המרשם x18
. לכן, מומלץ להפעיל את SCS רק ברכיבים עצמאיים שלא יוטמעו בקובצי בינארי מדור קודם.
אימות
אין בדיקת CTS ספציפית ל-SCS. במקום זאת, צריך לוודא שבדיקות CTS עוברות גם עם SCS מופעל וגם בלי SCS מופעל, כדי לוודא ש-SCS לא משפיע על המכשיר.