العنوان

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_TARGET SANITIZE_TARGET=address

يتم تخطي ملفات تنفيذية مثل هذه في SANITIZE_TARGET ، ويتم ترك الإصدار من استدعاء الإجراء الأول في /system/bin .

مكتبات مثل هذه مبنية بدون ASan. يمكن أن تحتوي على بعض رموز ASan من المكتبات الثابتة التي يعتمدون عليها.

الوثائق الداعمة