الخطأ GKI 16-6.12 في الخطأ الرئيسي في Android

توضّح هذه الصفحة المشاكل المهمة وإصلاحات الأخطاء التي تم رصدها في 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 أخطاء تجاوز حدود القيم الصغرى والكبرى للأرقام الكاملة الموقَّعة على الرغم من علامة المُجمِّع -fwrapv. تم تصميم العلامة -fwrapv لمعالجة الأعداد الصحيحة الموجبة والسالبة على أنّها تكميلية ومقترنة بسلوك محدّد للقيمة الزائدة.

      • على الرغم من أنّ إزالة تدفّق الأعداد الصحيحة الموقَّعة في نواة Linux يمكن أن يساعد في تحديد الأخطاء، هناك حالات يكون فيها تدفّق الأعداد الصحيحة مقصودًا، على سبيل المثال، مع atomic_long_t. نتيجةً لذلك، CONFIG_UBSAN_SIGNED_WRAP تم إيقافه للسماح لـ UBSAN بالعمل كمُنظِّف حدود فقط.
    • لمحة عن 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. ويؤدي ذلك إلى أنواع مختلفة من الأخطاء، مثل فساد الذاكرة واستخدام الذاكرة بعد تفريغها وتسرّب الذاكرة.
    • يجب فحص جميع استخدامات واجهات برمجة التطبيقات ذات الصلة بتحليل 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()
    • تم استعادة التغيير المذكور سابقًا أثناء طرح الإصدار 6.12-rc4 (راجِع aosp/3315251) لتفعيل CONFIG_OF_DYNAMIC مرة أخرى وربما الكشف عن برامج تشغيل يتضمّن أخطاء.