สคูโด้

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

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

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

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

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

การปรับแต่ง

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

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

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

ตัวเลือก ค่าเริ่มต้น 64 บิต ค่าเริ่มต้น 32 บิต คำอธิบาย
QuarantineSizeKb 256 64 ขนาด (เป็น KB) ของเขตกักกันที่ใช้เพื่อชะลอการจัดสรรที่แท้จริงของชิ้นส่วน ค่าที่ต่ำกว่าอาจลดการใช้หน่วยความจำแต่ลดประสิทธิผลของการบรรเทาลง ค่าลบจะกลับไปสู่ค่าเริ่มต้น การตั้งค่าทั้งสิ่งนี้และ ThreadLocalQuarantineSizeKb ให้เป็นศูนย์จะปิดใช้งานการกักกันทั้งหมด
QuarantineChunksUpToSize 2048 512 ขนาด (เป็นไบต์) สูงสุดที่สามารถกักเก็บชิ้นข้อมูลได้
ThreadLocalQuarantineSizeKb 64 16 ขนาด (เป็น KB) ของแคชต่อเธรดที่ใช้ในการถ่ายข้อมูลการกักกันส่วนกลาง ค่าที่ต่ำกว่าอาจลดการใช้หน่วยความจำ แต่อาจเพิ่มความขัดแย้งในการกักกันทั่วโลก การตั้งค่าทั้งสิ่งนี้และ QuarantineSizeKb ให้เป็นศูนย์จะปิดใช้งานการกักกันทั้งหมด
DeallocationTypeMismatch false false เปิดใช้งานการรายงานข้อผิดพลาดเกี่ยวกับ malloc/ลบ, ใหม่/ฟรี, ใหม่/ลบ[]
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 บิตเท่านั้น หากตั้งค่าไว้ พยายามปล่อยหน่วยความจำที่ไม่ได้ใช้ไปยังระบบปฏิบัติการ แต่ไม่บ่อยเกินช่วงเวลานี้ (ในหน่วยมิลลิวินาที) หากค่าเป็นลบ หน่วยความจำจะไม่ถูกปล่อยออกสู่ระบบปฏิบัติการ
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 ได้เช่นกัน