หน่วยความจำปฏิบัติการเท่านั้น (XOM) สำหรับไบนารีของ AArch64

ส่วนโค้ดปฏิบัติการสำหรับไบนารีของระบบ AArch64 จะทำเครื่องหมายโดยค่าเริ่มต้น ปฏิบัติการเท่านั้น (อ่านไม่ได้) เป็นการลดช่องโหว่จากโค้ดแบบทันท่วงที ใช้การโจมตีซ้ำ โค้ดที่ผสมผสานข้อมูลและการเขียนโค้ดเข้าด้วยกันและเขียนโค้ดอย่างมีจุดมุ่งหมาย ตรวจสอบส่วนเหล่านี้ (โดยไม่ต้องแมปส่วนหน่วยความจำใหม่ให้อ่านได้ก่อน) ใช้งานไม่ได้ แอปที่มี SDK เป้าหมายเป็น 10 (API ระดับ 29 ขึ้นไป) จะได้รับผลกระทบหากแอปพยายามอ่านส่วนโค้ดของ ไลบรารีระบบที่เปิดใช้หน่วยความจำที่ดำเนินการเท่านั้น (XOM) ในหน่วยความจำโดยไม่มีการเรียกใช้ก่อน ทำเครื่องหมายส่วนว่าอ่านได้

เพื่อให้ได้รับประโยชน์สูงสุดจากการลดปัญหานี้ การสนับสนุนทั้งฮาร์ดแวร์และเคอร์เนล ต้องระบุ หากไม่มีการรองรับนี้ การผ่อนปรนชั่วคราวอาจบังคับใช้เพียงบางส่วนเท่านั้น เคอร์เนลทั่วไปของ Android 4.9 มีแพตช์ที่เหมาะสมเพื่อให้บริการเต็มรูปแบบ รองรับสิ่งนี้ในอุปกรณ์ ARMv8.2

การใช้งาน

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

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

การรองรับอุปกรณ์และผลกระทบ

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

ต้องตั้งค่าแฟล็กเคอร์เนล CONFIG_ARM64_UAO ในเคอร์เนลเป็น ตรวจสอบว่าเคอร์เนลดำเนินการตามหน้า Userland ที่ทำเครื่องหมายว่า "เรียกใช้งานเท่านั้น" ARMv8 รุ่นก่อนหน้า หรืออุปกรณ์ ARMv8.2 ที่ปิดใช้การลบล้างการเข้าถึงของผู้ใช้ (UAO) ต้องไม่ ได้รับประโยชน์อย่างเต็มที่จากวิธีนี้ และอาจยังคงสามารถอ่านหน้าสำหรับการดำเนินการเท่านั้นได้โดยใช้ Syscalls

เปลี่ยนโครงสร้างภายในโค้ดที่มีอยู่

โค้ดที่มีการย้ายมาจาก AArch32 อาจมีข้อมูลผสมและ ซึ่งทำให้เกิดปัญหาขึ้นได้ ในหลายกรณี การแก้ไขปัญหาเหล่านี้ทำได้ง่ายๆ เป็นการย้ายค่าคงที่ไปยังส่วน .data ในไฟล์การประกอบ

ชิ้นส่วนประกอบที่เขียนด้วยลายมืออาจต้องเปลี่ยนโครงสร้างภายในโค้ดเพื่อแยกระหว่างเครื่อง ค่าคงที่นี้

ตัวอย่าง

ไบนารีที่สร้างโดยคอมไพเลอร์ Clang ไม่ควรมีปัญหาเกี่ยวกับข้อมูล ที่มีการสอดประสานกันในโค้ด หากโค้ดที่สร้างโดย GNU Compiler Collection (GCC) รวม (จากไลบรารีแบบคงที่) ให้ตรวจสอบไบนารีของเอาต์พุตเพื่อ เพื่อให้มั่นใจว่าค่าคงที่ไม่ได้ถูกรวบรวมไว้ในส่วนโค้ด

หากจำเป็นต้องตรวจสอบโค้ดในส่วนโค้ดสั่งการ เรียก mprotect ครั้งแรกเพื่อทำเครื่องหมายว่าอ่านโค้ดได้ หลังจากดำเนินการแล้ว เสร็จแล้ว โปรดโทรหา mprotect อีกครั้งเพื่อทำเครื่องหมายว่าอ่านไม่ได้

เปิดใช้ XOM

การดำเนินการเท่านั้นเปิดใช้โดยค่าเริ่มต้นสำหรับไบนารี 64 บิตทั้งหมดในบิลด์ ระบบ

ปิดใช้ XOM

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

สามารถปิดใช้ XOM สำหรับแต่ละโมดูลที่ไม่สามารถเปลี่ยนโครงสร้างภายในโค้ดหรือต้องอ่าน โค้ดสั่งการ โดยการตั้งค่า LOCAL_XOM และ xom ตัวแปรไปยัง false

// Android.mk
LOCAL_XOM := false

// Android.bp
cc_binary { // or other module types
   ...
   xom: false,
}

หากปิดใช้หน่วยความจำสำหรับการดำเนินการเท่านั้นในไลบรารีแบบคงที่ ระบบจะใช้ระบบบิลด์ นี้กับโมดูลที่ขึ้นต่อกันทั้งหมดของไลบรารีแบบคงที่ คุณสามารถลบล้าง โดยใช้ xom: true,

หากต้องการปิดใช้หน่วยความจำสำหรับการดำเนินการเท่านั้นในไดเรกทอรีย่อยหนึ่งๆ (ตัวอย่างเช่น foo/bar/) ส่งค่าไปยัง XOM_EXCLUDE_PATHS

make -j XOM_EXCLUDE_PATHS=foo/bar

หรือคุณสามารถตั้งค่า PRODUCT_XOM_EXCLUDE_PATHS ในการกำหนดค่าผลิตภัณฑ์ของคุณได้

คุณสามารถปิดใช้ไบนารีสำหรับการดำเนินการเท่านั้นทั่วโลกได้โดยการส่งผ่าน ENABLE_XOM=false ลงในคำสั่ง make

make -j ENABLE_XOM=false

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

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