จำนวนเต็มล้นโดยไม่ได้ตั้งใจอาจทำให้เกิดความเสียหายของหน่วยความจำหรือช่องโหว่การเปิดเผยข้อมูลในตัวแปรที่เกี่ยวข้องกับการเข้าถึงหน่วยความจำหรือการจัดสรรหน่วยความจำ เพื่อต่อสู้กับสิ่งนี้ เราได้เพิ่ม UndefinedBehaviorSanitizer (UBSan) ของ Clang ที่ลงนามและไม่ได้ลงนามเพื่อเสริมความแข็งแกร่งให้ กับเฟรมเวิร์กสื่อ ใน Android 7.0 ใน Android 9 เรา ได้ขยาย UBSan เพื่อให้ครอบคลุมส่วนประกอบต่างๆ มากขึ้น และรองรับระบบบิลด์ที่ได้รับการปรับปรุง
สิ่งนี้ออกแบบมาเพื่อเพิ่มการตรวจสอบเกี่ยวกับการดำเนินการ / คำแนะนำทางคณิตศาสตร์ ซึ่งอาจล้น เพื่อยกเลิกกระบวนการอย่างปลอดภัยหากมีการล้นเกิดขึ้น น้ำยาฆ่าเชื้อเหล่านี้สามารถบรรเทาความเสียหายของหน่วยความจำทั้งคลาสและช่องโหว่การเปิดเผยข้อมูล โดยที่สาเหตุที่แท้จริงคือจำนวนเต็มล้น เช่น ช่องโหว่ Stagefright ดั้งเดิม
ตัวอย่างและที่มา
Integer Overflow Sanitization (IntSan) ถูกจัดเตรียมโดยคอมไพเลอร์และเพิ่มเครื่องมือวัดลงในไบนารีในช่วงเวลาคอมไพล์เพื่อตรวจหาโอเวอร์โฟลว์ทางคณิตศาสตร์ โดยค่าเริ่มต้นจะเปิดใช้งานในองค์ประกอบต่างๆ ทั่วทั้งแพลตฟอร์ม เช่น /platform/external/libnl/Android.bp
การดำเนินการ
IntSan ใช้น้ำยาฆ่าเชื้อโอเวอร์โฟลว์จำนวนเต็มที่มีลายเซ็นและไม่ได้ลงนามของ UBSan การลดผลกระทบนี้เปิดใช้งานในระดับสำหรับแต่ละโมดูล ช่วยให้ส่วนประกอบที่สำคัญของ Android ปลอดภัยและไม่ควรปิดใช้งาน
เราขอแนะนำให้คุณเปิดใช้งาน Integer Overflow Sanitization สำหรับส่วนประกอบเพิ่มเติม ตัวเลือกที่เหมาะสมที่สุดคือรหัสเนทีฟที่มีสิทธิพิเศษหรือรหัสเนทีฟที่แยกวิเคราะห์อินพุตของผู้ใช้ที่ไม่น่าเชื่อถือ มีค่าใช้จ่ายด้านประสิทธิภาพเล็กน้อยที่เกี่ยวข้องกับการฆ่าเชื้อซึ่งขึ้นอยู่กับการใช้รหัสและความชุกของการดำเนินการทางคณิตศาสตร์ คาดหวังเปอร์เซ็นต์ค่าโสหุ้ยเล็กน้อยและทดสอบว่าประสิทธิภาพเป็นปัญหาหรือไม่
รองรับ IntSan ใน makefiles
ในการเปิดใช้งาน IntSan ใน makefile ให้เพิ่ม:
LOCAL_SANITIZE := integer_overflow # Optional features LOCAL_SANITIZE_DIAG := integer_overflow LOCAL_SANITIZE_BLACKLIST := modulename_blacklist.txt
-
LOCAL_SANITIZE
ใช้รายการน้ำยาฆ่าเชื้อที่คั่นด้วยเครื่องหมายจุลภาค โดยที่integer_overflow
เป็นชุดตัวเลือกที่บรรจุไว้ล่วงหน้าสำหรับน้ำยาฆ่าเชื้อสำหรับโอเวอร์โฟลว์จำนวนเต็มที่มีลายเซ็นและไม่ได้ลงชื่อพร้อม บัญชีดำเริ่มต้น -
LOCAL_SANITIZE_DIAG
เปิดโหมดการวินิจฉัยสำหรับน้ำยาฆ่าเชื้อ ใช้โหมดการวินิจฉัยในระหว่างการทดสอบเท่านั้น เนื่องจากการดำเนินการนี้จะไม่ยกเลิกเมื่อโอเวอร์โฟลว์ ซึ่งจะลบล้างข้อได้เปรียบด้านความปลอดภัยของการบรรเทาผลกระทบโดยสิ้นเชิง ดูการ แก้ไขปัญหา สำหรับรายละเอียดเพิ่มเติม -
LOCAL_SANITIZE_BLACKLIST
อนุญาตให้คุณระบุไฟล์บัญชีดำเพื่อป้องกันไม่ให้ฟังก์ชันและไฟล์ต้นฉบับถูกฆ่าเชื้อ ดูการ แก้ไขปัญหา สำหรับรายละเอียดเพิ่มเติม
หากคุณต้องการการควบคุมที่ละเอียดยิ่งขึ้น ให้เปิดใช้งานเครื่องฆ่าเชื้อทีละรายการโดยใช้แฟล็กหนึ่งหรือทั้งสอง:
LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow
รองรับ IntSan ในไฟล์พิมพ์เขียว
หากต้องการเปิดใช้งานการล้างข้อมูลจำนวนเต็มล้นในไฟล์พิมพ์เขียว เช่น /platform/external/libnl/Android.bp
ให้เพิ่ม:
sanitize: { integer_overflow: true, diag: { integer_overflow: true, }, blacklist: "modulename_blacklist.txt", },
เช่นเดียวกับไฟล์ make คุณสมบัติ integer_overflow
คือชุดตัวเลือกที่เตรียมไว้ล่วงหน้าสำหรับน้ำยาฆ่าเชื้อโอเวอร์โฟลว์จำนวนเต็มที่มีการลงชื่อและไม่ได้ลงชื่อแต่ละรายการด้วย บัญชีดำเริ่มต้น
ชุดคุณสมบัติการ diag
เปิดใช้งานโหมดการวินิจฉัยสำหรับน้ำยาฆ่าเชื้อ ใช้โหมดการวินิจฉัยระหว่างการทดสอบเท่านั้น โหมดการวินิจฉัยไม่ยกเลิกเมื่อโอเวอร์โฟลว์ ซึ่งขัดต่อข้อได้เปรียบด้านความปลอดภัยของการบรรเทาผลกระทบในบิลด์ผู้ใช้โดยสิ้นเชิง ดูการ แก้ไขปัญหา สำหรับรายละเอียดเพิ่มเติม
คุณสมบัติ blacklist
ช่วยให้สามารถระบุไฟล์บัญชีดำที่อนุญาตให้นักพัฒนาป้องกันไม่ให้ฟังก์ชันและไฟล์ต้นฉบับถูกฆ่าเชื้อ ดูการ แก้ไขปัญหา สำหรับรายละเอียดเพิ่มเติม
หากต้องการเปิดใช้งานเครื่องฆ่าเชื้อทีละรายการ ให้ใช้:
sanitize: { misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow"], diag: { misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow",], }, blacklist: "modulename_blacklist.txt", },
การแก้ไขปัญหา
หากคุณกำลังเปิดใช้งานการล้างข้อมูลโอเวอร์โฟลว์จำนวนเต็มในส่วนประกอบใหม่ หรืออาศัยไลบรารีแพลตฟอร์มที่มีการฆ่าเชื้อโอเวอร์โฟลว์จำนวนเต็ม คุณอาจพบปัญหาบางประการเกี่ยวกับโอเวอร์โฟลว์จำนวนเต็มที่ไม่เป็นพิษเป็นภัยที่ทำให้เกิดการยกเลิก คุณควรทดสอบส่วนประกอบที่เปิดใช้งานการฆ่าเชื้อเพื่อให้แน่ใจว่ามีน้ำล้นที่ไม่เป็นพิษเป็นภัย
หากต้องการค้นหา ยกเลิกที่เกิดจากการล้างข้อมูลในบิลด์ของผู้ใช้ ให้ค้นหา SIGABRT
ที่ขัดข้องด้วยข้อความ Abort ที่ระบุว่า UBSan ตรวจพบโอเวอร์โฟลว์ เช่น:
pid: ###, tid: ###, name: Binder:### >>> /system/bin/surfaceflinger <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'ubsan: sub-overflow'
การติดตามสแต็กควรมีฟังก์ชันที่ทำให้เกิดการยกเลิก อย่างไรก็ตาม โอเวอร์โฟลว์ที่เกิดขึ้นในฟังก์ชันแบบอินไลน์อาจไม่ปรากฏในการติดตามสแต็ก
เพื่อให้สามารถระบุสาเหตุหลักได้ง่ายขึ้น ให้เปิดใช้งานการวินิจฉัยในไลบรารีที่ทริกเกอร์การยกเลิกและพยายามทำให้เกิดข้อผิดพลาดซ้ำ เมื่อเปิดใช้งานการวินิจฉัย กระบวนการจะไม่ยกเลิก และจะทำงานต่อไปแทน การไม่ยกเลิกจะช่วยเพิ่มจำนวนโอเวอร์โฟลว์ที่ไม่เป็นพิษเป็นภัยในเส้นทางการดำเนินการเฉพาะ โดยไม่ต้องคอมไพล์ใหม่หลังจากแก้ไขข้อผิดพลาดแต่ละรายการ การวินิจฉัยสร้างข้อความแสดงข้อผิดพลาดซึ่งรวมถึงหมายเลขบรรทัดและไฟล์ต้นทางที่ทำให้เกิดการยกเลิก:
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')
เมื่อพบการดำเนินการเลขคณิตที่มีปัญหาแล้ว ตรวจสอบให้แน่ใจว่าการล้นนั้นไม่เป็นพิษเป็นภัยและตั้งใจ (เช่น ไม่มีนัยด้านความปลอดภัย) คุณสามารถแก้ไขการยกเลิกน้ำยาฆ่าเชื้อโดย:
- การปรับโครงสร้างโค้ดใหม่เพื่อหลีกเลี่ยงการโอเวอร์โฟลว์ ( ตัวอย่าง )
- ล้นอย่างชัดเจนผ่านฟังก์ชัน __builtin_*_overflow ของ Clang ( ตัวอย่าง )
- การปิดใช้งานการฆ่าเชื้อในฟังก์ชันโดยการระบุแอตทริบิวต์
no_sanitize
( ตัวอย่าง ) - การปิดใช้งานการฆ่าเชื้อของฟังก์ชันหรือไฟล์ต้นทางผ่านไฟล์บัญชีดำ ( ตัวอย่าง )
คุณควรใช้วิธีแก้ปัญหาที่ละเอียดที่สุด ตัวอย่างเช่น ฟังก์ชันขนาดใหญ่ที่มีการดำเนินการเลขคณิตจำนวนมากและการดำเนินการโอเวอร์โฟลว์เดียวควรมีการปรับโครงสร้างการดำเนินการเดียว แทนที่จะให้ฟังก์ชันทั้งหมดอยู่ในบัญชีดำ
รูปแบบทั่วไปที่อาจส่งผลให้เกิดการล้นอย่างไม่เป็นอันตราย ได้แก่:
- แคส ต์โดยปริยาย เมื่อเกิดโอเวอร์โฟลว์ที่ไม่ได้ลงชื่อก่อนที่จะส่งไปยังประเภทที่ลงชื่อ ( ตัวอย่าง )
- การลบรายการที่เชื่อมโยงซึ่งลดดัชนีลูปเมื่อลบ ( ตัวอย่าง )
- กำหนดประเภทที่ไม่ได้ลงนามเป็น -1 แทนการระบุค่าสูงสุดจริง ( ตัวอย่าง )
- ลูปที่ลดจำนวนเต็มที่ไม่ได้ลงนามในเงื่อนไข ( example , example )
ขอแนะนำให้นักพัฒนารับรองว่ากรณีที่น้ำยาฆ่าเชื้อตรวจพบว่าน้ำยาฆ่าเชื้อไม่เป็นพิษเป็นภัยจริง ๆ โดยไม่มีผลข้างเคียงหรือความปลอดภัยที่ไม่ได้ตั้งใจก่อนที่จะปิดใช้การฆ่าเชื้อ
ปิดการใช้งาน IntSan
คุณสามารถปิดใช้งาน IntSan ด้วยบัญชีดำหรือแอตทริบิวต์ของฟังก์ชัน ปิดใช้งานเท่าที่จำเป็นและเฉพาะเมื่อการจัดโครงสร้างโค้ดใหม่ไม่สมเหตุสมผล หรือหากมีค่าใช้จ่ายด้านประสิทธิภาพที่เป็นปัญหา
ดูเอกสารต้นน้ำ Clang สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการปิดใช้งาน IntSan ด้วย แอตทริบิวต์ของฟังก์ชัน และ การจัดรูปแบบไฟล์บัญชีดำ การขึ้นบัญชีดำควรกำหนดขอบเขตให้กับน้ำยาฆ่าเชื้อโดยเฉพาะโดยใช้ชื่อส่วนที่ระบุน้ำยาฆ่าเชื้อเป้าหมายเพื่อหลีกเลี่ยงผลกระทบต่อน้ำยาฆ่าเชื้ออื่นๆ
การตรวจสอบความถูกต้อง
ในปัจจุบัน ยังไม่มีการทดสอบ CTS สำหรับการฆ่าเชื้อแบบ Integer Overflow โดยเฉพาะ ตรวจสอบให้แน่ใจว่าการทดสอบ CTS ผ่านโดยมีหรือไม่มีการเปิดใช้งาน IntSan เพื่อตรวจสอบว่าไม่มีผลกระทบกับอุปกรณ์