يُجري UndefinedBehaviorSanitizer (UBSan) عمليات فحص في وقت الترجمة للبحث عن أنواع مختلفة من السلوك غير المحدَّد. على الرغم من أنّ أداة UBSan قادرة على رصد العديد من الأخطاء المتعلّقة بالسلوك غير المحدّد، يتيح Android ما يلي:
- المحاذاة
- قيمة منطقية (Bool)
- الحدود
- تعداد
- float-cast-overflow
- float-divide-by-zero
- عدد-صحيح-قسمة-على-صفر
- سمة غير صفرية
- خالية
- العودة
- returns-nonnull-attribute
- shift-base
- shift-exponent
- signed-integer-overflow
- لا يمكن الوصول
- unsigned-integer-overflow
- vla-bound
على الرغم من أنّ سلوك unsigned-integer-overflow ليس غير محدّد من الناحية الفنية، يتم تضمينه في أداة التطهير ويُستخدَم في العديد من وحدات Android، بما في ذلك مكوّنات mediaserver، للقضاء على أي ثغرات أمنية كامنة تتعلّق بoverflow للأعداد الصحيحة.
التنفيذ
في نظام إنشاء Android، يمكنك تفعيل UBSan على مستوى النظام أو على مستوى المشروع. لتفعيل أدوات فحص سلامة رمز التطبيقات (UBSan) على مستوى النظام، اضبط SANITIZE_TARGET في Android.mk. لتفعيل UBSan على مستوى كل وحدة، اضبط LOCAL_SANITIZE وحدِّد السلوكيات غير المحدَّدة التي تريد البحث عنها في Android.mk. مثلاً:
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_CFLAGS := -std=c11 -Wall -Werror -O0 LOCAL_SRC_FILES:= sanitizer-status.c LOCAL_MODULE:= sanitizer-status LOCAL_SANITIZE := alignment bounds null unreachable integer LOCAL_SANITIZE_DIAG := alignment bounds null unreachable integer include $(BUILD_EXECUTABLE)
وإعدادات المخطّط النموذجي المكافئ (Android.bp):
cc_binary { cflags: [ "-std=c11", "-Wall", "-Werror", "-O0", ], srcs: ["sanitizer-status.c"], name: "sanitizer-status", sanitize: { misc_undefined: [ "alignment", "bounds", "null", "unreachable", "integer", ], diag: { misc_undefined: [ "alignment", "bounds", "null", "unreachable", "integer", ], }, }, }
اختصارات UBSan
يتضمّن Android أيضًا اختصارَين، integer
و
default-ub
، لتفعيل مجموعة من أدوات التعقيم في الوقت نفسه. ويؤدي integer
إلى تفعيل integer-divide-by-zero
و
signed-integer-overflow
وunsigned-integer-overflow
.
يُفعِّل الخيار default-ub
عمليات التحقّق التي تواجه الحد الأدنى من مشاكل الأداء في المُجمِّع: bool, integer-divide-by-zero, return,
returns-nonnull-attribute, shift-exponent, unreachable and vla-bound
. يمكن استخدام
فئة أداة تطهير الأعداد الصحيحة مع SANITIZE_TARGET وLOCAL_SANITIZE،
في حين لا يمكن استخدام default-ub إلا مع SANITIZE_TARGET.
ميزة أفضل لإعداد تقارير الأخطاء
يُستخدَم UBSan التلقائي في Android لاستدعاء دالة محدّدة عند مواجهة سلوك غير محدّد. وتكون هذه الدالة هي abort تلقائيًا. ومع ذلك، اعتبارًا من تشرين الأول (أكتوبر) 2016، يتضمّن UBSan على Android مكتبة تشغيل اختيارية تُقدّم تقارير أخطاء أكثر تفصيلاً، بما في ذلك نوع السلوك غير المحدَّد الذي تم رصده ومعلومات عن الملف وخطوط الرموز المصدر. لتفعيل ميزة تسجيل الأخطاء باستخدام عمليات التحقّق من الأعداد الصحيحة، أضِف ما يلي إلى ملف Android.mk:
LOCAL_SANITIZE:=integer LOCAL_SANITIZE_DIAG:=integer
تفعِّل قيمة LOCAL_SANITIZE أداة التطهير أثناء عملية الإنشاء. تعمل دالة LOCAL_SANITIZE_DIAG على تفعيل وضع التشخيص لبرنامج التعقيم المحدّد. من الممكن ضبط LOCAL_SANITIZE وLOCAL_SANITIZE_DIAG على قيم مختلفة، ولكن لا يتم تفعيل سوى عمليات التحقّق الواردة في LOCAL_SANITIZE. إذا لم يتم تحديد عملية تحقّق في LOCAL_SANITIZE، ولكن تم تحديدها في LOCAL_SANITIZE_DIAG، لن يتم تفعيل عملية التحقّق ولن يتم عرض رسائل بيانات التشخيص.
في ما يلي مثال على المعلومات التي تقدّمها مكتبة وقت التشغيل UBSan:
pixel-xl:/ # sanitizer-status ubsan sanitizer-status/sanitizer-status.c:53:6: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'size_t' (aka 'unsigned long')
إزالة القيم غير الصالحة في الأعداد الصحيحة
يمكن أن تؤدي عمليات تجاوز الأعداد الصحيحة غير المقصودة إلى تلف الذاكرة أو ثغرات إفصاح عن المعلومات في المتغيّرات المرتبطة بالوصول إلى الذاكرة أو تخصيصها. لمواجهة هذه المشكلة، أضفنا أداة فحص أخطاء في Clang UndefinedBehaviorSanitizer (UBSan) لفحص أخطاء في القيم الصحيحة وغير الصحيحة للعدد الصحيح بهدف تعزيز أمان إطار عمل الوسائط في Android 7.0. في Android 9، وسّعنا نطاق استخدام UBSan ليشمل المزيد من المكوّنات وعزّزنا توافقه مع نظام الإنشاء.
تم تصميم هذا الإجراء لإضافة عمليات تحقّق حول العمليات الحسابية أو / التعليمات التي قد تؤدي إلى تجاوز الحدّ الأقصى، وذلك لإيقاف عملية بأمان في حال حدوث تجاوز. يمكن لهذه الأدوات تخفيف مجموعة كاملة من نقاط الضعف المتعلّقة بفساد الذاكرة وكشف المعلومات، حيث يكون السبب الأساسي هو حصول فائض في عدد الأعداد الكاملة ، مثل نقطة ضعف Stagefright الأصلية.
الأمثلة والمصدر
يقدّم المُجمِّع أداة فحص Integer Overflow Sanitization (IntSan) ويضيف
أداة فحص إلى الملف الثنائي أثناء وقت الترجمة لرصد التجاوزات الحسابية. ويتم تفعيلها تلقائيًا في مكوّنات مختلفة على مستوى
النظام الأساسي، على سبيل المثال
/platform/external/libnl/Android.bp
.
التنفيذ
يستخدم IntSan أداة UBSan لإزالة أخطاء تدفّق الأعداد الصحيحة الموقَّعة وغير الموقَّعة. يتم تفعيل تدابير التخفيف هذه على مستوى كل وحدة. ويساعد هذا الإجراء في الحفاظ على أمان المكوّنات المُهمّة في Android، ويجب عدم إيقافه.
ننصحك بشدة بتفعيل ميزة "التطهير من تدفّق الأعداد الصحيحة" لمكونات إضافية. وتشمل العناصر المعنيّة بشكلٍ مثالي الرموز البرمجية الأصلية المميّزة أو الرموز البرمجية الأصلية التي تُحلِّل إدخال المستخدم غير الموثوق به. هناك عبء صغير على الأداء مرتبط بالمُنظِّف يعتمد على استخدام الرمز البرمجي وانتشار العمليات الحسابية. من المتوقّع أن تكون النسبة المئوية للعمليات غير الضرورية صغيرة، ويمكنك اختبار ما إذا كان أداء التطبيق يشكّل مصدر قلق.
إتاحة IntSan في ملفات الإنشاء
لتفعيل IntSan في ملف makefile، أضِف ما يلي:
LOCAL_SANITIZE := integer_overflow # Optional features LOCAL_SANITIZE_DIAG := integer_overflow LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
- يتضمّن
LOCAL_SANITIZE
قائمة بالمعقّمات مفصولة بفواصل، وتكون السمةinteger_overflow
عبارة عن مجموعة من الخيارات معدّة مسبقًا للمعقّمات الكاملة الموقَّعة وغير الموقَّعة باستخدام قائمة حظر تلقائية. - يؤدي
LOCAL_SANITIZE_DIAG
إلى تفعيل وضع بيانات التشخيص لأجهزة التعقيم. لا تستخدِم وضع بيانات التشخيص إلا أثناء الاختبار لأنّه لن يؤدي إلى إيقاف عمليات التصعيد، ما يبطل تمامًا ميزة الأمان التي يوفّرها التخفيف. يمكنك الاطّلاع على تحديد المشاكل وحلّها للحصول على تفاصيل إضافية. - تسمح لك أداة
LOCAL_SANITIZE_BLOCKLIST
بتحديد ملف BLOCKLIST لمنع إزالة البرامج غير المرغوب فيها من الدوالّ والملفات المصدر. اطّلِع على تحديد المشاكل وحلّها للحصول على تفاصيل إضافية.
إذا أردت التحكّم بشكل أدق، يمكنك تفعيل أدوات التطهير بشكلٍ فردي باستخدام أحد العلامتَين التاليتَين أو كليهما:
LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow
إتاحة IntSan في ملفات المخططات
لتفعيل إزالة القيم غير الصالحة للعدد الصحيح في ملف مخطّط، مثل
/platform/external/libnl/Android.bp
،
أضِف ما يلي:
sanitize: { integer_overflow: true, diag: { integer_overflow: true, }, BLOCKLIST: "modulename_BLOCKLIST.txt", },
كما هو الحال مع ملفات make، تشكّل الخاصية integer_overflow
مجموعة من الخيارات المُجمَّعة مسبقًا
لأدوات فحص أخطاء تجاوز عدد الأعداد الصحيحة الموقَّعة وغير الموقَّعة الفردية
باستخدام قائمة حظر
تلقائية.
تتيح مجموعة الخصائص diag
وضع بيانات التشخيص لأجهزة
التعقيم. لا تستخدِم وضع بيانات التشخيص إلا أثناء الاختبار. لا يؤدي "وضع بيانات التشخيص" إلى
إيقاف عمليات التصعيد، ما ينفي تمامًا ميزة الأمان التي يوفّرها
التخفيف في إصدارات المستخدمين. اطّلِع على تحديد المشاكل وحلّها للحصول على تفاصيل إضافية.
تتيح سمة BLOCKLIST
تحديد ملف BLOCKLIST
الذي يسمح للمطوّرين بمنع إزالة محتوى الدوالّ وملفات المصدر
من الملفات. يمكنك الاطّلاع على تحديد المشاكل وحلّها للحصول على
تفاصيل إضافية.
لتفعيل المعقمات بشكلٍ فردي، استخدِم:
sanitize: { misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow"], diag: { misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow",], }, BLOCKLIST: "modulename_BLOCKLIST.txt", },
تحديد المشاكل وحلّها
في حال تفعيل ميزة إزالة بيانات تدفّق الأعداد الصحيحة في المكوّنات الجديدة، أو الاعتماد على مكتبات المنصة التي تم فيها إجراء عملية إزالة بيانات تدفّق الأعداد الصحيحة، قد تواجه بعض المشاكل المتعلّقة بتدفّق الأعداد الصحيحة غير الضارّ الذي يتسبب في عمليات الإيقاف. يجب اختبار المكوّنات مع تفعيل ميزة التطهير لضمان ظهور الزيادات غير الضارة.
للعثور على عمليات الإيقاف الناجمة عن التطهير في إصدارات المستخدمين، ابحث عن
SIGABRT
الأعطال التي تتضمّن رسائل إيقاف تشير إلى حدوث فائض تم رصده
بواسطة UBSan، مثل:
pid: ###, tid: ###, name: Binder:### >>> /system/bin/surfaceflinger <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'ubsan: sub-overflow'
من المفترض أن يتضمّن تتبع تسلسل استدعاء الدوال الدالة التي تتسبّب في الإيقاف، ومع ذلك، قد لا تكون حالات الزيادة التي تحدث في الدوال المضمّنة واضحة في تتبع تسلسل استدعاء الدوال.
لتحديد السبب الأساسي بسهولة أكبر، فعِّل بيانات التشخيص في المكتبة ابدأ عملية الإيقاف وحاول إعادة إظهار الخطأ. مع تفعيل بيانات التشخيص، لن يتم إلغاء العملية، بل ستتم مواصلة تنفيذها. يساعد عدم إلغاء التنفيذ في زيادة عدد عمليات الزيادة غير الضارّة في مسار تنفيذ معيّن بدون الحاجة إلى إعادة الترجمة بعد إصلاح كل خطأ. تُنشئ ميزة "بيانات التشخيص" رسالة خطأ تتضمّن رقم السطر وملف المصدر الذي يتسبب في إيقاف التنفيذ:
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')
بعد العثور على العملية الحسابية التي تتضمّن مشكلة، تأكَّد من أنّ عملية الزيادة المفاجئة غير ضارة ومقصودة (على سبيل المثال، لا تتضمّن أيّ آثار على الأمان). يمكنك معالجة توقُّف أداة التعقيم عن العمل باتّباع الخطوات التالية:
- إعادة صياغة الرمز البرمجي لتجنّب حدوث تدفّق بيانات زائد (مثال)
- حدوث تدفّق بيانات بشكل صريح من خلال دوال __builtin_*_overflow في Clang (مثال)
- إيقاف عملية التطهير في الدالة من خلال تحديد سمة
no_sanitize
(مثال) - إيقاف عملية تطهير وظيفة أو ملف مصدر من خلال ملف BLOCKLIST (مثال)
يجب استخدام الحل الأكثر دقة ممكنًا. على سبيل المثال، يجب إعادة صياغة العملية الفردية بدلاً من إدراج الدالة بالكامل في القائمة المحظورة في حال كانت الدالة كبيرة وتتضمّن العديد من العمليات الحسابية وعملية واحدة تؤدي إلى تجاوز الحد الأقصى.
تشمل الأنماط الشائعة التي قد تؤدي إلى حدوث تدفّقات جيدة ما يلي:
- عمليات التحويل الضمنية التي تحدث فيها زيادة غير موقَّعة قبل تحويلها إلى نوع موقَّع (مثال)
- عمليات حذف القائمة المرتبطة التي تنقص فهرس الحلقة عند الحذف (مثال)
- منح نوع غير موقَّع للقيمة -1 بدلاً من تحديد الحد الأقصى الفعلي للقيمة (مثال)
- الحلقات التي تنقص عددًا صحيحًا غير موقَّت في الشرط (مثال، مثال)
قبل إيقاف ميزة التطهير، ننصح المطوّرين بالتأكّد من أنّ الحالات التي يرصد فيها المنظِّف حدوث تدفّق زائد هي حالات غير ضارة بدون أيّ آثار جانبية أو تبعات أمنية غير مقصودة.
إيقاف IntSan
يمكنك إيقاف IntSan باستخدام قوائم الحظر أو سمات الدوالّ. يجب إيقاف هذه الميزة بشكل مقتصد فقط عندما يكون إعادة صياغة الرمز البرمجي غير معقولة أو في حال كانت هناك زيادة في وقت التنفيذ تؤدي إلى مشاكل.
اطّلِع على مستندات Clang الأصلية للحصول على مزيد من المعلومات عن إيقاف IntSan باستخدام سمات دالة وتنسيقملف BLOCKLIST. يجب أن يتم تحديد نطاق القائمة المحظورة على المعقّم المحدّد باستخدام أسماء الأقسام التي تحدّد المعقّم المستهدَف لتجنّب التأثير على المعقّمات الأخرى.
التحقُّق
لا يتوفّر حاليًا اختبار CTS مخصّص لفحص Integer Overflow Sanitization. بدلاً من ذلك، تأكَّد من اجتياز اختبارات CTS مع تفعيل IntSan أو بدونه للتحقّق من أنّه لا يؤثر في الجهاز.
تنظيف الحدود
يضيف BoundsSanitizer (BoundSan) أدوات قياس إلى الملفات الثنائية لإدراج عمليات التحقّق من الحدود حول عمليات الوصول إلى الصفيف. تتم إضافة عمليات التحقّق هذه إذا لم يتمكّن المُجمِّع من إثبات أنّ الوصول سيكون آمنًا في وقت الترجمة، وإذا كان حجم الصفيف سيكون معروفًا في وقت التشغيل، حتى يمكن التحقّق منه. ينشر نظام التشغيل Android 10 تقنية BoundSan في تقنيات الترميز والبلوتوث. يقدّم المُجمِّع BoundSan ويتم تفعيله بشكلٍتلقائي في مكونات مختلفة على مستوى المنصة.
التنفيذ
يستخدم BoundSan أداة تعقيم الحدود في UBSan. يتم تفعيل هذه الميزة على مستوى كل وحدة. ويساعد هذا الإجراء في الحفاظ على أمان المكوّنات المهمة في Android، ويجب عدم إيقافه.
ننصحك بشدة بتفعيل BoundSan للمكونات الإضافية. وتشمل العناصر المُقترَحة المثالية الرموز البرمجية الأصلية المميّزة أو الرموز البرمجية الأصلية المعقدة التي تُحلِّل إدخال المستخدم غير الموثوق به. تعتمد زيادة الأداء المرتبطة بتفعيل BoundSan على عدد عمليات الوصول إلى الصفيف التي لا يمكن إثبات أمانها. توقّع تسجيل نسبته مئوية صغيرة للنفقات العامة في المتوسّط، واختبر ما إذا كان الأداء يمثّل مصدر قلق.
تفعيل BoundSan في ملفات المخطّط
يمكن تفعيل BoundSan في ملفات المخطّط من خلال إضافة "bounds"
إلى سمة misc_undefined
sanitize للوحدات
الثنائية والمكتبات:
sanitize: { misc_undefined: ["bounds"], diag: { misc_undefined: ["bounds"], }, BLOCKLIST: "modulename_BLOCKLIST.txt",
diag
يُفعِّل الحقل diag
وضع بيانات التشخيص للأجهزة المعقمة.
لا تستخدِم وضع بيانات التشخيص إلا أثناء الاختبار. لا يُوقف وضع "بيانات التشخيص" عمليات المعالجة عند حدوث
عمليات تجاوز، ما ينفي ميزة الأمان التي توفّرها إجراءات التخفيف ويؤدي إلى
زيادة في وقت المعالجة، لذا لا يُنصح باستخدامه مع الإصدارات العلنية.
القائمة المحظورة
تسمح السمة BLOCKLIST
بتحديد ملف BLOCKLIST
يُمكن للمطوّرين استخدامه لمنع إزالة المحتوى غير المرغوب فيه من الدوالّ وملفات المصدر. لا تستخدِم هذه السمة إلا إذا كان الأداء يشكّل مصدر قلق وكانت الملفات أو الدوال المستهدفة تساهم بشكل كبير. تحقَّق يدويًا من هذه الملفات/الدوالّ
للتأكّد من أمان عمليات الوصول إلى الصفيف. اطّلِع على تحديد المشاكل وحلّها للحصول على مزيد من
التفاصيل.
تفعيل BoundSan في ملفات makefiles
يمكن تفعيل BoundSan في ملفات makefiles عن طريق إضافة "bounds"
إلى متغيّر LOCAL_SANITIZE
لوحدات المكتبة والثنائيات:
LOCAL_SANITIZE := bounds # Optional features LOCAL_SANITIZE_DIAG := bounds LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
يقبل LOCAL_SANITIZE
قائمة بالمعقّمات مفصولة بنقطة ملفتة.
LOCAL_SANITIZE_DIAG
يؤدي إلى تفعيل وضع بيانات التشخيص. استخدِم وضع التشخيص
أثناء الاختبار فقط. لا يُوقف "وضع بيانات التشخيص" عمليات التدفّق الزائد، ما يؤدي إلى إلغاء ميزة الأمان التي يوفّرها التخفيف من المخاطر ويؤدي إلى زيادة تكلفة الأداء، لذا لا يُنصح باستخدامه مع الإصدارات العلنية.
يسمح LOCAL_SANITIZE_BLOCKLIST
بتحديد ملف BLOCKLIST
يتيح للمطوّرين منع إزالة البيانات غير المرغوب فيها من الدوال وملفات المصدر. لا تستخدِم هذه السمة إلا إذا كان الأداء يشكّل مصدر قلق وكانت الملفات أو الدوال المستهدفة تساهم بشكل كبير. تحقَّق يدويًا من هذه الملفات/الدوالّ
للتأكّد من أمان عمليات الوصول إلى الصفيف. اطّلِع على تحديد المشاكل وحلّها للحصول على مزيد من
التفاصيل.
إيقاف BoundSan
يمكنك إيقاف BoundSan في الدوالّ وملفات المصدر باستخدام قوائم BLOCKLIST أوسمات الدوالّ. من الأفضل إبقاء BoundSan مفعّلاً، لذا لا يتم إيقافه إلا إذا كانت الدالة أو الملف تؤديان إلى زيادة كبيرة في وقت تنفيذ البرنامج وتمت مراجعة مصدرهما يدويًا.
لمزيد من المعلومات حول إيقاف BoundSan باستخدام سمات الدالة وتنسيق ملف BLOCKLIST، يُرجى الرجوع إلى مستندات Clang LLVM. يمكنك حصر عملية قيد الاشتباه في ملف الترشيح على المعقم المحدّد باستخدام أسماء الأقسام التي تحدّد المعقم المستهدف لتجنّب التأثير في المعقّمات الأخرى.
التحقُّق
لا يتوفّر اختبار CTS مخصّص لـ BoundSan. بدلاً من ذلك، تأكَّد من اجتياز اختبارات مجموعة أدوات اختبار التوافق (CTS) مع تفعيل BoundSan أو بدونه للتأكّد من أنّه لا يؤثر في الجهاز.
تحديد المشاكل وحلّها
اختبِر المكوّنات بدقة بعد تفعيل BoundSan للتأكّد من معالجة أي عمليات وصول خارج النطاق لم يتم رصدها في السابق.
يمكن بسهولة تحديد أخطاء BoundSan لأنّها تتضمّن الرسالة التالية: رسالة إيقاف السجلّ المؤقت:
pid: ###, tid: ###, name: Binder:### >>> /system/bin/foobar <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'ubsan: out-of-bounds'
عند التشغيل في وضع بيانات التشخيص، يتم طباعة الملف المصدر ورقم السطر وقيمته
logcat
. لا يؤدي هذا الوضع تلقائيًا إلى
إرسال رسالة إيقاف. راجِع logcat
للتحقّق من حدوث أي
أخطاء.
external/foo/bar.c:293:13: runtime error: index -1 out of bounds for type 'int [24]'