หน้านี้อธิบายปัญหาสำคัญและการแก้ไขข้อบกพร่องที่พบใน 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 *[]')
รายละเอียด: โปรแกรมตรวจสอบขอบเขตเป็นสิ่งจําเป็นในการปกป้องความสมบูรณ์ของเคอร์เนลโดยการตรวจหาการเข้าถึงที่อยู่นอกขอบเขต และเมื่อมีการเปิดใช้
CONFIG_UBSAN_TRAP
ตัวตรวจสอบขอบเขตจะทริกเกอร์เคอร์เนลแพนิคเมื่อพบรายการใดก็ตาม- เครื่องมือตรวจสอบขอบเขตเวอร์ชันเก่าจะตรวจสอบเฉพาะอาร์เรย์ขนาดคงที่ และไม่สามารถตรวจสอบอาร์เรย์ที่จัดสรรแบบไดนามิก เวอร์ชันใหม่ใช้แอตทริบิวต์
__counted_by
เพื่อกำหนดขอบเขตอาร์เรย์ที่รันไทม์ และตรวจหากรณีที่เข้าถึงนอกขอบเขตได้มากขึ้น อย่างไรก็ตาม ในบางกรณี ระบบจะเข้าถึงอาร์เรย์ก่อนที่จะตั้งค่าตัวแปรขนาด ซึ่งจะทริกเกอร์ตัวกรองขอบเขตและทำให้เกิดข้อผิดพลาดของเคอร์เนล หากต้องการแก้ไขปัญหานี้ ให้กำหนดขนาดของอาร์เรย์ทันทีหลังจากจัดสรรหน่วยความจำที่อยู่เบื้องหลัง ดังที่แสดงใน aosp/3343204
- เครื่องมือตรวจสอบขอบเขตเวอร์ชันเก่าจะตรวจสอบเฉพาะอาร์เรย์ขนาดคงที่ และไม่สามารถตรวจสอบอาร์เรย์ที่จัดสรรแบบไดนามิก เวอร์ชันใหม่ใช้แอตทริบิวต์
เกี่ยวกับ
CONFIG_UBSAN_SIGNED_WRAP
: Clang เวอร์ชันใหม่จะกรองค่าจำนวนเต็มที่มีเครื่องหมายที่เกินขอบเขตและต่ำกว่าขอบเขต แม้ว่าจะมี Flag คอมไพเลอร์-fwrapv
ก็ตาม Flag-fwrapv
ออกแบบมาเพื่อจัดการจำนวนเต็มแบบมีเครื่องหมายเป็นจำนวนเต็มแบบไม่แสดงเครื่องหมายแบบส่วนเติมเต็ม 2 ฐานที่มีลักษณะการทำงานที่โอเวอร์โฟลว์- แม้ว่าการกรองค่าที่เกินจำนวนเต็มที่มีเครื่องหมายในเคอร์เนล 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
- สรุป:
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 ต้องได้รับการตรวจสอบ รายการต่อไปนี้เป็นเพียงตัวอย่างบางส่วนของกรณีที่เราสังเกตได้
- การใช้งานหลังช่วงทดลองใช้ฟรี (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()
- การใช้งานหลังช่วงทดลองใช้ฟรี (UAF):
- การเปลี่ยนแปลงที่กล่าวถึงก่อนหน้านี้ได้รับการกู้คืนขณะที่ติดตั้ง Linux
6.12-rc4
(ดู aosp/3315251) ซึ่งเปิดใช้CONFIG_OF_DYNAMIC
อีกครั้งและอาจแสดงไดรเวอร์ที่มีข้อบกพร่อง
- สรุป: