หน้านี้อธิบายปัญหาสำคัญและการแก้ไขข้อบกพร่องที่พบใน android-mainline
ซึ่งอาจมีความสำคัญต่อพาร์ทเนอร์
15 พฤศจิกายน 2024
มีการอัปเดต Clang เป็น 19.0.1 สำหรับ
android-mainline
และandroid16-6.12
- สรุป: Clang เวอร์ชันใหม่มีเครื่องมือตรวจสอบขอบเขตสำหรับอาร์เรย์
ซึ่งจะจัดเก็บขนาดของอาร์เรย์ไว้ในตัวแปรแยกต่างหากที่ลิงก์กับอาร์เรย์
โดยใช้แอตทริบิวต์
__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 จะทริกเกอร์ Kernel Panic เมื่อพบข้อบกพร่อง- เวอร์ชันก่อนหน้าของ Bounds Sanitizer ตรวจสอบได้เฉพาะอาร์เรย์ที่มีขนาดคงที่
และตรวจสอบอาร์เรย์ที่จัดสรรแบบไดนามิกไม่ได้ เวอร์ชันใหม่ใช้แอตทริบิวต์
__counted_by
เพื่อกำหนดขอบเขตของอาร์เรย์ที่รันไทม์และ ตรวจหาการเข้าถึงที่อยู่นอกขอบเขตได้มากขึ้น อย่างไรก็ตาม ในบางกรณี ระบบจะเข้าถึงอาร์เรย์ ก่อนที่จะตั้งค่าตัวแปรขนาด ซึ่งจะทริกเกอร์ตัวตรวจสอบขอบเขต และทำให้เกิดข้อผิดพลาดระดับเคอร์เนล หากต้องการแก้ไขปัญหานี้ ให้ตั้งค่าขนาดของอาร์เรย์ทันทีหลังจากจัดสรรหน่วยความจำพื้นฐาน ดังที่แสดงใน aosp/3343204
- เวอร์ชันก่อนหน้าของ Bounds Sanitizer ตรวจสอบได้เฉพาะอาร์เรย์ที่มีขนาดคงที่
และตรวจสอบอาร์เรย์ที่จัดสรรแบบไดนามิกไม่ได้ เวอร์ชันใหม่ใช้แอตทริบิวต์
เกี่ยวกับ
CONFIG_UBSAN_SIGNED_WRAP
: Clang เวอร์ชันใหม่จะล้างข้อมูลการล้นและอันเดอร์โฟลว์ของจำนวนเต็มที่ลงชื่อ แม้จะมีแฟล็กคอมไพเลอร์-fwrapv
แฟล็ก-fwrapv
ออกแบบมาเพื่อถือว่าจำนวนเต็มที่มีเครื่องหมายเป็นส่วนเติมเต็มสอง จำนวนเต็มที่ไม่มีเครื่องหมายที่มีลักษณะการทำงานเมื่อเกิดโอเวอร์โฟลว์ที่กำหนด- แม้ว่าการล้างข้อมูลการล้นจำนวนเต็มที่ลงนามในเคอร์เนล Linux จะช่วย
ระบุข้อบกพร่องได้ แต่ก็มีบางกรณีที่การล้นเป็นไปโดยเจตนา เช่น ในกรณีของ
atomic_long_t
ด้วยเหตุนี้ เราจึงCONFIG_UBSAN_SIGNED_WRAP
ปิดใช้ เพื่ออนุญาตให้ UBSAN ทำงานเป็นตัวตรวจสอบขอบเขตเท่านั้น
- แม้ว่าการล้างข้อมูลการล้นจำนวนเต็มที่ลงนามในเคอร์เนล Linux จะช่วย
ระบุข้อบกพร่องได้ แต่ก็มีบางกรณีที่การล้นเป็นไปโดยเจตนา เช่น ในกรณีของ
เกี่ยวกับ
CONFIG_UBSAN_TRAP
: UBSAN ได้รับการกำหนดค่าให้ทริกเกอร์เคอร์เนลแพนิก เมื่อตรวจพบปัญหาเพื่อปกป้องความสมบูรณ์ของเคอร์เนล อย่างไรก็ตาม เราได้ปิดใช้ลักษณะการทำงานนี้ตั้งแต่23 ตุลาคมถึง12 พฤศจิกายน เราดำเนินการนี้เพื่อปลดบล็อกการอัปเดตคอมไพเลอร์ในขณะที่เราแก้ไขปัญหาที่ทราบ__counted_by
- สรุป: Clang เวอร์ชันใหม่มีเครื่องมือตรวจสอบขอบเขตสำหรับอาร์เรย์
ซึ่งจะจัดเก็บขนาดของอาร์เรย์ไว้ในตัวแปรแยกต่างหากที่ลิงก์กับอาร์เรย์
โดยใช้แอตทริบิวต์
1 พฤศจิกายน 2024
- Linux 6.12-rc4 landing
- สรุป:
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
อย่างไม่ถูกต้อง ซึ่งทำให้เกิดข้อผิดพลาดประเภทต่างๆ เช่น หน่วยความจำ เสียหาย การใช้งานหลังช่วงใช้ฟรี และหน่วยความจำรั่วไหล - การใช้ 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()
- Use after free (UAF)
- เราได้กู้คืนการเปลี่ยนแปลงที่กล่าวถึงก่อนหน้านี้ขณะที่เปิดตัว Linux
6.12-rc4
(ดู aosp/3315251) ซึ่งทำให้เปิดใช้CONFIG_OF_DYNAMIC
อีกครั้งและอาจเปิดเผยไดรเวอร์ที่มีข้อบกพร่อง
- สรุป: