LLVM ซึ่งเป็นโครงสร้างพื้นฐานของคอมไพเลอร์ที่ใช้สร้าง Android มีส่วนประกอบหลายอย่างที่ทำการวิเคราะห์แบบสแตติกและไดนามิก ส่วนประกอบเหล่านี้ สามารถใช้น้ำยาฆ่าเชื้อ—โดยเฉพาะ AddressSanitizer และ UndefinedBehaviorSanitizer— อย่างกว้างขวางเพื่อวิเคราะห์ Android น้ำยาฆ่าเชื้อเป็นส่วนประกอบเครื่องมือวัดแบบคอมไพเลอร์ซึ่งมีอยู่ในภายนอก/คอมไพเลอร์-rt ที่สามารถใช้ในระหว่างการพัฒนาและการทดสอบเพื่อขจัดจุดบกพร่องและทำให้ Android ดีขึ้น ชุดน้ำยาฆ่าเชื้อที่ใช้อยู่ในปัจจุบันของ Android สามารถค้นพบและวินิจฉัยข้อบกพร่องในการใช้หน่วยความจำในทางที่ผิดและพฤติกรรมที่ไม่ได้กำหนดที่อาจเป็นอันตรายได้
แนวทางปฏิบัติที่ดีที่สุดสำหรับ Android บิวด์ในการบูตและรันโดยเปิดใช้งานการฆ่าเชื้อ เช่น AddressSanitizer และ UndefinedBehaviorSanitizer หน้านี้แนะนำ AddressSanitizer, UndefinedBehaviorSanitizer และ KernelAddressSanitizer แสดงให้เห็นว่าสามารถใช้งานได้อย่างไรภายในระบบบิลด์ Android และแสดงตัวอย่างไฟล์ Android.mk และ Android.bp ที่สร้างส่วนประกอบดั้งเดิมโดยเปิดใช้งานน้ำยาฆ่าเชื้อเหล่านี้
ที่อยู่Sanitizer
AddressSanitizer (ASan) คือความสามารถในการวัดตามคอมไพเลอร์ที่ตรวจจับข้อผิดพลาดของหน่วยความจำหลายประเภทในโค้ด C/C++ ขณะรันไทม์ ASan สามารถตรวจจับข้อผิดพลาดของหน่วยความจำได้หลายคลาส รวมถึง:
- การเข้าถึงหน่วยความจำนอกขอบเขต
- ฟรีสองเท่า
- ใช้หลังฟรี
Android อนุญาตให้ ใช้เครื่องมือ ASan ที่ระดับการสร้างเต็มและระดับ แอป ด้วย asanwrapper
AddressSanitizer รวมเครื่องมือของการเรียกใช้ฟังก์ชันที่เกี่ยวข้องกับหน่วยความจำทั้งหมด ซึ่งรวมถึง alloca, malloc และ free และเติมตัวแปรทั้งหมดและขอบเขตหน่วยความจำที่จัดสรรไว้ด้วยหน่วยความจำที่ทริกเกอร์การเรียกกลับ ASan เมื่อมีการอ่านหรือเขียน
เครื่องมือนี้ช่วยให้ ASan ตรวจพบจุดบกพร่องของการใช้หน่วยความจำที่ไม่ถูกต้อง รวมถึงขอบเขตการดับเบิลฟรีและขอบเขตการใช้งาน การส่งคืน และการว่าง ขณะที่การแพ็ดดิ้งหน่วยความจำในภูมิภาคจะตรวจจับการอ่านหรือเขียนที่อยู่นอกขอบเขต หากเกิดการอ่านหรือเขียนในพื้นที่แพดดิ้งนี้ 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 callback ซึ่งหมายความว่าการละเมิดหน่วยความจำจะถูกตรวจจับทันทีที่เกิดขึ้น แทนที่จะรอความเสียหายที่ก่อให้เกิดความผิดพลาด สิ่งนี้มีประโยชน์อย่างยิ่งในการค้นหาจุดบกพร่องและการวินิจฉัยสาเหตุ
เพื่อตรวจสอบว่า ASAN ทำงานได้บนอุปกรณ์เป้าหมาย Android ได้รวม asan_test ที่เรียกใช้งานได้ การทดสอบปฏิบัติการ asan_test และตรวจสอบการทำงานของ ASAN บนอุปกรณ์เป้าหมาย โดยให้ข้อความการวินิจฉัยพร้อมสถานะการทดสอบแต่ละครั้ง เมื่อใช้ ASAN Android build จะอยู่ใน /data/nativetest/asan_test/asan_test
หรือ /data/nativetest64/asan_test/asan_test
โดยค่าเริ่มต้น
UndefinedBehaviorSanitizer
UndefinedBehaviorSanitizer (UBSan) ดำเนินการวัดเวลาคอมไพล์เพื่อตรวจสอบพฤติกรรมที่ไม่ได้กำหนดประเภทต่างๆ ในขณะที่ UBSan สามารถตรวจจับ พฤติกรรมที่ไม่ได้กำหนดไว้มากมาย Android รองรับการจัดตำแหน่ง, บูล, ขอบเขต, enum, float-cast-overflow, float-divide-by-zero, integer-divide-by-zero, nonnull-attribute, null, return, return-nonnull-attribute, shift-base, shift-exponent, signed-integer-overflow, ไม่สามารถเข้าถึงได้, unsigned-integer-overflow และ vla-bound unsigned-integer-overflow แม้ว่าจะไม่ใช่พฤติกรรมที่ไม่ได้กำหนดในทางเทคนิค แต่ก็รวมอยู่ในโปรแกรมฆ่าเชื้อและใช้ในโมดูล 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 ยังไม่รองรับการวินิจฉัยโดยละเอียดในไฟล์พิมพ์เขียวเหมือนกับที่สร้างไฟล์ นี่คือสิ่งที่ใกล้เคียงที่สุดที่เขียนเป็นพิมพ์เขียว (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 เปิดใช้ integer-divide-by-zero
, signed-integer-overflow
และ unsigned-integer-overflow
default-ub
เปิดใช้งานการตรวจสอบที่มีปัญหาประสิทธิภาพคอมไพเลอร์น้อยที่สุด: bool, integer-divide-by-zero, return, return-nonnull-attribute, shift-exponent, unreachable และ vla-bound สามารถใช้คลาสฆ่าเชื้อจำนวนเต็มกับ SANITIZE_TARGET และ LOCAL_SANITIZE ในขณะที่ default-ub สามารถใช้ได้กับ SANITIZE_TARGET เท่านั้น
การรายงานข้อผิดพลาดที่ดีขึ้น
การใช้งาน UBSan เริ่มต้นของ Android จะเรียกใช้ฟังก์ชันที่ระบุเมื่อพบพฤติกรรมที่ไม่ได้กำหนด โดยค่าเริ่มต้น ฟังก์ชันนี้จะยกเลิก อย่างไรก็ตาม เริ่มตั้งแต่เดือนตุลาคม 2559 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 สำหรับส่วนประกอบ userspace 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 ให้เพิ่มแฟล็กบิลด์ต่อไปนี้ในคอนฟิกูเรชันบิลด์เคอร์เนลของคุณ:
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 บนอุปกรณ์เป้าหมาย