ควบคุมความสมบูรณ์ของโฟลว์

ในปี 2016 ช่องโหว่ประมาณ 86% ใน Android เกี่ยวข้องกับความปลอดภัยของหน่วยความจำ ที่เกี่ยวข้อง ช่องโหว่ส่วนใหญ่ถูกแสวงหาประโยชน์โดยผู้โจมตีได้เปลี่ยนเกณฑ์ปกติ ควบคุมการทำงานของแอปเพื่อดำเนินกิจกรรมที่เป็นอันตรายตามใจชอบ สิทธิ์ทั้งหมดของแอปที่ถูกเจาะช่องโหว่ ควบคุมโฟลว์ Integrity (CFI) เป็นกลไกการรักษาความปลอดภัยที่ไม่อนุญาตให้มีการเปลี่ยนแปลง โฟลว์การควบคุมเดิมของไบนารีที่คอมไพล์แล้ว ทำให้ทำได้ยากขึ้นมาก เพื่อทำการโจมตีดังกล่าว

ใน Android 8.1 เราได้เปิดใช้ CFI ใน Media Stack ของ LLVM ใน Android 9 เราได้เปิดใช้ CFI ในคอมโพเนนต์อื่นๆ และเคอร์เนลด้วย CFI ของระบบคือ เปิดอยู่โดยค่าเริ่มต้น แต่คุณต้องเปิดใช้ CFI ของเคอร์เนล

CFI ของ LLVM ต้องมีการคอมไพล์ด้วย การเพิ่มประสิทธิภาพเวลาลิงก์ (LTO) LTO จะเก็บรักษาการแสดงบิตโค้ด LLVM ของไฟล์ออบเจ็กต์ไว้จนกว่า link-time ซึ่งทำให้คอมไพเลอร์ระบุเหตุผลได้ดีขึ้นว่าจะเพิ่มประสิทธิภาพใด สามารถดำเนินการได้ การเปิดใช้ LTO จะลดขนาดไบนารีสุดท้ายและปรับปรุง แต่จะเพิ่มเวลาคอมไพล์ ในการทดสอบบน Android ชุดค่าผสม ของ LTO และ CFI ก่อให้เกิดค่าใช้จ่ายและประสิทธิภาพของโค้ดที่ไม่สำคัญ ใน ทั้ง 2-3 เคสดีขึ้น

สำหรับรายละเอียดทางเทคนิคเพิ่มเติมเกี่ยวกับ CFI และการตรวจสอบเพื่อการควบคุมการส่งต่ออื่นๆ โปรดดูการออกแบบ LLVM เอกสารประกอบ

ตัวอย่างและแหล่งที่มา

CFI ได้มาจากคอมไพเลอร์และเพิ่มการใช้เครื่องมือลงในไบนารีระหว่าง เวลาคอมไพล์ เราสนับสนุน CFI ใน Toolchain ของ Clang และระบบบิลด์ของ Android ใน AOSP

CFI จะเปิดใช้งานโดยค่าเริ่มต้นสำหรับอุปกรณ์ Arm64 สำหรับชุดคอมโพเนนต์ใน /platform/build/target/product/cfi-common.mk นอกจากนี้ยังเปิดใช้โดยตรงในชุดคอมโพเนนต์สื่อ สร้างไฟล์/พิมพ์เขียว ไฟล์ เช่น /platform/frameworks/av/media/libmedia/Android.bp และ /platform/frameworks/av/cmds/stagefright/Android.mk

การใช้ CFI ของระบบ

CFI จะเปิดใช้โดยค่าเริ่มต้นหากคุณใช้ Clang และระบบบิลด์ของ Android จึงไม่ควรปิดใช้ CFI ช่วยให้ผู้ใช้ Android ปลอดภัย

อันที่จริงแล้ว เราขอแนะนำให้คุณเปิดใช้ CFI สำหรับองค์ประกอบเพิ่มเติม ตัวเลือกที่เหมาะสมคือโค้ดแบบเนทีฟที่เป็นสิทธิพิเศษ หรือรหัสแบบเนทีฟที่ประมวลผล อินพุตของผู้ใช้ที่ไม่น่าเชื่อถือ ถ้าคุณใช้ clang และระบบบิลด์ของ Android คุณจะสามารถ สามารถเปิดใช้ CFI ในคอมโพเนนต์ใหม่โดยการเพิ่ม 2-3 บรรทัดลงในไฟล์ที่คุณอัปโหลดหรือ ไฟล์พิมพ์เขียว

การสนับสนุน CFI ในดึงไฟล์

วิธีเปิดใช้ CFI ในไฟล์สร้าง เช่น /platform/frameworks/av/cmds/stagefright/Android.mk เพิ่ม: วันที่

