ที่อยู่Sanitizer

AddressSanitizer (ASan) เป็นเครื่องมือที่ใช้คอมไพเลอร์อย่างรวดเร็วสำหรับตรวจหาจุดบกพร่องของหน่วยความจำในโค้ดเนทีฟ

ASan ตรวจพบ:

  • บัฟเฟอร์สแต็กและฮีปโอเวอร์โฟลว์/อันเดอร์โฟลว์
  • กองใช้หลังจากฟรี
  • การใช้สแต็กนอกขอบเขต
  • ฟรีสองเท่า / ฟรีไวด์

ASan ทำงานบน ARM ทั้งแบบ 32 บิตและ 64 บิต รวมทั้ง x86 และ x86-64 โอเวอร์เฮด CPU ของ ASan อยู่ที่ประมาณ 2x โอเวอร์เฮดขนาดโค้ดอยู่ระหว่าง 50% ถึง 2x และโอเวอร์เฮดหน่วยความจำขนาดใหญ่ (ขึ้นอยู่กับรูปแบบการจัดสรรของคุณ แต่ตามลำดับที่ 2x)

Android 10 และสาขาหลัก AOSP บน AArch64 รองรับ ASan (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 โปรดดู Address Sanitizer แทน

ฆ่าเชื้อไฟล์ปฏิบัติการแต่ละรายการด้วย ASan

เพิ่ม LOCAL_SANITIZE:=address or sanitize: { address: true } ในกฎการสร้างสำหรับไฟล์ปฏิบัติการ คุณสามารถค้นหารหัสสำหรับตัวอย่างที่มีอยู่หรือค้นหาสารฆ่าเชื้ออื่น ๆ ที่มี

เมื่อตรวจพบจุดบกพร่อง ASan จะพิมพ์รายงานอย่างละเอียดทั้งไปยังเอาต์พุตมาตรฐานและไปยัง logcat จากนั้นจึงหยุดกระบวนการ

ฆ่าเชื้อไลบรารีที่ใช้ร่วมกันด้วย ASan

เนื่องจากวิธีการทำงานของ ASan ไลบรารีที่สร้างด้วย ASan จึงสามารถใช้ได้โดยไฟล์ปฏิบัติการที่สร้างด้วย ASan เท่านั้น

ในการฆ่าเชื้อไลบรารีที่ใช้ร่วมกันซึ่งใช้ในโปรแกรมสั่งการหลายตัว ซึ่งไม่ใช่ทั้งหมดที่สร้างด้วย ASan คุณต้องใช้ไลบรารีสองชุด วิธีที่แนะนำในการทำเช่นนี้คือการเพิ่มสิ่งต่อไปนี้ใน Android.mk สำหรับโมดูลที่เป็นปัญหา:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

สิ่งนี้ทำให้ไลบรารีอยู่ใน /system/lib/asan แทน /system/lib จากนั้นเรียกใช้ไฟล์ปฏิบัติการของคุณด้วย:

LD_LIBRARY_PATH=/system/lib/asan

สำหรับ system daemons ให้เพิ่มสิ่งต่อไปนี้ลงในส่วนที่เหมาะสมของ /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 ส่วนใหญ่สร้างขึ้นโดยไม่มีตัวชี้เฟรม ผลก็คือ คุณมักจะได้เฟรมที่มีความหมายเพียงหนึ่งหรือสองเฟรมเท่านั้น หากต้องการแก้ไขปัญหานี้ ให้สร้างไลบรารีใหม่ด้วย Asan (แนะนำ!) หรือด้วย:

LOCAL_CFLAGS:=-fno-omit-frame-pointer
LOCAL_ARM_MODE:=arm

หรือตั้งค่า ASAN_OPTIONS=fast_unwind_on_malloc=0 ในสภาพแวดล้อมของกระบวนการ อย่างหลังอาจใช้ CPU มาก ขึ้นอยู่กับโหลด

สัญลักษณ์

ในขั้นต้น รายงาน ASan มีการอ้างอิงถึงออฟเซ็ตในไบนารีและไลบรารีที่ใช้ร่วมกัน มีสองวิธีในการรับไฟล์ต้นฉบับและข้อมูลบรรทัด:

  • ตรวจสอบให้แน่ใจว่ามีไบนารี llvm-symbolizer อยู่ใน /system/bin llvm-symbolizer ถูกสร้างขึ้นจากแหล่งที่มาใน third_party/llvm/tools/llvm-symbolizer
  • กรองรายงานผ่านสคริปต์ external/compiler-rt/lib/asan/scripts/symbolize.py

วิธีที่สองสามารถให้ข้อมูลเพิ่มเติม (นั่นคือ ตำแหน่ง 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 และรีบูต

การใช้คุณสมบัติห่อ

แนวทางในส่วนก่อนหน้านี้ทำให้ 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

หากพบจุดบกพร่อง แอปหยุดทำงาน และรายงานจะถูกพิมพ์ลงในบันทึก

SANITIZE_TARGET

Android 7.0 ขึ้นไปรองรับการสร้างแพลตฟอร์ม Android ทั้งหมดด้วย ASan พร้อมกัน (หากคุณกำลังสร้างรุ่นที่สูงกว่า Android 9 HWASan เป็นตัวเลือกที่ดีกว่า)

รันคำสั่งต่อไปนี้ในโครงสร้างเดียวกัน

make -j42
SANITIZE_TARGET=address make -j42

ในโหมดนี้ userdata.img มีไลบรารีเพิ่มเติมและต้องแฟลชไปยังอุปกรณ์ด้วย ใช้บรรทัดคำสั่งต่อไปนี้:

fastboot flash userdata && fastboot flashall

สิ่งนี้สร้างไลบรารีที่ใช้ร่วมกันสองชุด: ปกติใน /system/lib (ชุดแรกทำการร้องขอ) และ ASan-instrumented ใน /data/asan/lib (ชุดที่สองทำการเรียกใช้) ไฟล์เรียกทำงานจากบิลด์ที่สองจะเขียนทับไฟล์จากบิลด์แรก ASan-instrumented executable ได้รับเส้นทางการค้นหาไลบรารีที่แตกต่างกันซึ่งรวมถึง /data/asan/lib ก่อน /system/lib ผ่านการใช้ /system/bin/linker_asan ใน PT_INTERP

ระบบบิลด์บล็อกไดเร็กทอรีอ็อบเจ็กต์ระดับกลางเมื่อค่า $SANITIZE_TARGET เปลี่ยนไป สิ่งนี้บังคับให้สร้างเป้าหมายทั้งหมดขึ้นใหม่ในขณะที่รักษาไบนารีที่ติดตั้งไว้ภายใต้ /system/lib

ไม่สามารถสร้างเป้าหมายบางอย่างด้วย ASan:

  • ไฟล์ปฏิบัติการที่เชื่อมโยงแบบคงที่
  • LOCAL_CLANG:=false
  • LOCAL_SANITIZE:=false ไม่ใช่ ASan'd สำหรับ SANITIZE_TARGET=address

ไฟล์เรียกทำงานเหล่านี้จะถูกข้ามไปในบิลด์ SANITIZE_TARGET และเวอร์ชันจากการเรียกใช้ make แรกจะถูกทิ้งไว้ใน /system/bin

ห้องสมุดเช่นนี้สร้างขึ้นโดยไม่มี ASan พวกเขาสามารถมีโค้ด ASan บางส่วนจากไลบรารีสแตติกที่พวกเขาใช้

เอกสารสนับสนุน