น้ำยาฆ่าเชื้อ LLVM

LLVM ซึ่งเป็นโครงสร้างพื้นฐานของคอมไพเลอร์ที่ใช้ในการสร้าง Android ประกอบด้วยส่วนประกอบหลายอย่างที่ทำการวิเคราะห์แบบคงที่และแบบไดนามิก จากส่วนประกอบเหล่านี้น้ำยาฆ่าเชื้อโดยเฉพาะ AddressSanitizer และ UndefinedBehaviorSanitizer สามารถใช้วิเคราะห์ Android ได้อย่างครอบคลุม Sanitizers เป็นส่วนประกอบเครื่องมือที่ใช้คอมไพเลอร์ที่มีอยู่ในภายนอก / คอมไพเลอร์ -Rt ที่สามารถใช้ในระหว่างการพัฒนาและการทดสอบเพื่อผลักดันจุดบกพร่องและทำให้ Android ดีขึ้น ชุดน้ำยาฆ่าเชื้อในปัจจุบันของ Android สามารถค้นหาและวินิจฉัยจุดบกพร่องของการใช้หน่วยความจำในทางที่ผิดและพฤติกรรมที่ไม่ได้กำหนดที่อาจเป็นอันตรายได้

แนวทางปฏิบัติที่ดีที่สุดสำหรับรุ่น Android คือการบูตและรันโดยเปิดใช้งานน้ำยาฆ่าเชื้อเช่น AddressSanitizer และ UndefinedBehaviorSanitizer หน้านี้จะแนะนำ AddressSanitizer, UndefinedBehaviorSanitizer และ KernelAddressSanitizer แสดงวิธีการใช้งานภายในระบบสร้าง Android และให้ตัวอย่างไฟล์ Android.mk และ Android.bp ที่สร้างส่วนประกอบดั้งเดิมโดยเปิดใช้งานน้ำยาฆ่าเชื้อเหล่านี้

ที่อยู่

AddressSanitizer (ASan) คือความสามารถในการใช้เครื่องมือที่ใช้คอมไพเลอร์ซึ่งตรวจพบข้อผิดพลาดของหน่วยความจำหลายประเภทในรหัส C / C ++ ในขณะรันไทม์ ASan สามารถตรวจพบข้อผิดพลาดของหน่วยความจำหลายประเภท ได้แก่ :

  • การเข้าถึงหน่วยความจำนอกขอบเขต
  • ฟรีสองเท่า
  • ใช้หลังจากฟรี

Android อนุญาตให้ ใช้เครื่องมือ ASan ในระดับการสร้างเต็มรูปแบบและ ระดับแอป ด้วย asanwrapper

AddressSanitizer รวมเครื่องมือของการเรียกฟังก์ชันที่เกี่ยวข้องกับหน่วยความจำทั้งหมดเข้าด้วยกันรวมถึงการจัดสรร, malloc และฟรีและเพิ่มตัวแปรทั้งหมดและพื้นที่หน่วยความจำที่จัดสรรด้วยหน่วยความจำที่เรียกใช้การเรียกกลับ ASan เมื่อมีการอ่านหรือเขียน

เครื่องมือวัดช่วยให้ ASan ตรวจพบข้อบกพร่องในการใช้หน่วยความจำที่ไม่ถูกต้องซึ่งรวมถึงขอบเขตการใช้งานแบบ double-free และ use-after, return และ free ในขณะที่ memory-region padding ตรวจจับการอ่านหรือเขียนนอกขอบเขต หากเกิดการอ่านหรือเขียนไปยังพื้นที่ padding นี้ ASan จะตรวจจับและส่งออกข้อมูลเพื่อช่วยในการวินิจฉัยการละเมิดหน่วยความจำรวมถึง call stack, shadow memory map, ประเภทของการละเมิดหน่วยความจำ, สิ่งที่อ่านหรือเขียน, คำสั่งที่ทำให้เกิด การละเมิดและเนื้อหาหน่วยความจำ

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

