AddressSanitizer (ASan) یک ابزار سریع مبتنی بر کامپایلر برای تشخیص اشکالات حافظه در کدهای بومی است.
ASan تشخیص می دهد:
- سرریز/زیر جریان بافر پشته و پشته
- استفاده از پشته پس از رایگان
- پشته استفاده خارج از محدوده
- دو برابر رایگان / وحشی رایگان
ASan روی ARM 32 بیتی و 64 بیتی به علاوه x86 و x86-64 اجرا می شود. سربار CPU ASan تقریباً 2 برابر است، سربار اندازه کد بین 50٪ تا 2x، و سربار حافظه بزرگ است (بسته به الگوهای تخصیص شما، اما به ترتیب 2x).
اندروید 10 و شعبه اصلی AOSP در AArch64 از AddressSanitizer با کمک سخت افزار (HWASan) پشتیبانی می کنند، ابزاری مشابه با سربار RAM کمتر و محدوده بزرگتری از باگ های شناسایی شده. HWASan استفاده از پشته را پس از بازگشت، علاوه بر باگ های شناسایی شده توسط ASan، شناسایی می کند.
HWASan دارای سربار پردازنده و اندازه کد مشابه است، اما سربار RAM بسیار کمتری (15%) دارد. HWASan غیر قطعی است. تنها 256 مقدار تگ ممکن وجود دارد، بنابراین احتمال 0.4 درصد از دست دادن هر گونه اشکال وجود دارد. HWASan مناطق قرمز با اندازه محدود ASan را برای تشخیص سرریزها و قرنطینه با ظرفیت محدود برای تشخیص استفاده پس از رایگان ندارد، بنابراین برای HWASan اهمیتی ندارد که سرریز چقدر بزرگ است یا چه مدت پیش حافظه اختصاص داده شده است. این باعث می شود HWASan بهتر از ASan باشد. میتوانید درباره طراحی HWASan یا استفاده از HWASan در اندروید بیشتر بخوانید.
ASan سرریزهای پشته/جهانی را علاوه بر سرریزهای پشته ای شناسایی می کند و با حداقل سرریز حافظه سریع است.
این سند نحوه ساخت و اجرای قطعات/تمام اندروید با ASan را شرح می دهد. اگر با ASan یک برنامه SDK/NDK میسازید، به جای آن 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
/asan قرار می دهد. سپس فایل اجرایی خود را با استفاده از:
LD_LIBRARY_PATH=/system/lib/asan
برای دیمون های سیستم، موارد زیر را به بخش مناسب /init.rc
یا /init.$device$.rc
اضافه کنید.
setenv LD_LIBRARY_PATH /system/lib/asan
با خواندن /proc/$PID/maps
بررسی کنید که فرآیند از کتابخانه های /system/lib/asan
استفاده می کند. اگر اینطور نیست، ممکن است لازم باشد 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 از یک بازگشایی سریع و مبتنی بر اشاره گر فریم برای ثبت یک ردیابی پشته برای هر تخصیص حافظه و رویداد تخصیص در برنامه استفاده می کند. بیشتر اندروید بدون نشانگر فریم ساخته شده است. در نتیجه، اغلب فقط یک یا دو فریم معنادار دریافت می کنید. برای رفع این مشکل، کتابخانه را با ASan بازسازی کنید (توصیه می شود!)، یا با:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
یا ASAN_OPTIONS=fast_unwind_on_malloc=0
در محیط فرآیند تنظیم کنید. بسته به بار، دومی می تواند بسیار CPU فشرده باشد.
نمادسازی
در ابتدا، گزارشهای 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 نمی تواند کدهای جاوا را ببیند، اما می تواند اشکالات موجود در کتابخانه های 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، بوت فلش فست بوت و راه اندازی مجدد.
از ویژگی 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
را در ابتدای مسیر جستجوی کتابخانه پویا اضافه می کند. به این ترتیب کتابخانه های دارای ابزار ASan از /system/lib/asan
به کتابخانه های معمولی در /system/lib
هنگام اجرا با asanwrapper
ترجیح داده می شوند.
اگر اشکالی پیدا شود، برنامه از کار می افتد و گزارش در گزارش چاپ می شود.
SANITIZE_TARGET
اندروید 7.0 و بالاتر شامل پشتیبانی از ساخت کل پلتفرم اندروید با ASan به صورت همزمان است. (اگر نسخهای بالاتر از اندروید 9 میسازید، HWASan انتخاب بهتری است.)
دستورات زیر را در همان درخت بیلد اجرا کنید.
make -j42
SANITIZE_TARGET=address make -j42
در این حالت، userdata.img
حاوی کتابخانه های اضافی است و باید به دستگاه نیز فلش شود. از خط فرمان زیر استفاده کنید:
fastboot flash userdata && fastboot flashall
این دو مجموعه از کتابخانه های مشترک ایجاد می کند: نرمال در /system/lib
(اولین فراخوانی make) و ASan-instrumented در /data/asan/lib
(دومین فراخوانی make). فایل های اجرایی از بیلد دوم آنهایی را که از بیلد اول هستند رونویسی می کنند. فایل های اجرایی با ابزار ASan یک مسیر جستجوی کتابخانه متفاوتی دریافت می کنند که شامل /data/asan/lib
قبل از /system/lib
با استفاده از /system/bin/linker_asan
در PT_INTERP
است.
هنگامی که مقدار $SANITIZE_TARGET
تغییر کرده است، سیستم ساخت، دایرکتوری های اشیاء میانی را تغییر می دهد. این باعث میشود که همه اهداف بازسازی شوند، در حالی که باینریهای نصب شده در /system/lib
حفظ میشوند.
برخی از اهداف را نمی توان با ASan ساخت:
- فایل های اجرایی با پیوند ایستا
-
LOCAL_CLANG:=false
-
LOCAL_SANITIZE:=false
برایSANITIZE_TARGET=address
ASan'd نمی شود
اجرایی مانند اینها در ساخت SANITIZE_TARGET
نادیده گرفته می شوند و نسخه از اولین فراخوانی make در /system/bin
باقی می ماند.
کتابخانه هایی مانند این بدون ASan ساخته می شوند. آنها می توانند حاوی مقداری کد ASan از کتابخانه های ثابتی باشند که به آنها وابسته هستند.