AddressSanitizer (ASan) هي أداة سريعة تستند إلى التجميع لاكتشاف أخطاء الذاكرة في التعليمات البرمجية الأصلية.
يكتشف ASan ما يلي:
- تجاوز/تدفق المخزن المؤقت للتكديس وأجزاء من الذاكرة
- استخدام لقطات لأجزاء من الذاكرة بعد الفترة المجانية
- استخدام الحزمة خارج النطاق
- موقف سيارات مزدوج/بدون تكلفة
يعمل ASan على كل من معالِج ARM بإصدارَي 32 و64 بت، بالإضافة إلى x86 وx86-64. أعباء وحدة المعالجة المركزية في ASan أكبر بمرتين تقريبًا، ويتراوح حجم الرمز البرمجي بين 50% و2x، فضلاً عن حجم كبير من الذاكرة التي تحملها (يعتمد على أنماط التخصيص، ولكن بترتيب 2x).
يتيح كلّ من Android 10 والفرع الرئيسي من AOSP على AArch64 استخدام أداة AddressSanitizer (HWASan) المستندة إلى الأجهزة، وهي أداة مشابهة تستهلك ذاكرة وصول عشوائي أقل وترصد عددًا أكبر من الأخطاء. يرصد برنامج HWASan استخدام التكديس بعد الإرجاع، بالإضافة إلى الأخطاء التي اكتشفها ASan.
لدى HWASan أعباء مماثلة لوحدة المعالجة المركزية (CPU) وحجم الرموز، لكن حجم ذاكرة الوصول العشوائي أقل بكثير (%15). HWASan غير محدّد. لا تتوفّر سوى 256 قيمة محتملة للعلامات، لذا هناك احتمال بنسبة 0.4% بأن يتم تجاهل أي خطأ. لا تتضمّن أداة HWASan المناطق الحمراء ذات الحجم المحدود في أداة ASan لرصد حالات تجاوز الذاكرة ووضع العزل بسعة محدودة لرصد حالات الاستخدام بعد تحرير الذاكرة، وبالتالي لا يهمّ أداة HWASan حجم تجاوز الذاكرة أو المدة التي مضت على تحرير الذاكرة. وهذا يجعل HWASan أفضل من ASan. يمكنك الاطّلاع على مزيد من المعلومات حول تصميم HWASan أو حول استخدام HWASan على Android.
ترصد أداة ASan عمليات تجاوز الذاكرة في الحزمة/على مستوى التطبيق بالإضافة إلى عمليات تجاوز الذاكرة في الحِزمة، وهي سريعة وتستهلك الحد الأدنى من الذاكرة.
يوضّح هذا المستند كيفية تصميم أجزاء من Android أو كل أجهزة Android وتشغيلها باستخدام ASan. إذا كنت بصدد إنشاء تطبيق حزمة تطوير برامج (SDK) أو حزمة تطوير تطبيقات (NDK) باستخدام أداة ASan، يمكنك الاطّلاع على أداة فحص العناوين بدلاً من ذلك.
تنظيف الملفات التنفيذية الفردية باستخدام ASan
إضافة LOCAL_SANITIZE:=address
أو sanitize: { address: true }
إلى
قاعدة الإصدار للملف التنفيذي. ويمكنك البحث في التعليمات البرمجية عن أمثلة حالية أو البحث عن
معطقمات التنظيف الأخرى المتاحة.
عند اكتشاف خطأ، يطبع ASan تقريرًا مطوَّلاً إلى المعيار
إلى logcat
ثم تعطل العملية.
إزالة البيانات غير الصالحة من المكتبات المشتركة باستخدام ASan
نظرًا للطريقة التي تعمل بها ASan، لا يمكن استخدام المكتبة التي تم إنشاؤها باستخدام ASan إلا بواسطة قابل للتنفيذ تم إنشاؤه باستخدام ASan.
لتنظيف مكتبة مشتركة يتم استخدامها في عدة ملفات تنفيذية، وليس جميع
التي تم إنشاؤها باستخدام ASan، تحتاج إلى نسختين من المكتبة. تشير رسالة الأشكال البيانية
الطريقة الموصى بها لإجراء ذلك هي إضافة ما يلي إلى Android.mk
للوحدة النمطية المعنية:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
يؤدي ذلك إلى وضع المكتبة في /system/lib/asan
بدلاً من
/system/lib
. بعد ذلك، يمكنك تشغيل الملف التنفيذي باستخدام:
LD_LIBRARY_PATH=/system/lib/asan
بالنسبة إلى البرامج الخفيّة للنظام، أضف ما يلي إلى القسم المناسب من
/init.rc
أو /init.$device$.rc
setenv LD_LIBRARY_PATH /system/lib/asan
تحقق من أن العملية تستخدم مكتبات من /system/lib/asan
عند توفّرها من خلال قراءة /proc/$PID/maps
. إذا لم يكن الأمر كذلك، قد تحتاج إلى
إيقاف SELinux:
adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID # if it is a system service, or may be adb shell stop; adb shell start.
تحسين عمليات تتبُّع تسلسل استدعاء الدوال البرمجية
يستخدم ASan أداة إلغاء سريعة مستندة إلى مؤشر الإطار لتسجيل تكديس لكل حدث تخصيص للذاكرة وترتيب في البرنامج. معظم الأقسام في نظام Android بدون مؤشرات عرض الإطارات. نتيجة لذلك، غالبًا ما إطار أو إطارين ذي معنى. لحل هذه المشكلة، يمكنك إما إعادة إنشاء المكتبة باستخدام ASan (موصى به!)، أو مع:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
أو ضبط ASAN_OPTIONS=fast_unwind_on_malloc=0
في العملية
محددة. قد يكون هذا الأخير مستهلكًا للغاية لوحدة المعالجة المركزية، اعتمادًا على
التحميل.
الترميز
في البداية، تحتوي تقارير ASan على إشارات إلى الموضع في الملفات الثنائية والمكتبات المشترَكة. هناك طريقتان للحصول على معلومات ملف المصدر والسطر:
- تأكَّد من توفّر ملف
llvm-symbolizer
الثنائي في/system/bin
. تم إنشاءllvm-symbolizer
من مصادر فيthird_party/llvm/tools/llvm-symbolizer
. - فلترة التقرير من خلال
external/compiler-rt/lib/asan/scripts/symbolize.py
البرنامج النصي.
يمكن أن يوفّر النهج الثاني المزيد من البيانات (أي file:line
موقعًا جغرافيًا) بسبب
توفّر المكتبات الرمزية على المضيف.
ASan في التطبيقات
لا يمكن لأداة ASan الاطّلاع على رمز Java، ولكن يمكنها رصد الأخطاء في مكتبات JNI
. ولتنفيذ ذلك، تحتاجون إلى إنشاء ملف قابل للتنفيذ باستخدام ASan، والذي
هذا الطلب هو /system/bin/app_process(32|64)
. هذا النمط
لتمكين ASan في جميع التطبيقات على الجهاز في نفس الوقت، وهو
ولكن من المفترض أن يتمكن الجهاز المزوّد بذاكرة وصول عشوائي (RAM) بسعة 2 غيغابايت من معالجة هذا الإجراء.
أضِف LOCAL_SANITIZE:=address
إلى
قاعدة الإنشاء app_process
في frameworks/base/cmds/app_process
. تجاهل
استهداف app_process__asan
في الملف نفسه في الوقت الحالي (إذا كان
لا يزال متوفّرًا في وقت قراءة هذه المقالة).
عدِّل قسم service zygote
منملفsystem/core/rootdir/init.zygote(32|64).rc
المناسب لإضافة السطور التالية إلى مجموعة الأسطر المُعدَّلة المسافة بينها والتي تحتوي على class main
، مع تعديل المسافة بينها أيضًا بالقدر نفسه:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
إنشاء ومزامنته مع adb وبدء تشغيل fastboot flash وإعادة التشغيل
استخدام سمة wrap
النهج الموجود في القسم السابق يضع ASan في كل في النظام (في الواقع، في كل عنصر تابع لـ Zygote العملية). من الممكن تشغيل تطبيق واحد (أو أكثر) باستخدام ميزة ASan، تداول بعض أعباء الذاكرة لبدء تشغيل التطبيق بشكل أبطأ.
ويمكن إجراء ذلك من خلال بدء تطبيقك باستخدام الموقع wrap.
.
يُجري المثال التالي تشغيل تطبيق Gmail ضمن ASan:
adb root
adb shell setenforce 0 # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"
في هذا السياق، تتم إعادة كتابة /system/bin/app_process
من قِبل "asanwrapper
".
إلى /system/bin/asan/app_process
، التي تم إنشاؤها باستخدام
ASan. ويضيف أيضًا /system/lib/asan
في بداية
مسار البحث في المكتبة الديناميكية. بهذه الطريقة تعزف موسيقى ASan
من المكتبات من /system/lib/asan
هي المفضّلة للمكتبات العادية.
في /system/lib
عند التشغيل مع asanwrapper
.
في حال العثور على خطأ، يتعطّل التطبيق ويتم طباعة التقرير في السجلّ.
SANITIZE_TARGET
يشمل الإصدار 7.0 من Android والإصدارات الأحدث دعمًا لإنشاء نظام Android الأساسي بأكمله باستخدام ASan مرة واحدة. (إذا كنت بصدد إنشاء إصدار أحدث من Android 9، يُعدّ HWASan خيارًا أفضل.)
نفِّذ الأوامر التالية في شجرة التصميم نفسها.
make -j42
SANITIZE_TARGET=address make -j42
في هذا الوضع، يحتوي userdata.img
على مكتبات إضافية ويجب
فلاشها على الجهاز أيضًا. استخدِم سطر الأوامر التالي:
fastboot flash userdata && fastboot flashall
يؤدي هذا إلى إنشاء مجموعتين من المكتبات المشتركة: عادةً ما تكون
"/system/lib
" (أول استدعاء) وتعزف "أسان" في
/data/asan/lib
(الاستدعاء الثاني). يمكن تنفيذها من
فإن الإصدار الثاني يحل محلها من الإصدار الأول. تحصل ملفات exes التي تم تجهيزها باستخدام ASan على مسار بحث مكتبة مختلف يتضمّن /data/asan/lib
قبل /system/lib
من خلال استخدام /system/bin/linker_asan
في PT_INTERP
.
يخترق نظام التصميم دلائل الكائنات الوسيطة عند
تم تغيير قيمة $SANITIZE_TARGET
. يؤدي هذا إلى إعادة إنشاء كل
المستهدفة مع الاحتفاظ بالثنائيات المثبَّتة ضمن /system/lib
.
لا يمكن إنشاء بعض الاستهدافات باستخدام ASan:
- ملفات تنفيذية مرتبطة بشكل ثابت
- هدفان (
LOCAL_CLANG:=false
) - لم يتم استخدام
LOCAL_SANITIZE:=false
مع معايير ASan لـSANITIZE_TARGET=address
يتم تخطي الملفات التنفيذية مثل هذه في إصدار SANITIZE_TARGET
،
من عملية الاستدعاء الأولى التي سيتم الاحتفاظ بها في /system/bin
.
يتم إنشاء مكتبات مثل هذه بدون ASan. يمكن أن تحتوي على بعض ASan من المكتبات الثابتة التي تعتمد عليها.