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