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، وإعادة التشغيل.
استخدام خاصية الالتفاف
النهج الموجود في القسم السابق يضع 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
(الاستدعاء الثاني). يمكن تنفيذها من
فإن الإصدار الثاني يحل محلها من الإصدار الأول. العزف على الآلات الموسيقية على أسان
الملفات التنفيذية على مسار مختلف للبحث في المكتبة يتضمن
/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 من المكتبات الثابتة التي تعتمد عليها.