חומרי חיטוי של LLVM

LLVM, תשתית המהדר המשמשת לבניית אנדרואיד, מכילה מספר רכיבים המבצעים ניתוח סטטי ודינמי. מבין הרכיבים הללו, ניתן להשתמש בחומרי החיטוי - במיוחד AddressSanitizer ו-UndefinedBehaviorSanitizer - לניתוח אנדרואיד. חומרי חיטוי הם רכיבי מכשור מבוססי מהדר הכלולים ב-rt חיצוני/קומפילר שניתן להשתמש בהם במהלך הפיתוח והבדיקה כדי לדחוף באגים ולהפוך את אנדרואיד לטוב יותר. מערך חומרי החיטוי הנוכחי של אנדרואיד יכול לגלות ולאבחן באגים רבים של שימוש לרעה בזיכרון והתנהגות בלתי מוגדרת שעלולה להיות מסוכנת.

השיטה המומלצת עבור רכיבי אנדרואיד לאתחל ולהפעיל עם מכשירי חיטוי מופעלים, כגון AddressSanitizer ו-UndefinedBehaviorSanitizer. דף זה מציג את AddressSanitizer, UndefinedBehaviorSanitizer ו-KernelAddressSanitizer, מראה כיצד ניתן להשתמש בהם בתוך מערכת ה-Build של Android, ונותן קבצי Android.mk ו-Android.bp לדוגמה הבונים רכיבים מקוריים כאשר חומרי החיטוי הללו מופעלים.

AddressSnitizer

AddressSanitizer (ASan) היא יכולת מכשור מבוסס מהדר המזהה סוגים רבים של שגיאות זיכרון בקוד C/C++ בזמן ריצה. ASan יכול לזהות סוגים רבים של שגיאות זיכרון, כולל:

  • גישה לזיכרון מחוץ לתחום
  • כפול חינם
  • שימוש-ללא לאחר

אנדרואיד מאפשרת מכשור ASan ברמת הבנייה המלאה ורמת האפליקציה עם asanwrapper.

AddressSanitizer משלב מכשור של כל קריאות הפונקציות הקשורות לזיכרון - כולל alloca, malloc ו-free - וריפוד כל המשתנים ואזורי הזיכרון שהוקצו עם זיכרון שמפעיל התקשרות חוזרת של ASan כאשר הוא נקרא או נכתב אליו.

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

pixel-xl:/ # sanitizer-status                                                                                            
=================================================================
==14164==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x0032000054b0 at pc 0x005df16ffc3c bp 0x007fc236fdf0 sp 0x007fc236fdd0
WRITE of size 1 at 0x0032000054b0 thread T0
    #0 0x5df16ffc3b in test_crash_malloc sanitizer-status/sanitizer-status.c:36:13
    #1 0x5df17004e3 in main sanitizer-status/sanitizer-status.c:76:7
    #2 0x794cf665f3 in __libc_init (/system/lib64/libc.so+0x1b5f3)
    #3 0x5df16ffa53 in do_arm64_start (/system/bin/sanitizer-status+0xa53)

0x0032000054b0 is located 0 bytes to the right of 32-byte region [0x003200005490,0x0032000054b0)
allocated by thread T0 here:
    #0 0x794d0bdc67 in malloc (/system/lib64/libclang_rt.asan-aarch64-android.so+0x74c67)
    #1 0x5df16ffb47 in test_crash_malloc sanitizer-status/sanitizer-status.c:34:25
    #2 0x5df17004e3 in main sanitizer-status/sanitizer-status.c:76:7
    #3 0x794cf665f3 in __libc_init (/system/lib64/libc.so+0x1b5f3)
    #4 0x5df16ffa53 in do_arm64_start (/system/bin/sanitizer-status+0xa53)
    #5 0x794df78893  (<unknown module>)

SUMMARY: AddressSanitizer: heap-buffer-overflow sanitizer-status/sanitizer-status.c:36:13 in test_crash_malloc

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

כדי לוודא ש-ASAN מתפקד במכשיר יעד, אנדרואיד כללה את קובץ ההפעלה asan_test. קובץ ההפעלה asan_test בודק ומאמת את פונקציונליות ה-ASAN במכשיר יעד, נותן הודעות אבחון עם הסטטוס של כל בדיקה. בעת שימוש ב-ASAN Android build, הוא ממוקם ב- /data/nativetest/asan_test/asan_test או /data/nativetest64/asan_test/asan_test כברירת מחדל.

UndefinedBehavior Sanitizer

