โปรแกรมตรวจสอบที่อยู่เคอร์เนล

Android มี Kernel Address Sanitizer (KASan) ซึ่งคล้ายกับโปรแกรมตรวจสอบที่ทำงานบน LLVM สำหรับคอมโพเนนต์พื้นที่ผู้ใช้ KASan เป็นการรวมกันของเคอร์เนลและการแก้ไขเวลาคอมไพล์ ซึ่งส่งผลให้ระบบมีเครื่องมือวัดผลที่ช่วยให้ค้นพบข้อบกพร่องและวิเคราะห์สาเหตุได้ง่ายขึ้น

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

KASan ใช้เครื่องมือวัดหน่วยความจำของฟังก์ชันที่คอมไพล์และหน่วยความจำเงาร่วมกันเพื่อติดตามการเข้าถึงหน่วยความจำขณะรันไทม์ ซึ่งคล้ายกับ ASan ใน KASan พื้นที่หน่วยความจำเคอร์เนล 1 ใน 8 จะใช้สำหรับหน่วยความจำเงาโดยเฉพาะ ซึ่งจะกำหนดว่าการเข้าถึงหน่วยความจำนั้นถูกต้องหรือไม่

KASan ใช้งานได้ในสถาปัตยกรรม x86_64 และ arm64 ซึ่งเป็นส่วนหนึ่งของเคอร์เนลจาก upstream ตั้งแต่เวอร์ชัน 4.0 และได้รับการพอร์ตไปยังเคอร์เนลที่ใช้ Android 3.18

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

การใช้งาน

หากต้องการคอมไพล์เคอร์เนลที่เปิดใช้ KASan และ kcov ให้เพิ่ม Flag การคอมไพล์ต่อไปนี้ในการกำหนดค่าการสร้างเคอร์เนล

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