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 ได้เช่นกัน