UndefinedBehaviorSanitizer (UBSan) מבצע מכשור בזמן הידור כדי לבדוק סוגים שונים של התנהגות לא מוגדרת. בעוד ש-UBSan מסוגלת לזהות התנהגויות לא מוגדרות רבות , אנדרואיד תומכת ביישור, bool, bounds, enum, float-cast-overflow, float-divide-ab-0, float-divide-ab-0, integer-divide-ab-0, nonnull-attribute, null, return, מחזירה-nonnull-attribute, shift-base, shift-exponent, signed-great-overflow, unreachable, unsigned-getal-overflow, ו-vla-bound. unsigned-integer-overflow, על אף שאינה התנהגות לא מוגדרת מבחינה טכנית, נכלל בחומר החיטוי ומשמש במודולים רבים של אנדרואיד, כולל רכיבי שרת המדיה, כדי לחסל כל פגיעות סמויה של הצפת מספרים שלמים.

יישום

במערכת הבנייה של אנדרואיד, אתה יכול להפעיל את UBSan באופן גלובלי או מקומי. כדי להפעיל את UBSan ברחבי העולם, הגדר את SANITIZE_TARGET ב-Android.mk. כדי להפעיל את UBSan ברמת כל מודול, הגדר את LOCAL_SANITIZE וציין את ההתנהגויות הלא מוגדרות שברצונך לחפש ב-Android.mk. לדוגמה:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_CFLAGS := -std=c11 -Wall -Werror -O0

LOCAL_SRC_FILES:= sanitizer-status.c

LOCAL_MODULE:= sanitizer-status

LOCAL_SANITIZE := alignment bounds null unreachable integer
LOCAL_SANITIZE_DIAG := alignment bounds null unreachable integer

include $(BUILD_EXECUTABLE)

מערכת הבנייה של אנדרואיד עדיין לא תומכת באבחון מפורט בקבצי שרטוט כמו בקבצי makefile. הנה המקבילה הקרובה ביותר שנכתבה כשרטוט (Android.bp):

cc_binary {

    cflags: [
        "-std=c11",
        "-Wall",
        "-Werror",
        "-O0",
    ],

    srcs: ["sanitizer-status.c"],

    name: "sanitizer-status",

    sanitize: {
        misc_undefined: [
            "alignment",
            "bounds",
            "null",
            "unreachable",
            "integer",
        ],
        diag: {
            undefined : true
        },
    },

}

קיצורי דרך של UBSan

לאנדרואיד יש גם שני קיצורי דרך, integer default-ub , כדי לאפשר קבוצה של חומרי חיטוי בו-זמנית. מספר שלם מאפשר integer-divide-by-zero , signed-integer-overflow unsigned-integer-overflow . default-ub מאפשרת את הבדיקות שיש להן בעיות ביצועי מהדר מינימליות: bool, מספר שלם-חלק באפס, return, returns-nonnull-attribute, shift-exponent, unreachable ו-vla-bound. ניתן להשתמש במחלקת חיטוי המספרים השלמים עם SANITIZE_TARGET ו-LOCAL_SANITIZE, בעוד שניתן להשתמש ברירת המחדל-ub רק עם SANITIZE_TARGET.

דיווח שגיאות טוב יותר

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

LOCAL_SANITIZE:=integer
LOCAL_SANITIZE_DIAG:=integer

הערך LOCAL_SANITIZE מאפשר את החיטוי במהלך הבנייה. LOCAL_SANITIZE_DIAG מפעיל את מצב האבחון עבור חומר החיטוי שצוין. אפשר להגדיר את LOCAL_SANITIZE ו-LOCAL_SANITIZE_DIAG לערכים שונים, אך רק בדיקות אלו ב-LOCAL_SANITIZE מופעלות. אם בדיקה לא צוינה ב-LOCAL_SANITIZE, אך היא מצוינת ב-LOCAL_SANITIZE_DIAG, הסימון לא מופעל ולא ניתנות הודעות אבחון.

להלן דוגמה למידע המסופק על ידי ספריית זמן הריצה של UBSan:

pixel-xl:/ # sanitizer-status ubsan
sanitizer-status/sanitizer-status.c:53:6: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'size_t' (aka 'unsigned long')

חיטוי כתובת ליבה

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

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

בדומה ל-ASAN, KASAN משתמשת בשילוב של מכשור פונקציית זיכרון בזמן הידור וזיכרון צל כדי לעקוב אחר גישה לזיכרון בזמן ריצה. ב-KASAN, שמינית משטח זיכרון הליבה מוקדשת לזיכרון צל, מה שקובע אם גישה לזיכרון חוקית או לא.

KASAN נתמך בארכיטקטורות x86_64 ו-arm64. זה היה חלק מהקרנל במעלה הזרם מאז 4.0, ועבר חזרה לגרעין מבוסס אנדרואיד 3.18. KASAN נבדקה על גרעיני אנדרואיד שהורכבו עם gcc על בסיס 4.9.2.

