สคูโด้

Scudo เป็นตัวจัดสรรหน่วยความจำโหมดผู้ใช้แบบไดนามิก หรือตัวจัดสรร ฮีป ได้รับการออกแบบมาให้มีความยืดหยุ่นต่อช่องโหว่ที่เกี่ยวข้องกับฮีป (เช่น บัฟเฟอร์โอเวอร์โฟลว์แบบอิงฮีป ใช้หลัง free และ double free ) ขณะที่ยังคงประสิทธิภาพไว้ โดยจัดเตรียมมาตรฐาน C allocation และ deallocation primitives (เช่น malloc และ free) เช่นเดียวกับ C ++ primitives (เช่น new และ delete)

Scudo เป็นการบรรเทาผลกระทบมากกว่าตัวตรวจจับข้อผิดพลาดของหน่วยความจำที่สมบูรณ์ เช่น AddressSanitizer (ASan)

เริ่มตั้งแต่ Android 11 เป็นต้นไป scudo จะใช้สำหรับโค้ดเนทีฟทั้งหมด (ยกเว้นในอุปกรณ์ที่มีหน่วยความจำเหลือน้อย ซึ่งยังคงใช้ jemalloc อยู่) ที่รันไทม์ การจัดสรรฮีปดั้งเดิมและการจัดสรรคืนจะให้บริการโดย Scudo สำหรับไฟล์เรียกทำงานทั้งหมดและการพึ่งพาไลบรารี และกระบวนการจะถูกยกเลิกหากตรวจพบความเสียหายหรือพฤติกรรมที่น่าสงสัยในฮีป

ใน Android 10 ต้องเปิดใช้งาน scudo แบบไบนารีโดยการตั้งค่าตัวเลือก LOCAL_SANITIZE := scudo ในไฟล์ .mk หรือโปรแกรม sanitize: { scudo: true, } ในไฟล์ .bp

Scudo เป็น โอเพ่นซอร์ส และเป็นส่วนหนึ่งของโปรเจ็กต์ compiler-rt ของ LLVM สามารถดูเอกสารได้ที่ https://llvm.org/docs/ScudoHardenedAllocator.html รันไทม์ของ Scudo ถูกจัดส่งโดยเป็นส่วนหนึ่งของ toolchain ของ Android และเพิ่มการสนับสนุนใน Soong และ Make เพื่อให้เปิดใช้ allocator ในไบนารีได้ง่าย

คุณสามารถเปิดหรือปิดใช้งานการลดพิเศษภายในตัวจัดสรรได้โดยใช้ตัวเลือกที่อธิบายไว้ด้านล่าง

การปรับแต่ง

พารามิเตอร์บางตัวของตัวจัดสรรสามารถกำหนดตามพื้นฐานต่อกระบวนการได้หลายวิธี:

  • สแตติก : กำหนดฟังก์ชัน __scudo_default_options ในโปรแกรมที่ส่งคืนสตริงตัวเลือกที่จะแยกวิเคราะห์ ฟังก์ชันนี้ต้องมีต้นแบบดังต่อไปนี้: extern "C" const char *__scudo_default_options()
  • แบบไดนามิก: ใช้ตัวแปรสภาพแวดล้อม SCUDO_OPTIONS ที่มีสตริงตัวเลือกที่จะแยกวิเคราะห์ ตัวเลือกที่กำหนดด้วยวิธีนี้จะแทนที่คำจำกัดความที่ทำผ่าน __scudo_default_options

มีตัวเลือกดังต่อไปนี้

ตัวเลือก ค่าเริ่มต้น 64 บิต ค่าเริ่มต้น 32 บิต คำอธิบาย
QuarantineSizeKb 256 64 ขนาด (เป็น KB) ของการกักกันที่ใช้เพื่อชะลอการจัดสรรคืนสินค้าที่แท้จริงของกลุ่ม ค่าที่ต่ำกว่าอาจลดการใช้หน่วยความจำแต่ลดประสิทธิภาพของการลด; ค่าลบจะกลับไปเป็นค่าเริ่มต้น การตั้งค่าทั้ง this และ ThreadLocalQuarantineSizeKb เป็นศูนย์จะปิดใช้งานการกักกันทั้งหมด
QuarantineChunksUpToSize 2048 512 ขนาด (เป็นไบต์) สูงสุดที่สามารถกักเก็บชิ้นส่วนได้
ThreadLocalQuarantineSizeKb 64 16 ขนาด (เป็น KB) ของการใช้แคชต่อเธรดเพื่อออฟโหลดการกักกันส่วนกลาง ค่าที่ต่ำกว่าอาจลดการใช้หน่วยความจำแต่อาจเพิ่มการโต้แย้งในการกักกันส่วนกลาง การตั้งค่าทั้งสิ่งนี้และ QuarantineSizeKb เป็นศูนย์จะปิดใช้งานการกักกันทั้งหมด
DeallocationTypeMismatch false false เปิดใช้งานการรายงานข้อผิดพลาดใน malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true เปิดใช้งานการรายงานข้อผิดพลาดเกี่ยวกับขนาดที่ไม่ตรงกันระหว่างขนาดใหม่และการลบ
ZeroContents false false เปิดใช้งานเนื้อหาที่เป็นศูนย์ในการจัดสรรและการจัดสรรคืน
allocator_may_return_null false false ระบุว่าตัวจัดสรรสามารถคืนค่า null เมื่อเกิดข้อผิดพลาดที่กู้คืนได้ แทนที่จะยุติกระบวนการ
hard_rss_limit_mb 0 0 เมื่อ RSS ของกระบวนการถึงขีดจำกัดนี้ กระบวนการจะสิ้นสุดลง
soft_rss_limit_mb 0 0 เมื่อ RSS ของกระบวนการถึงขีดจำกัดนี้ การจัดสรรเพิ่มเติมจะล้มเหลวหรือคืน null (ขึ้นอยู่กับค่าของ allocator_may_return_null ) จนกว่า RSS จะย้อนกลับเพื่ออนุญาตให้มีการจัดสรรใหม่
allocator_release_to_os_interval_ms ไม่มี 5000 มีผลกับตัวจัดสรร 64 บิตเท่านั้น หากตั้งค่าไว้ จะพยายามปล่อยหน่วยความจำที่ไม่ได้ใช้ไปยัง OS แต่ไม่บ่อยเกินช่วงเวลานี้ (หน่วยเป็นมิลลิวินาที) หากค่าเป็นลบ หน่วยความจำจะไม่ถูกปล่อยไปยังระบบปฏิบัติการ
abort_on_error true true หากตั้งค่าไว้ เครื่องมือจะเรียก abort() แทน _exit() หลังจากพิมพ์ข้อความแสดงข้อผิดพลาด

