ทําความเข้าใจรายงาน HWASan

เมื่อเครื่องมือ HWASan ตรวจพบข้อบกพร่องเกี่ยวกับหน่วยความจำ ระบบจะหยุดกระบวนการด้วย abort() และพิมพ์รายงานไปยัง stderr และ logcat ข้อผิดพลาด HWASan จะอยู่ใน /data/tombstones เช่นเดียวกับข้อขัดข้องที่เกิดจากโค้ดเนทีฟทั้งหมดใน Android

รายงานตัวอย่าง

เมื่อเทียบกับข้อขัดข้องที่เกิดจากโค้ดเนทีฟทั่วไป HWASan จะมีข้อมูลเพิ่มเติมในช่องข้อความ Abort ใกล้ด้านบนของ Tombstone ตัวอย่างข้อขัดข้องที่เกิดจากฮีปมีดังนี้ สำหรับ ข้อบกพร่องของสแต็ก โปรดดูหมายเหตุสำหรับส่วนที่เฉพาะเจาะจงกับสแต็ก

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/flame_hwasan/flame:Tiramisu/MASTER/7956676:userdebug/dev-keys'
Revision: 'DVT1.0'
ABI: 'arm64'
Timestamp: 2019-04-24 01:13:22+0000
pid: 11154, tid: 11154, name: sensors@1.0-ser  >>> /vendor/bin/hw/android.hardware.sensors@1.0-service <<<
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
Abort message: '

[...]

[0x00433ae20040,0x00433ae20060) is a small unallocated heap chunk; size: 32 offset: 5








[ … regular crash dump follows …]

รายงานนี้คล้ายกับรายงาน AddressSanitizer แต่ข้อบกพร่อง HWASan เกือบทั้งหมดเป็นข้อผิดพลาดการกำหนดแท็กไม่ตรงกัน ซึ่งหมายถึงการเข้าถึงหน่วยความจำที่แท็กตัวชี้ไม่ตรงกับแท็กหน่วยความจำที่เกี่ยวข้อง ซึ่งอาจเป็นกรณีใดกรณีหนึ่งต่อไปนี้

  • การเข้าถึงนอกขอบเขตในสแต็กหรือฮีป
  • ข้อผิดพลาด Use-after-free ในฮีป
  • ข้อผิดพลาด Use-after-return ในสแต็ก

ส่วน

คำอธิบายของแต่ละส่วนในรายงาน HWASan มีดังนี้

ข้อผิดพลาดในการเข้าถึง

มีข้อมูลเกี่ยวกับการเข้าถึงหน่วยความจำที่ไม่ถูกต้อง ซึ่งรวมถึงข้อมูลต่อไปนี้

  • ประเภทการเข้าถึง (READ เทียบกับ WRITE)
  • ขนาดการเข้าถึง (จำนวนไบต์ที่พยายามเข้าถึง)
  • หมายเลขเธรดของการเข้าถึง
  • แท็กตัวชี้และแท็กหน่วยความจำ (สำหรับการแก้ไขข้อบกพร่องขั้นสูง)

สแต็กเทรซของการเข้าถึง

สแต็กเทรซของการเข้าถึงหน่วยความจำที่ไม่ถูกต้อง ดูการสร้างสัญลักษณ์เพื่อ สร้างสัญลักษณ์

สาเหตุ

สาเหตุที่เป็นไปได้ของการเข้าถึงที่ไม่ถูกต้อง หากมีสาเหตุที่เป็นไปได้หลายรายการ ระบบจะแสดงรายการตามลำดับความน่าจะเป็นจากมากไปน้อย โดยจะอยู่ก่อนข้อมูลโดยละเอียดเกี่ยวกับสาเหตุที่เป็นไปได้ HWASan สามารถวินิจฉัยสาเหตุต่อไปนี้ได้

  • Use-after-free
  • การกำหนดแท็กสแต็กไม่ตรงกัน ซึ่งอาจเป็นการใช้สแต็กหลังจากกลับมา การใช้สแต็กหลังจากขอบเขต หรือการใช้สแต็กนอกขอบเขต
  • บัฟเฟอร์ฮีปล้น
  • การล้นทั่วโลก

ข้อมูลหน่วยความจำ

