مطهّر العنوان

أداة AddressSanitizer ‏ (ASan) هي أداة سريعة مستندة إلى المُجمِّع لرصد أخطاء الذاكرة في الرموز البرمجية الأصلية.

يرصد ASan ما يلي:

  • تجاوز/تدفق المخزن المؤقت للتكديس وأجزاء من الذاكرة
  • استخدام الذاكرة لأخذ لقطات لعناصر متعدّدة بعد تحريرها
  • استخدام التكديس خارج النطاق
  • رسوم مجانية مضاعفة/رسوم مجانية بدون قيود

تعمل تقنية ASan على كل من معالجات ARM بسعة 32 بت و64 بت، بالإضافة إلى الأجهزة المزوّدة بمعالجات x86 وx86-64. يبلغ معدل استخدام وحدة المعالجة المركزية (CPU) في ASan حوالي الضعف، ويتراوح حجم الرموز البرمجية بين 50% و2x، إضافةً إلى حجم كبير من الذاكرة (بناءً على أنماط التخصيص، ولكن بترتيب 2x).

يتوافق Android 10 والفرع الرئيسي لنظام AOSP على AArch64 مع أداة AddressSanitizer (HWASan) المتوافقة مع الأجهزة، وهي أداة مشابهة ذات أعباء أقل لذاكرة الوصول العشوائي (RAM) ومجموعة أكبر من الأخطاء التي يتم اكتشافها. ترصد أداة HWASan استخدام الحزمة بعد الرجوع، بالإضافة إلى الأخطاء التي رصدتها أداة ASan.

تستهلك تقنية HWASan مقدارًا مماثلاً من وحدة المعالجة المركزية وحجم الرمز البرمجي، ولكنّها تستهلك قدرًا أقل بكثير من ذاكرة الوصول العشوائي (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 إلا من خلال ملف executible تم إنشاؤه باستخدام 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 بدون مؤشرات عرض الإطارات. نتيجة لذلك، غالبًا ما تحصل على إطار أو إطارين مفيدين فقط. لحلّ هذه المشكلة، يمكنك إعادة إنشاء المكتبة باستخدام IDE IDE (يُنصح به) أو باستخدام:

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، وإعادة التشغيل.

استخدام سمة wrap

يضع النهج في القسم السابق 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 في بداية مسار البحث في المكتبة الديناميكية. بهذه الطريقة، يتم تفضيل مكتبات /system/lib/asan التي تم تجهيزها لأداة 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 (أول عملية استدعاء) وآلية ASan في /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 من المكتبات الثابتة التي تعتمد عليها.

المستندات الداعمة