GKI 16-6.12 android-mainline errata

หน้านี้อธิบายปัญหาสำคัญและการแก้ไขข้อบกพร่องที่พบใน android-mainline ซึ่งอาจมีความสำคัญต่อพาร์ทเนอร์

15 พฤศจิกายน 2024

  • อัปเดต Clang เป็น 19.0.1 สำหรับ android-mainline และ android16-6.12

    • สรุป: Clang เวอร์ชันใหม่มีการเพิ่ม Bounds Sanitizer สำหรับอาร์เรย์ ซึ่งขนาดของอาร์เรย์จะจัดเก็บไว้ในตัวแปรแยกต่างหากที่ลิงก์กับอาร์เรย์โดยใช้แอตทริบิวต์ __counted_by ฟีเจอร์นี้อาจทำให้เกิดเคอร์เนลแพนิก หากไม่ได้อัปเดตขนาดอาร์เรย์อย่างถูกต้อง ข้อความแสดงข้อผิดพลาดจะมีลักษณะดังนี้
    UBSAN: array-index-out-of-bounds in common/net/wireless/nl80211.c
    index 0 is out of range for type 'struct ieee80211_channel *[] __counted_by(n_channels)' (aka 'struct ieee80211_channel *[]')
    
    • รายละเอียด: Bounds Sanitizer มีความสำคัญอย่างยิ่งในการปกป้องความสมบูรณ์ของเคอร์เนลด้วยการตรวจหาการเข้าถึงนอกขอบเขต และเมื่อเปิดใช้ CONFIG_UBSAN_TRAP แล้ว Bounds Sanitizer จะทริกเกอร์เคอร์เนลแพนิกเมื่อตรวจพบ

      • Bounds Sanitizer เวอร์ชันก่อนหน้าตรวจสอบเฉพาะอาร์เรย์ที่มีขนาดคงที่และตรวจสอบอาร์เรย์ที่จัดสรรแบบไดนามิกไม่ได้ เวอร์ชันใหม่ใช้แอตทริบิวต์ __counted_by เพื่อกำหนดขอบเขตของอาร์เรย์ในรันไทม์และตรวจหาการเข้าถึงนอกขอบเขตได้มากขึ้น อย่างไรก็ตาม ในบางกรณี ระบบจะเข้าถึงอาร์เรย์ก่อนที่จะตั้งค่าตัวแปรขนาด ซึ่งจะทริกเกอร์ Bounds Sanitizer และทำให้เกิดเคอร์เนลแพนิก หากต้องการแก้ไขปัญหานี้ ให้ตั้งค่าขนาดของ อาร์เรย์ทันทีหลังจากจัดสรรหน่วยความจำพื้นฐาน ดังที่ แสดงใน aosp/3343204
    • เกี่ยวกับ CONFIG_UBSAN_SIGNED_WRAP: Clang เวอร์ชันใหม่จะล้างข้อมูลการล้นและการล้นกลับของจำนวนเต็มที่มีเครื่องหมาย แม้ว่าจะมีแฟล็กคอมไพเลอร์ -fwrapv ก็ตาม แฟล็ก -fwrapv ได้รับการออกแบบมาเพื่อจัดการจำนวนเต็มที่มีเครื่องหมายเป็นจำนวนเต็มที่ไม่มีเครื่องหมายแบบ Two's Complement ที่มีลักษณะการทำงานของการล้นที่กำหนดไว้

      • แม้ว่าการล้างข้อมูลการล้นของจำนวนเต็มที่มีเครื่องหมายในเคอร์เนล Linux จะช่วยระบุข้อบกพร่องได้ แต่ก็มีบางกรณีที่การล้นเป็นไปโดยเจตนา เช่น ใน atomic_long_t ด้วยเหตุนี้ เราจึงปิดใช้ CONFIG_UBSAN_SIGNED_WRAP has been disabled เพื่อให้ UBSAN ทำงานเป็น Bounds Sanitizer เท่านั้น
    • เกี่ยวกับ CONFIG_UBSAN_TRAP: เราได้กำหนดค่า UBSAN ให้ทริกเกอร์เคอร์เนลแพนิกเมื่อตรวจพบปัญหาเพื่อปกป้องความสมบูรณ์ของเคอร์เนล อย่างไรก็ตาม เราได้ปิดใช้ลักษณะการทำงานนี้ตั้งแต่วันที่ 23 ตุลาคม ถึง 12 พฤศจิกายน เราดำเนินการเช่นนี้เพื่อปลดบล็อกการอัปเดตคอมไพเลอร์ในขณะที่เราแก้ไขปัญหา __counted_by ที่ทราบ

