AddressSanitizer (ASan) هي أداة سريعة تعتمد على المترجم لاكتشاف أخطاء الذاكرة في الكود الأصلي.
يكتشف ASan:
- كومة وتجاوز سعة المخزن المؤقت / تحت التدفق
- استخدام كومة بعد مجانا
- كومة استخدام خارج النطاق
- ضعف الحرة / البرية الحرة
يعمل ASan على كل من ARM 32 بت و 64 بت ، بالإضافة إلى x86 و x86-64. تبلغ النفقات العامة لوحدة المعالجة المركزية من ASan تقريبًا 2x ، ويتراوح حجم الكود الزائد بين 50٪ و 2x ، ونفقات ذاكرة كبيرة (تعتمد على أنماط التخصيص الخاصة بك ، ولكن بترتيب 2x).
يدعم Android 10 وفرع AOSP الرئيسي على AArch64 ASan (HWASan) المسرع بالأجهزة ، وهو أداة مماثلة مع ذاكرة وصول عشوائي أقل ونطاق أكبر من الأخطاء المكتشفة. يكتشف HWASan استخدام المكدس بعد الإرجاع ، بالإضافة إلى الأخطاء التي اكتشفها ASan.
HWASan لديه نفس حجم وحدة المعالجة المركزية وحجم الكود ، ولكن ذاكرة RAM أقل بكثير (15٪). HWASan غير حتمي. لا يوجد سوى 256 قيمة علامة ممكنة ، لذلك هناك احتمال ثابت بنسبة 0.4٪ لفقدان أي خطأ. لا يحتوي HWASan على مناطق حمراء محدودة الحجم من ASan لاكتشاف التدفقات الزائدة والحجر الصحي ذي السعة المحدودة للكشف عن الاستخدام بعد الاستخدام ، لذلك لا يهم HWASan حجم الفائض أو المدة التي تم فيها إلغاء تخصيص الذاكرة. هذا يجعل HWASan أفضل من ASan. يمكنك قراءة المزيد حول تصميم HWASan أو حول استخدام HWASan على Android .
يكتشف ASan التدفقات المكدسة / الشاملة بالإضافة إلى تدفقات الكومة ، وهو سريع مع الحد الأدنى من الذاكرة الزائدة.
يصف هذا المستند كيفية إنشاء وتشغيل أجزاء / كل أجهزة Android باستخدام ASan. إذا كنت تقوم بإنشاء تطبيق SDK / NDK باستخدام ASan ، فراجع Address Sanitizer بدلاً من ذلك.
تعقيم الملفات التنفيذية الفردية باستخدام 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 في جميع التطبيقات الموجودة على الجهاز في نفس الوقت ، وهو حمل ثقيل ، ولكن يجب أن يكون الجهاز الذي يحتوي على ذاكرة وصول عشوائي سعتها 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"
في هذا السياق ، يعيد asanwrapper
كتابة /system/bin/app_process
إلى /system/bin/asan/app_process
، والذي تم إنشاؤه باستخدام ASan. يقوم أيضًا بإضافة /system/lib/asan
في بداية مسار البحث الديناميكي للمكتبة. وبهذه الطريقة تُفضل مكتبات ASan المزودة بوسائل من /system/lib/asan
على المكتبات العادية في /system/lib
عند التشغيل باستخدام asanwrapper
.
إذا تم العثور على خطأ ، فإن التطبيق يتعطل ، ويتم طباعة التقرير في السجل.
SANITIZE_TARGET
يتضمن Android 7.0 والإصدارات الأحدث دعمًا لإنشاء نظام Android الأساسي بالكامل باستخدام ASan في وقت واحد. (إذا كنت تقوم بإنشاء إصدار أعلى من Android 9 ، فإن HWASan هو خيار أفضل.)
قم بتشغيل الأوامر التالية في نفس شجرة البناء.
make -j42
SANITIZE_TARGET=address make -j42
في هذا الوضع ، يحتوي userdata.img
على مكتبات إضافية ويجب وميضه على الجهاز أيضًا. استخدم سطر الأوامر التالي:
fastboot flash userdata && fastboot flashall
هذا يبني مجموعتين من المكتبات المشتركة: عادي in /system/lib
(أول استدعاء) ، و ASan-Instrumented in /data/asan/lib
(الثاني يجعل استدعاء). الكتابة التنفيذية من البناء الثاني على تلك من البناء الأول. تحصل الملفات التنفيذية المجهزة بأدوات AS على مسار بحث مكتبة مختلف يتضمن /data/asan/lib
before /system/lib
من خلال استخدام /system/bin/linker_asan
في PT_INTERP
.
نظام البناء clobbers أدلة الكائنات الوسيطة عندما تتغير قيمة $SANITIZE_TARGET
. هذا يفرض إعادة بناء جميع الأهداف مع الحفاظ على الثنائيات المثبتة تحت /system/lib
.
لا يمكن بناء بعض الأهداف باستخدام ASan:
- الملفات التنفيذية المرتبطة إحصائيًا
-
LOCAL_CLANG:=false
-
LOCAL_SANITIZE:=false
ليس كما هو لـ SANITIZE_TARGETSANITIZE_TARGET=address
يتم تخطي ملفات تنفيذية مثل هذه في SANITIZE_TARGET
، ويتم ترك الإصدار من استدعاء الإجراء الأول في /system/bin
.
مكتبات مثل هذه مبنية بدون ASan. يمكن أن تحتوي على بعض رموز ASan من المكتبات الثابتة التي يعتمدون عليها.