อธิบายสิ่งที่ HWASan ทราบเกี่ยวกับหน่วยความจำที่เข้าถึง และอาจแตกต่างกันไปตามประเภทข้อบกพร่อง

ประเภทข้อบกพร่อง สาเหตุ รูปแบบรายงาน
การกำหนดแท็กไม่ตรงกัน Use-after-free ใช้รูปแบบรายงานต่อไปนี้
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
บัฟเฟอร์ฮีปล้น โปรดทราบว่าอาจเป็นการล้นต่ำด้วย
<address> is located N bytes to the right of M-byte region [<start>, <end>)
allocated here:
การกำหนดแท็กสแต็กไม่ตรงกัน รายงานสแต็กจะไม่แยกความแตกต่างระหว่างข้อบกพร่องการล้นหรือการล้นต่ำกับข้อบกพร่อง Use-after-return นอกจากนี้ คุณต้องสร้างสัญลักษณ์แบบออฟไลน์เพื่อค้นหาการจัดสรรสแต็กที่เป็นแหล่งที่มาของข้อผิดพลาด ดูทำความเข้าใจรายงานสแต็ก รายงาน
การคืนหน่วยความจำไม่ถูกต้อง Use-after-free ข้อบกพร่องการคืนหน่วยความจำซ้ำ หากเกิดเหตุการณ์นี้เมื่อปิดกระบวนการ อาจหมายถึงการละเมิดกฎการกำหนดครั้งเดียว
<address> is located N bytes inside of M-byte region [<start>, <end>)
freed by thread T0 here:
อธิบายที่อยู่ไม่ได้ อาจเป็นการคืนหน่วยความจำแบบสุ่ม (การคืนหน่วยความจำที่ไม่ได้จัดสรรไว้ก่อนหน้านี้) หรือการคืนหน่วยความจำซ้ำหลังจากนำหน่วยความจำที่จัดสรรไว้ออกจากบัฟเฟอร์ว่างของ HWASan
0x... คือหน่วยความจำ Shadow ของ HWASan เป็นการคืนหน่วยความจำแบบสุ่ม เนื่องจากแอปพยายามคืนหน่วยความจำภายในของ HWASan

สแต็กเทรซของการคืนหน่วยความจำ

สแต็กเทรซของตำแหน่งที่คืนหน่วยความจำ จะปรากฏเฉพาะในกรณีที่เกิดข้อบกพร่อง Use-after-free หรือ Invalid-free ดูการสร้างสัญลักษณ์เพื่อสร้างสัญลักษณ์

สแต็กเทรซของการจัดสรร

สแต็กเทรซของตำแหน่งที่จัดสรรหน่วยความจำ ดูการสร้างสัญลักษณ์เพื่อสร้างสัญลักษณ์

ข้อมูลการแก้ไขข้อบกพร่องขั้นสูง

รายงาน HWASan ยังมีข้อมูลการแก้ไขข้อบกพร่องขั้นสูงบางอย่าง ซึ่งรวมถึงข้อมูลต่อไปนี้ (ตามลำดับ)

  1. รายการเธรดในกระบวนการ
  2. รายการเธรดในกระบวนการ
  3. ค่าของแท็กหน่วยความจำใกล้กับหน่วยความจำที่เกิดข้อผิดพลาด
  4. การดัมป์รีจิสเตอร์ ณ จุดที่มีการเข้าถึงหน่วยความจำ

การดัมป์แท็กหน่วยความจำ

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

tags: ad/5c (ptr/mem)
[...]
Memory tags around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: 0e  0e  0e  57  20  20  20  20  20  2e  5e  5e  5e  5e  5e  b5
=>0x006f33ae2000: f6  f6  f6  f6  f6  4c  ad  ad  ad  ad  ad  ad [5c] 5c  5c  5c
  0x006f33ae2010: 5c  04  2e  2e  2e  2e  2e  2f  66  66  66  66  66  80  6a  6a
Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
  0x006f33ae1ff0: ab  52  eb  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
=>0x006f33ae2000: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. [..] ..  ..  ..
  0x006f33ae2010: ..  5c  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..

โปรดสังเกตแท็ก ad ที่ต่อเนื่องกัน 6 × 16 = 96 ไบต์ทางด้านซ้ายซึ่งตรงกับแท็กตัวชี้