บางครั้งกระบวนการค้นหาจุดบกพร่องอาจดูเหมือนไม่สามารถกำหนดได้โดยเฉพาะอย่างยิ่งสำหรับข้อบกพร่องที่ต้องใช้การตั้งค่าพิเศษหรือเทคนิคขั้นสูงเช่นการทำ heap priming หรือการหาประโยชน์จากเงื่อนไข จุดบกพร่องเหล่านี้จำนวนมากไม่ปรากฏให้เห็นในทันทีและอาจแสดงคำสั่งหลายพันคำให้ห่างจากการละเมิดหน่วยความจำซึ่งเป็นสาเหตุที่แท้จริง ASan ใช้ฟังก์ชันที่เกี่ยวข้องกับหน่วยความจำและข้อมูลแผ่นรองทั้งหมดที่มีพื้นที่ที่ไม่สามารถเข้าถึงได้โดยไม่ต้องเรียกใช้การเรียกกลับ ASan ซึ่งหมายความว่าการละเมิดหน่วยความจำจะเกิดขึ้นทันทีที่เกิดขึ้นแทนที่จะรอให้เกิดความเสียหายที่ก่อให้เกิดความผิดพลาด สิ่งนี้มีประโยชน์อย่างมากในการค้นหาจุดบกพร่องและการวินิจฉัยสาเหตุ

ในการตรวจสอบว่า ASAN ทำงานบนอุปกรณ์เป้าหมาย Android ได้รวม asan_test executable การทดสอบปฏิบัติการ asan_test และตรวจสอบความถูกต้องของฟังก์ชัน ASAN บนอุปกรณ์เป้าหมายโดยให้ข้อความวินิจฉัยพร้อมสถานะของการทดสอบแต่ละครั้ง เมื่อใช้งานสร้าง ASAN Android จะอยู่ใน /data/nativetest/asan_test/asan_test หรือ /data/nativetest64/asan_test/asan_test ตามค่าเริ่มต้น

ไม่ได้กำหนด BehaviorSanitizer

UndefinedBehaviorSanitizer (UBSan) ทำหน้าที่รวบรวมเวลาเครื่องมือเพื่อตรวจสอบพฤติกรรมที่ไม่ได้กำหนดประเภทต่างๆ ในขณะที่ UBSan สามารถตรวจจับ พฤติกรรมที่ไม่ได้กำหนดมากมาย แต่ Android รองรับการจัดตำแหน่งบูลขอบเขต enum ลอยหล่อล้นลอยหารด้วยศูนย์จำนวนเต็มหารด้วยศูนย์ nonnull แอตทริบิวต์ null ผลตอบแทน Return-nonnull-attribute, shift-base, shift-exponent, signed-integer-overflow, ไม่สามารถเข้าถึงได้, ไม่ได้ลงนาม-integer-overflow และ vla-bound ไม่ได้ลงชื่อ - จำนวนเต็ม - ล้นแม้ว่าในทางเทคนิคจะไม่ใช่พฤติกรรมที่ไม่ได้กำหนด แต่จะรวมอยู่ในน้ำยาฆ่าเชื้อและใช้ในโมดูล Android จำนวนมากรวมถึงส่วนประกอบสื่อกลางเพื่อกำจัดช่องโหว่ที่แฝงอยู่ในจำนวนเต็มล้น

การนำไปใช้

ในระบบสร้าง Android คุณสามารถเปิดใช้งาน 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)

