AddressSanitizer

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 از کتابخانه های ثابتی باشند که به آنها وابسته هستند.

اسناد پشتیبانی