หากขนาดของการจัดสรรไม่ใช่จำนวนเท่าของ 16 ระบบจะจัดเก็บส่วนที่เหลือของขนาดเป็น แท็กหน่วยความจำ และจัดเก็บแท็กเป็น แท็กแกรนูล ขนาดเล็ก ในตัวอย่างก่อนหน้า หลังจากแท็ก ad ที่จัดสรรไว้ซึ่งแสดงเป็นตัวหนา เรามีการจัดสรรแท็ก 5c ขนาด 5 × 16 + 4 = 84 ไบต์

แท็กหน่วยความจำเป็น 0 (เช่น tags: ad/00 (ptr/mem)) บ่งบอกถึงข้อบกพร่อง Stack-use-after-return

การดัมป์รีจิสเตอร์

การดัมป์รีจิสเตอร์ในรายงาน HWASan สอดคล้องกับคำสั่งที่ทำการเข้าถึงหน่วยความจำที่ไม่ถูกต้อง การดัมป์นี้จะตามด้วยการดัมป์รีจิสเตอร์อีกรายการจากตัวจัดการสัญญาณ Android ปกติ โปรดละเว้นการดัมป์รายการที่ 2 เนื่องจากระบบดำเนินการเมื่อ HWASan เรียก abort() และไม่เกี่ยวข้องกับข้อบกพร่อง

การสร้างสัญลักษณ์

หากต้องการรับชื่อฟังก์ชันและหมายเลขบรรทัดในสแต็กเทรซ (และรับชื่อตัวแปรสำหรับข้อบกพร่อง Use-after-scope) คุณต้องสร้างสัญลักษณ์แบบออฟไลน์

การตั้งค่าครั้งแรก: ติดตั้ง llvm-symbolizer

หากต้องการสร้างสัญลักษณ์ ระบบของคุณต้องติดตั้ง llvm-symbolizer และเข้าถึงได้จาก $PATH ใน Debian คุณสามารถติดตั้งได้โดยใช้ sudo apt install llvm

รับไฟล์สัญลักษณ์

สำหรับการสร้างสัญลักษณ์ เราต้องใช้ไบนารีที่ไม่ได้ลบสัญลักษณ์ออกซึ่งมีสัญลักษณ์ ตำแหน่งของไฟล์จะขึ้นอยู่กับประเภทบิลด์

  • สำหรับการสร้างแบบโลคัล ไฟล์สัญลักษณ์จะอยู่ใน out/target/product/<product>/symbols/
  • สำหรับการสร้าง AOSP (เช่น แฟลชจาก Android Flash Tool) การ สร้างจะอยู่ใน Android CI ในอาร์ติแฟกต์ สำหรับการสร้างจะมีไฟล์ ${PRODUCT}-symbols-${BUILDID}.zip
  • สำหรับการสร้างภายใน จากองค์กรของคุณ โปรดดูเอกสารประกอบขององค์กรเพื่อขอความช่วยเหลือในการรับไฟล์สัญลักษณ์

สร้างสัญลักษณ์

