AdresDezenfektan

AddressSanitizer (ASan), yerel koddaki bellek hatalarını tespit etmek için derleyici tabanlı hızlı bir araçtır.

ASan şunları tespit eder:

  • Yığın ve yığın arabellek taşması/yetersizliği
  • Serbest kaldıktan sonra yığın kullanımı
  • Kapsam dışında yığın kullanımı
  • Çift serbest/vahşi serbest

ASan, hem 32 bit hem de 64 bit ARM ile x86 ve x86-64 üzerinde çalışır. ASan'ın CPU ek yükü kabaca 2x, kod boyutu ek yükü %50 ile 2x arasında ve büyük bir bellek ek yükü (tahsis modellerinize bağlıdır, ancak 2x mertebesinde).

AArch64'teki Android 10 ve AOSP ana dalı, daha düşük RAM ek yükü ve daha geniş bir algılanan hata yelpazesine sahip benzer bir araç olan donanım hızlandırmalı ASan'ı (HWASan) destekler. HWASan, ASan tarafından tespit edilen hatalara ek olarak dönüşten sonra yığın kullanımını tespit eder.

HWASan, benzer CPU ve kod boyutu ek yüküne sahiptir, ancak çok daha küçük bir RAM ek yüküne (%15) sahiptir. HWASan deterministik değildir. Yalnızca 256 olası etiket değeri vardır, dolayısıyla herhangi bir hatayı kaçırma olasılığı %0,4'tür. HWASan, taşmaları algılamak için ASan'ın sınırlı boyutlu kırmızı bölgelerine ve serbest kullanımdan sonra kullanımı algılamak için sınırlı kapasiteli karantinaya sahip değildir, bu nedenle HWASan için taşmanın ne kadar büyük olduğu veya belleğin ne kadar süre önce serbest bırakıldığı önemli değildir. Bu, HWASan'ı ASan'dan daha iyi yapar. HWASan'ın tasarımı veya HWASan'ın Android'de kullanımı hakkında daha fazla bilgi edinebilirsiniz.

ASan, yığın taşmalarına ek olarak yığın/genel taşmaları da algılar ve minimum bellek yüküyle hızlıdır.

Bu belge, Android'in bazı kısımlarını/tümünü ASan ile nasıl oluşturacağınızı ve çalıştıracağınızı açıklar. ASan ile bir SDK/NDK uygulaması oluşturuyorsanız bunun yerine Adres Temizleyici'ye bakın.

ASan ile bağımsız yürütülebilir dosyaları sterilize etme

Yürütülebilir dosya için oluşturma kuralına LOCAL_SANITIZE:=address veya sanitize: { address: true } ekleyin. Mevcut örnekler için kodda arama yapabilir veya mevcut diğer dezenfektanları bulabilirsiniz.

Bir hata algılandığında, ASan hem standart çıktıya hem de logcat ayrıntılı bir rapor yazdırır ve ardından işlemi çökertir.

ASan ile paylaşılan kitaplıkları temizleme

ASan'ın çalışma şekli nedeniyle, ASan ile oluşturulan bir kitaplık yalnızca ASan ile oluşturulmuş bir yürütülebilir dosya tarafından kullanılabilir.

Tamamı ASan ile oluşturulmayan birden çok yürütülebilir dosyada kullanılan paylaşılan bir kitaplığı sterilize etmek için kitaplığın iki kopyasına ihtiyacınız vardır. Bunu yapmanın önerilen yolu, söz konusu modül için aşağıdakini Android.mk eklemektir:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

Bu, kitaplığı /system/lib/asan yerine /system/lib içine yerleştirir. Ardından yürütülebilir dosyanızı şununla çalıştırın:

LD_LIBRARY_PATH=/system/lib/asan

Sistem arka plan programları için /init.rc veya /init.$device$.rc öğelerinin uygun bölümüne aşağıdakileri ekleyin.

setenv LD_LIBRARY_PATH /system/lib/asan

/proc/$PID/maps okuyarak, işlemin mevcut olduğunda /system/lib/asan kitaplıkları kullandığını doğrulayın. Değilse, SELinux'u devre dışı bırakmanız gerekebilir:

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.

Daha iyi yığın izleri

ASan, programdaki her bellek tahsisi ve serbest bırakma olayı için bir yığın izlemesi kaydetmek üzere hızlı, çerçeve işaretçisi tabanlı bir çözücü kullanır. Android'in çoğu çerçeve işaretçileri olmadan oluşturulmuştur. Sonuç olarak, genellikle yalnızca bir veya iki anlamlı çerçeve elde edersiniz. Bunu düzeltmek için kitaplığı ASan (önerilen!) ile veya şunu kullanarak yeniden oluşturun:

LOCAL_CFLAGS:=-fno-omit-frame-pointer
LOCAL_ARM_MODE:=arm

Veya işlem ortamında ASAN_OPTIONS=fast_unwind_on_malloc=0 ayarlayın. İkincisi, yüke bağlı olarak çok CPU yoğun olabilir.

simgeleştirme

