AddressSanitizer (ASan) เป็นเครื่องมือที่ทำงานได้อย่างรวดเร็วโดยใช้คอมไพเลอร์ ข้อบกพร่องหน่วยความจําในโค้ดแบบเนทีฟ
ASan ตรวจพบสิ่งต่อไปนี้
- สแต็กและฮีปบัฟเฟอร์ล้น/ล้นเกิน
- การใช้ฮีปหลังจากฟรี
- การใช้สแต็กนอกขอบเขต
- Double Free/Wild Free
ASan ทำงานได้ทั้งบน ARM แบบ 32 บิตและ 64 บิต รวมถึง x86 และ x86-64 โอเวอร์เฮด CPU ของ ASan ประมาณ 2 เท่า โอเวอร์เฮดของขนาดโค้ดอยู่ระหว่าง 50% ถึง 2 เท่า และโอเวอร์เฮดหน่วยความจำขนาดใหญ่ (ขึ้นอยู่กับรูปแบบการจัดสรรของคุณ แต่เรียงลำดับ 2x)
Android 10 และ AOSP สาขาหลักบน AArch64 สนับสนุน AddressSanitizer ที่ใช้ฮาร์ดแวร์ (HWASan) เครื่องมือที่คล้ายกันที่มีโอเวอร์เฮดของ RAM ต่ำลงและ ในช่วงข้อบกพร่องที่ตรวจพบได้ HWASan ตรวจพบการใช้สแต็กหลังจากการส่งคืน นอกเหนือจากข้อบกพร่อง ตรวจพบโดย ASan
HWASan มีค่าใช้จ่ายโอเวอร์เฮดของขนาด CPU และโค้ดที่คล้ายกัน แต่มีโอเวอร์เฮดของ RAM น้อยกว่ามาก (15%) HWASan เป็นแบบไม่กำหนดทิศทาง มีค่าแท็กที่เป็นไปได้เพียง 256 ค่า จึงมีค่าคงที่ 0.4% ก็อาจจะเกิดข้อผิดพลาด HWASan ไม่มีเขตสีแดงจำกัดของ ASan สำหรับ การตรวจหารายการส่วนเกินและเขตกักเก็บที่จำกัดสำหรับการตรวจหาการใช้งานหลังการใช้งานฟรี ดังนั้นจึงไม่สำคัญกับ HWASan ว่าข้อมูลที่เกินมาจะมีขนาดเท่าใด หรือใช้งานหน่วยความจำได้นานแค่ไหนแล้ว มีการซื้อขาย ซึ่งทำให้ HWASan ดีกว่า ASan คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ ดีไซน์ HWASan หรือเกี่ยวกับการใช้ HWASan ใน Android
ASan ตรวจพบสแต็ก/โอเวอร์โฟลว์ทั่วโลก นอกเหนือจากฮีปล้น และทำงานได้รวดเร็วโดยมีค่าใช้จ่ายในหน่วยความจำน้อยที่สุด
เอกสารนี้จะอธิบายวิธีสร้างและเรียกใช้ส่วนต่างๆ/อุปกรณ์ Android ทั้งหมดด้วย ASan หากคุณกำลังสร้างแอป SDK/NDK ด้วย ASan โปรดดู ตัวล้างที่อยู่ แทน
ทำความสะอาดไฟล์ปฏิบัติการแต่ละรายการด้วย ASan
เพิ่ม LOCAL_SANITIZE:=address
หรือ sanitize: { address: true }
ลงใน
กฎการสร้างสำหรับไฟล์ปฏิบัติการ คุณสามารถค้นหาโค้ดสำหรับตัวอย่างที่มีอยู่หรือค้นหา
เจลล้างพิษอื่นๆ ที่มีให้บริการ
เมื่อตรวจพบข้อบกพร่อง ASan จะพิมพ์รายงานแบบละเอียดทั้งตามมาตรฐาน
เอาต์พุตไปยัง logcat
แล้วทำให้กระบวนการขัดข้อง
ทำความสะอาดคลังภาพที่แชร์ด้วย ASan
วิธีการทำงานของ ASan นั้น ห้องสมุดที่สร้างด้วย ASan นั้นใช้ได้เฉพาะ ไฟล์ปฏิบัติการที่สร้างขึ้นด้วย ASan
เพื่อทำความสะอาดไลบรารีที่ใช้ร่วมกันซึ่งใช้ในไฟล์สั่งการหลายรายการ ไม่ใช่ทั้งหมด
ที่สร้างด้วย ASan คุณต้องมีสำเนา
ของไลบรารี 2 ฉบับ
วิธีที่แนะนำคือให้เพิ่มข้อมูลต่อไปนี้ลงใน Android.mk
สำหรับโมดูลที่เป็นปัญหา
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
การดำเนินการนี้จะทำให้ไลบรารีอยู่ใน /system/lib/asan
แทนที่จะเป็น
/system/lib
จากนั้นเรียกใช้ไฟล์ปฏิบัติการด้วยสิ่งต่อไปนี้
LD_LIBRARY_PATH=/system/lib/asan
สำหรับ Daemon ของระบบ ให้เพิ่มรายการต่อไปนี้ลงในส่วนที่เหมาะสมของ
/init.rc
หรือ /init.$device$.rc
setenv LD_LIBRARY_PATH /system/lib/asan
ยืนยันว่ากระบวนการใช้ไลบรารีจาก /system/lib/asan
เมื่อนำเสนอโดยการอ่าน /proc/$PID/maps
ไม่เช่นนั้น คุณอาจต้อง
เพื่อปิดใช้งาน SELinux
adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID # if it is a system service, or may be adb shell stop; adb shell start.
สแต็กเทรซที่ดียิ่งขึ้น
ASan ใช้เครื่องมือคลายปมที่ใช้เฟรมไวท์บอร์ดเพื่อบันทึกการเรียงซ้อน ติดตามสำหรับเหตุการณ์การจัดสรรหน่วยความจำและข้อเสนอตำแหน่งดีลทั้งหมดในโปรแกรม พบบ่อยที่สุด ของ Android สร้างขึ้นโดยไม่ใช้ตัวชี้เฟรม ด้วยเหตุนี้ คุณจึงมักจะได้รับ เพียงแค่ 1 หรือ 2 เฟรมเท่านั้น ในการแก้ไขปัญหานี้ ให้สร้างไลบรารีอีกครั้งด้วย ASan (แนะนำ!) หรือกับ:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
หรือกำหนดให้มี ASAN_OPTIONS=fast_unwind_on_malloc=0
ในขั้นตอนนี้
ของคุณ ซึ่งอาจใช้ CPU มาก
ด้วย
สัญลักษณ์
ในช่วงแรก รายงาน ASan มีการอ้างอิงถึงออฟเซ็ตในไบนารีและแชร์ ห้องสมุด การดูข้อมูลไฟล์และบรรทัดมี 2 วิธีดังนี้
- ตรวจสอบว่าไบนารี
llvm-symbolizer
อยู่ใน/system/bin
llvm-symbolizer
สร้างขึ้นจากแหล่งที่มาในthird_party/llvm/tools/llvm-symbolizer
- กรองรายงานผ่าน
external/compiler-rt/lib/asan/scripts/symbolize.py
สคริปต์
วิธีที่ 2 สามารถให้ข้อมูลเพิ่มเติม (เช่น สถานที่ตั้ง file:line
แห่ง) เนื่องจาก
ความพร้อมใช้งานของไลบรารีสัญลักษณ์ในโฮสต์
ASan ในแอป
ASan มองเห็นโค้ด Java ไม่ได้ แต่ตรวจพบข้อบกพร่องใน JNI ได้
ห้องสมุด คุณต้องสร้างไฟล์ปฏิบัติการด้วย ASan ซึ่ง
กรณีนี้คือ /system/bin/app_process(32|64)
ช่วงเวลานี้
เปิดใช้งาน ASan ในแอปทั้งหมดบนอุปกรณ์ในเวลาเดียวกัน
การใช้งานหนัก แต่อุปกรณ์ที่มี RAM 2 GB ควรรองรับได้
เพิ่ม LOCAL_SANITIZE:=address
ไว้ใน
กฎของบิลด์ app_process
ใน frameworks/base/cmds/app_process
เพิกเฉย
ตอนนี้เป้าหมาย app_process__asan
ในไฟล์เดียวกัน
ยังคงมีอยู่ ณ เวลาที่คุณอ่านข้อความนี้)
แก้ไขส่วน service zygote
ของ
system/core/rootdir/init.zygote(32|64).rc
ที่เหมาะสมเพื่อเพิ่ม
ต่อบรรทัดไปยังบล็อกของบรรทัดที่มีการเยื้องที่มี class main
และ
เยื้องด้วยจํานวนเท่ากัน:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
สร้าง, ซิงค์ adb, Fastboot Flash Boot และรีบูต
ใช้คุณสมบัติการรวม
แนวทางในส่วนก่อนหน้านี้ทำให้ ASan ลงในระบบ (อันที่จริงก็คือทุกองค์ประกอบสืบทอดของ Zygote กระบวนการ) คุณจะเรียกใช้แอปเพียงแอปเดียว (หรือหลายแอป) ด้วย ASan ได้ เพิ่มโอเวอร์เฮดหน่วยความจำบางส่วนเพื่อให้การเริ่มต้นแอปที่ช้าลง
ซึ่งทำได้โดยการเริ่มต้นแอปด้วยพร็อพเพอร์ตี้ wrap.
ตัวอย่างต่อไปนี้เรียกใช้แอป Gmail ภายใต้ ASan
adb root
adb shell setenforce 0 # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"
ในบริบทนี้ asanwrapper
จะเขียน /system/bin/app_process
ใหม่
ไปยัง /system/bin/asan/app_process
ซึ่งสร้างขึ้นด้วย
ASan และเพิ่ม /system/lib/asan
ในตอนเริ่มต้นด้วย
เส้นทางการค้นหาไลบรารีแบบไดนามิกได้ วิธีนี้ใช้โดย ASan
ไลบรารีจาก /system/lib/asan
ควรแปลงเป็นไลบรารีปกติ
ใน /system/lib
เมื่อทำงานกับ asanwrapper
หากพบข้อบกพร่อง แอปจะขัดข้อง และรายงานจะถูกพิมพ์ไปยัง บันทึก
ทำให้เป้าหมายเสร็จสมบูรณ์
Android 7.0 ขึ้นไปมีการสนับสนุนในการสร้างแพลตฟอร์ม Android ทั้งแพลตฟอร์มด้วย ASan ได้พร้อมกัน (หากคุณกำลังสร้างรุ่นที่สูงกว่า Android 9 การใช้ HWASan ถือเป็นตัวเลือกที่ดีกว่า)
เรียกใช้คำสั่งต่อไปนี้ในโครงสร้างบิลด์เดียวกัน
make -j42
SANITIZE_TARGET=address make -j42
ในโหมดนี้ userdata.img
จะมีไลบรารีเพิ่มเติมและต้อง
ในอุปกรณ์ด้วย ใช้บรรทัดคำสั่งต่อไปนี้
fastboot flash userdata && fastboot flashall
ระบบจะสร้างไลบรารีที่ใช้ร่วมกัน 2 ชุด ได้แก่ ชุดปกติใน
/system/lib
(การเรียกใช้ครั้งแรก) และใช้ ASan ใน
/data/asan/lib
(การเรียกใช้ครั้งที่ 2) ไฟล์ดำเนินการจาก
บิลด์ที่ 2 จะเขียนทับบิลด์จากบิลด์แรก ใช้เครื่องดนตรี ASan
ไฟล์ปฏิบัติการจะได้รับเส้นทางการค้นหาไลบรารีอื่นที่ประกอบด้วย
/data/asan/lib
ก่อน /system/lib
ผ่านการใช้
/system/bin/linker_asan
ใน PT_INTERP
ไดเรกทอรีของออบเจ็กต์ระบบบิลด์จะเป็นตัวเข้ารหัสออบเจ็กต์ตัวกลางเมื่อ
ค่า $SANITIZE_TARGET
มีการเปลี่ยนแปลง บังคับให้มีการสร้างใหม่
กำหนดเป้าหมายขณะที่เก็บไบนารีที่ติดตั้งไว้ภายใต้ /system/lib
เป้าหมายบางอย่างไม่สามารถสร้างด้วย ASan ได้:
- ไฟล์ปฏิบัติการที่ลิงก์แบบคงที่
- เป้าหมาย
LOCAL_CLANG:=false
LOCAL_SANITIZE:=false
ไม่ใช่ ASan สำหรับSANITIZE_TARGET=address
ระบบจะข้ามไฟล์ปฏิบัติการเช่นนี้ในบิลด์ SANITIZE_TARGET
และ
เวอร์ชันจากการเรียกใช้ครั้งแรกยังคงอยู่ใน /system/bin
ห้องสมุดลักษณะนี้สร้างขึ้นโดยไม่มี ASan มี ASan บางอย่าง จากไลบรารีแบบคงที่ที่ต้องใช้