hwasan_symbolize --symbols <DECOMPRESSED_DIR>/out/target/product/*/symbols < crash

ทำความเข้าใจรายงานสแต็ก

สำหรับข้อบกพร่องที่เกิดขึ้นกับตัวแปรสแต็ก รายงาน HWASan จะมีรายละเอียดดังนี้

Cause: stack tag-mismatch
Address 0x007d4d251e80 is located in stack of thread T64
Thread: T64 0x0074000b2000 stack: [0x007d4d14c000,0x007d4d255cb0) sz: 1088688 tls: [0x007d4d255fc0,0x007d4d259000)
Previously allocated frames:
  record_addr:0x7df7300c98 record:0x51ef007df3f70fb0  (/apex/com.android.art/lib64/libart.so+0x570fb0)
  record_addr:0x7df7300c90 record:0x5200007df3cdab74  (/apex/com.android.art/lib64/libart.so+0x2dab74)
  [...]

HWASan จะติดตามเฟรมสแต็กที่ผ่านมาเพื่อช่วยให้คุณเข้าใจข้อบกพร่องของสแต็ก HWASan จะไม่แปลงเฟรมเหล่านี้เป็นเนื้อหาที่มนุษย์เข้าใจได้ในรายงานข้อบกพร่อง และ ต้องมีขั้นตอนการสร้างสัญลักษณ์เพิ่มเติม

การละเมิดกฎการกำหนดครั้งเดียว

ข้อบกพร่อง Use-after-free บางรายการที่ HWASan รายงานอาจบ่งบอกถึงการละเมิดกฎการกำหนดครั้งเดียว (One Definition Rule หรือ ODR) การละเมิด ODR เกิดขึ้นเมื่อมีการกำหนดตัวแปรเดียวกันหลายครั้งในโปรแกรมเดียวกัน ซึ่งหมายความว่าตัวแปรจะถูกทำลายหลายครั้ง ซึ่งอาจทำให้เกิดข้อผิดพลาด Use-after-free

หลังจากการสร้างสัญลักษณ์ การละเมิด ODR จะแสดงข้อผิดพลาด Use-after-free ที่มี __cxa_finalize ทั้งในสแต็กการเข้าถึงที่ไม่ถูกต้องและสแต็กคืนหน่วยความจำที่นี่ สแต็กจัดสรรไว้ก่อนหน้านี้ที่นี่ มี __dl__ZN6soinfo17call_constructorsEv และควรชี้ไปยังตำแหน่งในโปรแกรมที่กำหนดตัวแปรไว้สูงกว่าในสแต็ก

การละเมิด ODR อาจเกิดขึ้นได้หากมีการใช้ไลบรารีแบบคงที่ หากมีการลิงก์ไลบรารีแบบคงที่ที่กำหนดตัวแปรส่วนกลาง C++ ไปยังไลบรารีที่แชร์หรือไฟล์ปฏิบัติการหลายรายการ อาจมีการกำหนดสัญลักษณ์เดียวกันหลายรายการในพื้นที่ที่อยู่เดียวกัน ซึ่งทำให้เกิดข้อผิดพลาด ODR

การแก้ปัญหา

ส่วนนี้อธิบายข้อผิดพลาดบางอย่างและวิธีแก้ไข

HWAddressSanitizer อธิบายแอดเดรสโดยละเอียดเพิ่มเติมไม่ได้

บางครั้ง HWASan อาจมีพื้นที่ไม่เพียงพอสำหรับข้อมูลเกี่ยวกับการจัดสรรหน่วยความจำที่ผ่านมา ในกรณีดังกล่าว รายงานจะมีสแต็กเทรซเพียงรายการเดียวสำหรับการเข้าถึงหน่วยความจำโดยตรง ตามด้วยหมายเหตุ

HWAddressSanitizer can not describe address in more detail.

ในบางกรณี คุณสามารถแก้ไขปัญหานี้ได้โดยเรียกใช้การทดสอบหลายครั้ง อีกตัวเลือกหนึ่งคือการเพิ่มขนาดประวัติ HWASan คุณสามารถทำได้ทั่วโลกใน build/soong/cc/sanitize.go (มองหา hwasanGlobalOptions) หรือในสภาพแวดล้อมของกระบวนการ (ลองใช้ adb shell echo $HWASAN_OPTIONS เพื่อดูการตั้งค่าปัจจุบัน)

ข้อผิดพลาดนี้อาจเกิดขึ้นได้เช่นกันหากหน่วยความจำที่เข้าถึงไม่ได้แมปหรือจัดสรรโดยตัวจัดสรรที่ไม่รู้จัก HWASan ในกรณีนี้ แท็ก mem ที่แสดงในส่วนหัวของข้อขัดข้องโดยทั่วไปจะเป็น 00 หากคุณมีสิทธิ์เข้าถึง Tombstone แบบเต็ม การดูการดัมป์แผนที่หน่วยความจำอาจช่วยให้ทราบว่าที่อยู่เป็นของการแมปใด (หากมี)

ข้อบกพร่องที่ซ้อนกันในเธรดเดียวกัน

หมายความว่าเกิดข้อบกพร่องขณะสร้างรายงานข้อขัดข้อง HWASan ซึ่งมักเกิดจากข้อบกพร่องในรันไทม์ HWASan โปรดรายงานข้อบกพร่องและระบุวิธีการจำลองปัญหา (หากเป็นไปได้)