Başlangıçta ASan raporları, ikili dosyalar ve paylaşılan kitaplıklardaki ofsetlere referanslar içerir. Kaynak dosya ve satır bilgilerini almanın iki yolu vardır:

  • llvm-symbolizer ikili dosyasının /system/bin içinde bulunduğundan emin olun. llvm-symbolizer third_party/llvm/tools/llvm-symbolizer içindeki kaynaklardan oluşturulmuştur.
  • Raporu external/compiler-rt/lib/asan/scripts/symbolize.py betiği aracılığıyla filtreleyin.

İkinci yaklaşım, ana bilgisayarda simgeleştirilmiş kitaplıkların mevcudiyeti nedeniyle daha fazla veri (yani file:line konumları) sağlayabilir.

Uygulamalarda ASan

ASan, Java kodunu göremez, ancak JNI kitaplıklarındaki hataları algılayabilir. Bunun için, bu durumda /system/bin/app_process( 32|64 ) olan ASan ile yürütülebilir dosyayı oluşturmanız gerekir. Bu, ASan'ı cihazdaki tüm uygulamalarda aynı anda etkinleştirir ki bu ağır bir yüktür, ancak 2 GB RAM'e sahip bir cihaz bunu kaldırabilmelidir.

frameworks/base/cmds/app_process içindeki app_process derleme kuralına LOCAL_SANITIZE:=address ekleyin. Şimdilik aynı dosyadaki app_process__asan hedefini yok sayın (bunu okuduğunuz sırada hala oradaysa).

Uygun system/core/rootdir/init.zygote( 32|64 ).rc dosyasının service zygote bölümünü düzenleyerek class main içeren ve yine aynı miktarda girintili olan girintili satırlar bloğuna aşağıdaki satırları ekleyin:

    setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib
    setenv ASAN_OPTIONS allow_user_segv_handler=true

Derleyin, adb senkronizasyonu yapın, hızlı önyükleme yapın ve yeniden başlatın.

sarma özelliğini kullanma

Önceki bölümdeki yaklaşım, ASan'ı sistemdeki her uygulamaya (aslında Zygote sürecinin her soyuna) yerleştirir. ASan ile yalnızca bir (veya birkaç) uygulama çalıştırmak, daha yavaş uygulama başlatma için bir miktar bellek yükü takas etmek mümkündür.

Bu, uygulamanızı wrap. mülk. Aşağıdaki örnek, Gmail uygulamasını ASan altında çalıştırır:

adb root
adb shell setenforce 0  # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"

Bu bağlamda asanwrapper /system/bin/app_process ASan ile oluşturulmuş /system/bin/asan/app_process olarak yeniden yazar. Ayrıca, dinamik kitaplık arama yolunun başına /system/lib/asan ekler. Bu şekilde, asanwrapper ile çalışırken /system/lib/asan ASan enstrümanlı kitaplıklar /system/lib normal kitaplıklara tercih edilir.

Bir hata bulunursa uygulama çöker ve rapor günlüğe yazdırılır.

SANITIZE_TARGET

Android 7.0 ve üstü, tüm Android platformunu ASan ile aynı anda oluşturmak için destek içerir. (Android 9'dan daha yüksek bir sürüm oluşturuyorsanız, HWASan daha iyi bir seçimdir.)

Aşağıdaki komutları aynı yapı ağacında çalıştırın.

make -j42
SANITIZE_TARGET=address make -j42

Bu modda, userdata.img fazladan kitaplıklar içerir ve cihaza da flash ile yüklenmelidir. Aşağıdaki komut satırını kullanın:

fastboot flash userdata && fastboot flashall

Bu, iki dizi paylaşılan kitaplık oluşturur: /system/lib içinde normal (ilk make çağrısı) ve /data/asan/lib içinde ASan-cihazlı (ikinci make çağrısı). İkinci yapıdaki yürütülebilir dosyalar, ilk yapıdakilerin üzerine yazılır. ASan-enstrümanlı yürütülebilir dosyalar, PT_INTERP / /system/bin/linker_asan /system/lib önce /data/asan/lib içeren farklı bir kitaplık arama yolu elde eder.

Yapı sistemi, $SANITIZE_TARGET değeri değiştiğinde ara nesne dizinlerini tıkar. Bu, kurulu ikili dosyaları /system/lib altında korurken tüm hedeflerin yeniden oluşturulmasını zorlar.

Bazı hedefler ASan ile oluşturulamaz:

  • Statik olarak bağlantılı yürütülebilir dosyalar
  • LOCAL_CLANG:=false hedefler
  • LOCAL_SANITIZE:=false SANITIZE_TARGET=address için ASan'lı değil

Bunun gibi yürütülebilir dosyalar SANITIZE_TARGET derlemesinde atlanır ve ilk make çağrısının sürümü /system/bin içinde bırakılır.

Bunun gibi kütüphaneler ASan olmadan inşa edilmiştir. Bağımlı oldukları statik kitaplıklardan bazı ASan kodları içerebilirler.

Destekleyici belgeler