LOCAL_SANITIZE := cfi
# Optional features
LOCAL_SANITIZE_DIAG := cfi
LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt

  • LOCAL_SANITIZE ระบุ CFI เป็นสารฆ่าเชื้อในช่วง งานสร้าง
  • LOCAL_SANITIZE_DIAG เปิดโหมดการวินิจฉัยสำหรับ CFI โหมดการวินิจฉัยจะพิมพ์ข้อมูลการแก้ไขข้อบกพร่องเพิ่มเติมใน Logcat ระหว่าง ข้อขัดข้อง ซึ่งเป็นประโยชน์ขณะพัฒนาและทดสอบบิลด์ สร้าง อย่าลืมนำโหมดการวินิจฉัยออกจากบิลด์เวอร์ชันที่ใช้งานจริง
  • LOCAL_SANITIZE_BLACKLIST อนุญาตให้คอมโพเนนต์เลือก ปิดใช้การวัดคุม CFI สำหรับแต่ละฟังก์ชันหรือไฟล์ต้นฉบับ คุณ สามารถใช้รายการที่ไม่อนุญาตเป็นวิธีสุดท้ายในการแก้ปัญหาใดๆ ที่แสดงต่อผู้ใช้ อาจไม่มีอยู่ในกรณีอื่น ดูรายละเอียดเพิ่มเติมได้ที่ ปิดใช้ CFI

การสนับสนุน CFI ในไฟล์พิมพ์เขียว

หากต้องการเปิดใช้ CFI ในไฟล์พิมพ์เขียว เช่น /platform/frameworks/av/media/libmedia/Android.bp เพิ่ม:

   sanitize: {
        cfi: true,
        diag: {
            cfi: true,
        },
        blacklist: "cfi_blacklist.txt",
    },

การแก้ปัญหา

หากคุณกำลังเปิดใช้ CFI ในคอมโพเนนต์ใหม่ คุณอาจพบปัญหาบางประการกับ ข้อผิดพลาดประเภทฟังก์ชันไม่ตรงกัน และประเภทโค้ดแอสเซมบลีไม่ตรงกัน ข้อผิดพลาด

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

หากต้องการแก้ไขปัญหานี้ ให้ตรวจสอบว่าฟังก์ชันที่เรียกใช้มีประเภทเดียวกับ ประกาศแบบคงที่ ต่อไปนี้เป็นตัวอย่าง CL 2 รายการ

อีกปัญหาหนึ่งที่เป็นไปได้คือการพยายามเปิดใช้ CFI ในโค้ดที่มีทางอ้อม การเรียกประชุม เนื่องจากไม่มีการพิมพ์โค้ดแอสเซมบลี จึงทำให้เกิดประเภท ไม่ตรงกัน

หากต้องการแก้ไขปัญหานี้ ให้สร้าง Wrapper ของโค้ดแบบเนทีฟสำหรับการเรียกใช้การประกอบแต่ละครั้ง แล้วระบุ รวมลายเซ็นฟังก์ชันเดียวกับเครื่องหมายการเรียกใช้ จากนั้น Wrapper จะ เรียกรหัสชุดประกอบโดยตรง เนื่องจากสาขาโดยตรงไม่ได้ใช้เครื่องวัด CFI (ไม่สามารถกำหนดใหม่ขณะรันไทม์ได้ จึงไม่ก่อให้เกิดความเสี่ยงด้านความปลอดภัย) วิธีนี้จะแก้ปัญหานี้ได้

หากมีฟังก์ชันการประกอบมากเกินไปและแก้ไขไม่ได้ทั้งหมด คุณจะทำสิ่งต่อไปนี้ได้ และขึ้นบัญชีดำฟังก์ชันทั้งหมดที่มีการเรียกการประกอบทางอ้อมด้วย นี่คือ ไม่แนะนำให้ทำเพราะจะปิดการตรวจสอบ CFI ในฟังก์ชันเหล่านี้ ซึ่งจะเป็นการเปิด พื้นที่การโจมตี

ปิดใช้ CFI

เราไม่พบโอเวอร์เฮดประสิทธิภาพใดๆ คุณจึงไม่ต้องปิดใช้ CFI อย่างไรก็ตาม หากส่งผลกระทบต่อผู้ใช้ คุณสามารถเลือกปิดใช้ CFI สำหรับฟังก์ชันหรือไฟล์แหล่งที่มาแต่ละรายการโดยระบุไฟล์รายการที่ไม่อนุญาตสำหรับ Sanitizer ในเวลาคอมไพล์ แบล็คลิสต์จะสั่งให้คอมไพเลอร์ปิดใช้ CFI การวัดคุมในพื้นที่ที่ระบุ

ระบบบิลด์ของ Android จะสนับสนุนแบล็คลิสต์ตามองค์ประกอบ (อนุญาตให้ คุณเลือกไฟล์ต้นฉบับหรือฟังก์ชันที่จะไม่ได้รับ CFI ของ Google) สำหรับทั้ง Make และ Soong สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับรูปแบบของ ไฟล์รายการที่ไม่อนุญาต โปรดดู อัปสตรีม แนบเอกสาร

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

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