การตรวจสอบความถูกต้อง

ปัจจุบัน ไม่มีการทดสอบ CTS สำหรับ Scudo โดยเฉพาะ ตรวจสอบให้แน่ใจว่าการทดสอบ CTS ผ่านโดยมีหรือไม่มี Scudo ที่เปิดใช้งานสำหรับไบนารีที่ระบุเพื่อตรวจสอบว่าไม่ส่งผลกระทบต่ออุปกรณ์

การแก้ไขปัญหา

หากตรวจพบปัญหาที่ไม่สามารถกู้คืนได้ ตัวจัดสรรจะแสดงข้อความแสดงข้อผิดพลาดไปยังตัวบอกข้อผิดพลาดมาตรฐาน จากนั้นจึงยุติกระบวนการ การติดตามสแต็กที่นำไปสู่การยุติจะถูกเพิ่มในบันทึกของระบบ ผลลัพธ์มักจะเริ่มต้นด้วย Scudo ERROR: ตามด้วยบทสรุปสั้นๆ ของปัญหาพร้อมกับตัวชี้ใดๆ

นี่คือรายการข้อความแสดงข้อผิดพลาดปัจจุบันและสาเหตุที่เป็นไปได้:

  • corrupted chunk header : การตรวจสอบผลรวมของเช็คซัมของส่วนหัวของอันล้มเหลว อาจเป็นเพราะหนึ่งในสองสิ่ง: ส่วนหัวถูกเขียนทับ (บางส่วนหรือทั้งหมด) หรือตัวชี้ที่ส่งไปยังฟังก์ชันไม่ใช่ส่วนย่อย
  • race on chunk header : สองเธรดที่แตกต่างกันกำลังพยายามจัดการส่วนหัวเดียวกันในเวลาเดียวกัน ซึ่งมักจะเป็นอาการของสภาวะการแข่งขันหรือขาดการล็อคโดยทั่วไปเมื่อดำเนินการกับกลุ่มนั้น
  • invalid chunk state : ก้อนไม่อยู่ในสถานะที่คาดไว้สำหรับการดำเนินการที่กำหนด เช่น ไม่ได้รับการจัดสรรเมื่อพยายามทำให้ว่าง หรือไม่ได้ถูกกักกันเมื่อพยายามรีไซเคิล การดับเบิ้ลฟรีเป็นสาเหตุทั่วไปของข้อผิดพลาดนี้
  • misaligned pointer : ข้อกำหนดการจัดตำแหน่งพื้นฐานมีผลบังคับใช้อย่างมาก: 8 ไบต์บนแพลตฟอร์ม 32 บิตและ 16 ไบต์บนแพลตฟอร์ม 64 บิต หากตัวชี้ที่ส่งไปยังฟังก์ชันของเราไม่ตรงกับเกณฑ์เหล่านั้น แสดงว่าตัวชี้ที่ส่งไปยังฟังก์ชันใดฟังก์ชันหนึ่งไม่อยู่ในแนวเดียวกัน
  • allocation type mismatch : เมื่อเปิดใช้งานตัวเลือกนี้ ฟังก์ชันการจัดสรรคืนที่เรียกบนกลุ่มจะต้องตรงกับประเภทของฟังก์ชันที่ถูกเรียกเพื่อจัดสรร ความไม่ตรงกันประเภทนี้อาจทำให้เกิดปัญหาด้านความปลอดภัยได้
  • การ invalid sized delete : เมื่อใช้ตัวดำเนินการลบขนาด C++14 และเปิดใช้งานการตรวจสอบเพิ่มเติม จะมีขนาดที่ไม่ตรงกันระหว่างที่ส่งผ่านเมื่อจัดสรรคืนกลุ่มและขนาดที่ร้องขอเมื่อจัดสรร โดยทั่วไปจะเป็นปัญหาของคอมไพเลอร์หรือ ความสับสนเกี่ยวกับประเภท วัตถุที่จัดสรรคืน
  • RSS limit exhausted : เกินขีดจำกัด RSS สูงสุดที่ระบุหรือไม่ก็ได้

หากคุณกำลังแก้ไขข้อขัดข้องในระบบปฏิบัติการ คุณสามารถใช้ HWASan OS build หากคุณกำลังแก้ไขข้อขัดข้องในแอป คุณสามารถใช้ บิลด์แอป HWASan ได้เช่นกัน