בנוסף ל-KASAN, kcov הוא שינוי גרעין נוסף שמועיל לבדיקה. kcov פותחה כדי לאפשר בדיקת fuzz מונחית כיסוי בקרנל. הוא מודד את הכיסוי במונחים של כניסות של סיסמאות והוא שימושי עם מערכות מטושטשות, כגון syzkaller .

יישום

כדי להרכיב ליבה עם KASAN ו-kcov מופעלים, הוסף את דגלי הבנייה הבאים לתצורת בניית הליבה שלך:

CONFIG_KASAN 
CONFIG_KASAN_INLINE 
CONFIG_TEST_KASAN 
CONFIG_KCOV 
CONFIG_SLUB 
CONFIG_SLUB_DEBUG 
CONFIG_CC_OPTIMIZE_FOR_SIZE

ומסירים את הדברים הבאים:

CONFIG_SLUB_DEBUG_ON 
CONFIG_SLUB_DEBUG_PANIC_ON 
CONFIG_KASAN_OUTLINE 
CONFIG_KERNEL_LZ4

לאחר מכן בנה והבזק את הקרנל שלך כרגיל. ליבת KASAN גדולה בהרבה מהמקור. אם רלוונטי, שנה את כל פרמטרי האתחול והגדרות של טוען האתחול כדי לקחת זאת בחשבון.

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

...
[    0.000000] c0      0 Virtual kernel memory layout:
[    0.000000] c0      0     kasan   : 0xffffff8000000000 - 0xffffff9000000000   (    64 GB)
[    0.000000] c0      0     vmalloc : 0xffffff9000010000 - 0xffffffbdbfff0000   (   182 GB)
[    0.000000] c0      0     vmemmap : 0xffffffbdc0000000 - 0xffffffbfc0000000   (     8 GB maximum)
[    0.000000] c0      0               0xffffffbdc0000000 - 0xffffffbdc3f95400   (    63 MB actual)
[    0.000000] c0      0     PCI I/O : 0xffffffbffa000000 - 0xffffffbffb000000   (    16 MB)
[    0.000000] c0      0     fixed   : 0xffffffbffbdfd000 - 0xffffffbffbdff000   (     8 KB)
[    0.000000] c0      0     modules : 0xffffffbffc000000 - 0xffffffc000000000   (    64 MB)
[    0.000000] c0      0     memory  : 0xffffffc000000000 - 0xffffffc0fe550000   (  4069 MB)
[    0.000000] c0      0       .init : 0xffffffc001d33000 - 0xffffffc001dce000   (   620 KB)
[    0.000000] c0      0       .text : 0xffffffc000080000 - 0xffffffc001d32284   ( 29385 KB)
...

וכך ייראה באג:

[   18.539668] c3      1 ==================================================================
[   18.547662] c3      1 BUG: KASAN: null-ptr-deref on address 0000000000000008
[   18.554689] c3      1 Read of size 8 by task swapper/0/1
[   18.559988] c3      1 CPU: 3 PID: 1 Comm: swapper/0 Tainted: G        W      3.18.24-xxx #1
[   18.569275] c3      1 Hardware name: Android Device
[   18.577433] c3      1 Call trace:
[   18.580739] c3      1 [<ffffffc00008b32c>] dump_backtrace+0x0/0x2c4
[   18.586985] c3      1 [<ffffffc00008b600>] show_stack+0x10/0x1c
[   18.592889] c3      1 [<ffffffc001481194>] dump_stack+0x74/0xc8
[   18.598792] c3      1 [<ffffffc000202ee0>] kasan_report+0x11c/0x4d0
[   18.605038] c3      1 [<ffffffc00020286c>] __asan_load8+0x20/0x80
[   18.611115] c3      1 [<ffffffc000bdefe8>] android_verity_ctr+0x8cc/0x1024
[   18.617976] c3      1 [<ffffffc000bcaa2c>] dm_table_add_target+0x3dc/0x50c
[   18.624832] c3      1 [<ffffffc001bdbe60>] dm_run_setup+0x50c/0x678
[   18.631082] c3      1 [<ffffffc001bda8c0>] prepare_namespace+0x44/0x1ac
[   18.637676] c3      1 [<ffffffc001bda170>] kernel_init_freeable+0x328/0x364
[   18.644625] c3      1 [<ffffffc001478e20>] kernel_init+0x10/0xd8
[   18.650613] c3      1 ==================================================================

בנוסף, אם מודולים מופעלים בקרנל שלך, אתה יכול לטעון את מודול ליבת test_kasan לבדיקות נוספות. המודול מנסה גישה לזיכרון מחוץ לתחום ושימוש-ללא-אחרי והוא שימושי בבדיקת KASAN על התקן יעד.