ระบบบิวด์ Android ยังไม่รองรับการวินิจฉัยโดยละเอียดในไฟล์พิมพ์เขียวเช่นเดียวกับ makefiles นี่คือสิ่งที่เทียบเท่าที่ใกล้เคียงที่สุดที่เขียนเป็นพิมพ์เขียว (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

Android ยังมีทางลัดสองทางคือ integer และ default-ub เพื่อเปิดใช้งานชุดน้ำยาฆ่าเชื้อในเวลาเดียวกัน จำนวนเต็มเปิดใช้งาน integer-divide-by-zero , signed-integer-overflow และ unsigned-integer-overflow default-ub เปิดใช้งานการตรวจสอบที่มีปัญหาด้านประสิทธิภาพของคอมไพเลอร์น้อยที่สุด: บูล, จำนวนเต็ม - หาร - ศูนย์, การส่งคืน, การคืนค่า-nonnull-attribute, shift-exponent, ไม่สามารถเข้าถึงได้และ vla-bound คลาสน้ำยาฆ่าเชื้อจำนวนเต็มสามารถใช้ได้กับ SANITIZE_TARGET และ LOCAL_SANITIZE ในขณะที่ค่าเริ่มต้น - ub สามารถใช้ได้กับ SANITIZE_TARGET เท่านั้น

รายงานข้อผิดพลาดที่ดีขึ้น

การใช้งาน UBSan เริ่มต้นของ Android จะเรียกใช้ฟังก์ชันที่ระบุเมื่อพบพฤติกรรมที่ไม่ได้กำหนด โดยค่าเริ่มต้นฟังก์ชันนี้จะถูกยกเลิก อย่างไรก็ตามตั้งแต่เดือนตุลาคม 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 สำหรับส่วนประกอบของพื้นที่ผู้ใช้ Android รวมถึง Kernel Address Sanitizer (KASAN) KASAN เป็นการรวมกันของเคอร์เนลและการปรับเปลี่ยนเวลาคอมไพล์ซึ่งส่งผลให้เกิดระบบเครื่องมือที่ช่วยให้สามารถค้นหาจุดบกพร่องและวิเคราะห์สาเหตุที่แท้จริงได้ง่ายขึ้น

KASAN สามารถตรวจจับการละเมิดหน่วยความจำหลายประเภทในเคอร์เนล นอกจากนี้ยังสามารถตรวจจับการอ่านและเขียนนอกขอบเขตบนสแต็กฮีปและตัวแปรส่วนกลางและสามารถตรวจจับการใช้งานฟรีภายหลังและฟรีสองครั้ง

เช่นเดียวกับ ASAN KASAN ใช้การรวมกันของเครื่องมือวัดฟังก์ชันหน่วยความจำในเวลาคอมไพล์และหน่วยความจำเงาเพื่อติดตามการเข้าถึงหน่วยความจำขณะรันไทม์ ใน KASAN พื้นที่หน่วยความจำเคอร์เนลหนึ่งในแปดถูกอุทิศให้กับหน่วยความจำเงาซึ่งกำหนดว่าการเข้าถึงหน่วยความจำถูกต้องหรือไม่

KASAN ได้รับการสนับสนุนบนสถาปัตยกรรม x86_64 และ arm64 เป็นส่วนหนึ่งของเคอร์เนลต้นน้ำตั้งแต่ 4.0 และถูกส่งกลับไปยังเคอร์เนลที่ใช้ Android 3.18 KASAN ได้รับการทดสอบบนเคอร์เนล Android ที่คอมไพล์ด้วย gcc ตาม 4.9.2

นอกจาก KASAN แล้ว kcov ยังเป็นอีกหนึ่งการปรับเปลี่ยนเคอร์เนลที่มีประโยชน์สำหรับการทดสอบ kcov ได้รับการพัฒนาเพื่อให้สามารถทดสอบ fuzz แบบครอบคลุมในเคอร์เนลได้ มันวัดความครอบคลุมในแง่ของอินพุต syscall และมีประโยชน์กับระบบ fuzzing เช่น syzkaller

การนำไปใช้

ในการคอมไพล์เคอร์เนลที่เปิดใช้งาน KASAN และ kcov ให้เพิ่มแฟล็ก build ต่อไปนี้ในคอนฟิกูเรชันบิลด์เคอร์เนลของคุณ:

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 มีขนาดใหญ่กว่าเดิมมาก หากเป็นไปได้ให้แก้ไขพารามิเตอร์การบูตและการตั้งค่า bootloader เพื่อพิจารณาสิ่งนี้

หลังจากกระพริบเคอร์เนลให้ตรวจสอบบันทึกการบูตเคอร์เนลเพื่อดูว่า 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 บนอุปกรณ์เป้าหมาย