1 พฤศจิกายน 2024

  • การรวม Linux 6.12-rc4
    • สรุป: CONFIG_OF_DYNAMIC อาจทำให้เกิดการถดถอยอย่างรุนแรงสำหรับไดรเวอร์ที่มีข้อบกพร่อง
    • รายละเอียด: ขณะรวม Linux 6.12-rc1 เข้ากับ android-mainline เราสังเกตเห็นปัญหาเกี่ยวกับไดรเวอร์นอกทรีที่ไม่โหลด เราพบว่าการเปลี่ยนแปลงที่ ทำให้เกิดข้อบกพร่องของไดรเวอร์คือการคอมมิต 274aff8711b2 ("clk: Add KUnit tests for clks registered with struct clk_parent_data") และเรา ได้ย้อนกลับการเปลี่ยนแปลงดังกล่าวชั่วคราวใน aosp/3287735 การเปลี่ยนแปลงดังกล่าวเลือก CONFIG_OF_OVERLAY ซึ่งเลือก CONFIG_OF_DYNAMIC เมื่อ !OF_DYNAMIC การนับการอ้างอิงใน of_node_get() และ of_node_put() จะถูกปิดใช้เนื่องจากมีการใช้งานเป็น noops การเปิดใช้ OF_DYNAMIC อีกครั้งจะทำให้เกิดปัญหาในไดรเวอร์ที่ใช้การนับการอ้างอิงสำหรับ struct device_node อย่างไม่ถูกต้อง ซึ่งทำให้เกิดข้อผิดพลาดประเภทต่างๆ เช่น หน่วยความจำเสียหาย การใช้งานหลังช่วงใช้ฟรี (Use After Free) และหน่วยความจำรั่วไหล
    • ต้องตรวจสอบการใช้ API ที่เกี่ยวข้องกับการแยกวิเคราะห์ OF ทั้งหมด รายการต่อไปนี้เป็นเพียงบางส่วน แต่มีกรณีที่เราสังเกตเห็น
      • การใช้งานหลังช่วงใช้ฟรี (Use After Free) (UAF):
        • การใช้การโต้แย้ง device_node เดียวกันซ้ำ: ฟังก์ชันเหล่านั้นเรียก of_node_put() ในโหนดที่กำหนด ซึ่งอาจต้องเพิ่ม of_node_get() ก่อนที่จะเรียกฟังก์ชันเหล่านั้น (เช่น เมื่อเรียกซ้ำๆ โดยใช้โหนดเดียวกันเป็นอาร์กิวเมนต์)
          • of_find_compatible_node()
          • of_find_node_by_name()
          • of_find_node_by_path()
          • of_find_node_by_type()
          • of_get_next_cpu_node()
          • of_get_next_parent()
          • of_get_next_child()
          • of_get_next_available_child()
          • of_get_next_reserved_child()
          • of_find_node_with_property()
          • of_find_matching_node_and_match()
        • การใช้ device_node หลังจากออกจากลูปบางประเภท
          • for_each_available_child_of_node_scoped()
          • for_each_available_child_of_node()
          • for_each_child_of_node_scoped()
          • for_each_child_of_node()
        • การเก็บพอยน์เตอร์โดยตรงไปยังพร็อพเพอร์ตี้ char * จาก device_node ไว้ เช่น การใช้
          • const char *foo = struct device_node::name
          • of_property_read_string()
          • of_property_read_string_array()
          • of_property_read_string_index()
          • of_get_property()
      • หน่วยความจำรั่วไหล:
        • การรับ device_node และลืมยกเลิกการอ้างอิง (of_node_put()) โหนดที่ส่งคืนจากฟังก์ชันเหล่านี้ต้องได้รับการปล่อยที่จุดใดจุดหนึ่ง
          • of_find_compatible_node()
          • of_find_node_by_name()
          • of_find_node_by_path()
          • of_find_node_by_type()
          • of_find_node_by_phandle()
          • of_parse_phandle()
          • of_find_node_opts_by_path()
          • of_get_next_cpu_node()
          • of_get_compatible_child()
          • of_get_child_by_name()
          • of_get_parent()
          • of_get_next_parent()
          • of_get_next_child()
          • of_get_next_available_child()
          • of_get_next_reserved_child()
          • of_find_node_with_property()
          • of_find_matching_node_and_match()
      • การเก็บ device_node จากการวนซ้ำของลูป หากคุณส่งคืนหรือออกจากฟังก์ชันต่อไปนี้ คุณต้องยกเลิกการอ้างอิงที่เหลือที่จุดใดจุดหนึ่ง
        • for_each_available_child_of_node()
        • for_each_child_of_node()
        • for_each_node_by_type()
        • for_each_compatible_node()
        • of_for_each_phandle()
    • เราได้กู้คืนการเปลี่ยนแปลงที่กล่าวถึงก่อนหน้านี้ขณะรวม Linux 6.12-rc4 (ดู aosp/3315251) ซึ่งจะเปิดใช้ CONFIG_OF_DYNAMIC อีกครั้งและอาจทำให้เกิดไดรเวอร์ที่มีข้อบกพร่อง