น้ำยาฆ่าเชื้อล้นจำนวนเต็ม

จำนวนเต็มล้นโดยไม่ได้ตั้งใจอาจทำให้เกิดความเสียหายของหน่วยความจำหรือช่องโหว่การเปิดเผยข้อมูลในตัวแปรที่เกี่ยวข้องกับการเข้าถึงหน่วยความจำหรือการจัดสรรหน่วยความจำ เพื่อต่อสู้กับสิ่งนี้ เราได้เพิ่ม 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 เพื่อตรวจสอบว่าไม่มีผลกระทบกับอุปกรณ์