AdresSanitizer (ASan), yerel koddaki bellek hatalarını tespit etmek için hızlı, derleyici tabanlı bir araçtır.
ASan şunları tespit eder:
- Yığın ve yığın arabellek taşması/eksikliği
- Bedavadan sonra yığın kullanımı
- Kapsam dışında yığın kullanımı
- Çift özgür/vahşi özgür
ASan hem 32 bit hem de 64 bit ARM'nin yanı sıra x86 ve x86-64'te çalışır. ASan'ın CPU yükü kabaca 2 kat, kod boyutu yükü %50 ile 2 kat arasında ve büyük bir bellek yükü (tahsis düzenlerinize bağlı olarak ancak 2 kat civarında).
Android 10 ve AArch64'teki AOSP ana şubesi, daha düşük RAM yüküne 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üş sonrasında yığın kullanımını da tespit eder.
HWASan benzer CPU ve kod boyutu yüküne sahiptir ancak çok daha küçük bir RAM yüküne sahiptir (%15). HWASan belirleyici değildir. Yalnızca 256 olası etiket değeri vardır, dolayısıyla herhangi bir hatanın gözden kaçırılma olasılığı %0,4'tür. HWASan, taşmaları tespit etmek için ASan'ın sınırlı boyutlu kırmızı bölgelerine ve serbest kullanımdan sonra kullanımı tespit etmek için sınırlı kapasiteli karantinaya sahip değildir, bu nedenle taşmanın ne kadar büyük olduğu veya belleğin ne kadar zaman önce serbest bırakıldığı HWASan için önemli değildir. Bu HWASan'ı ASan'dan daha iyi kılar. HWASan'ın tasarımı veya HWASan'ın Android'de kullanımı hakkında daha fazla bilgi edinebilirsiniz.
ASan, yığın taşmalarının yanı sıra yığın/genel taşmalarını da algılar ve minimum bellek yüküyle hızlıdır.
Bu belgede ASan ile Android'in bazı bölümlerinin/tümünün nasıl oluşturulacağı ve çalıştırılacağı açıklanmaktadır. ASan ile bir SDK/NDK uygulaması oluşturuyorsanız bunun yerine Adres Temizleyici'ye bakın.
ASan ile bireysel yürütülebilir dosyaların temizlenmesi
Yürütülebilir dosyanın derleme kuralına LOCAL_SANITIZE:=address
veya sanitize: { address: true }
ekleyin. Mevcut örnekleri bulmak için kodda arama yapabilir veya mevcut diğer dezenfektanları bulabilirsiniz.
Bir hata tespit edildiğinde ASan, hem standart çıktıya hem de logcat
ayrıntılı bir rapor yazdırır ve ardından süreci çökertir.
ASan ile paylaşılan kütüphanelerin temizlenmesi
ASan'ın çalışma şekli nedeniyle, ASan ile oluşturulmuş bir kütüphane yalnızca ASan ile oluşturulmuş bir yürütülebilir dosya tarafından kullanılabilir.
Hepsi ASan ile oluşturulmamış birden fazla yürütülebilir dosyada kullanılan paylaşılan bir kitaplığı temizlemek için kitaplığın iki kopyasına ihtiyacınız vardır. Bunu yapmanın önerilen yolu, söz konusu modül için Android.mk
aşağıdakileri eklemektir:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
Bu, kütüphaneyi /system/lib yerine /system/lib
/system/lib/asan
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
dosyasının uygun bölümüne aşağıdakini 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 şununla 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 CPU'yu çok yoğun kullanabilir.
Sembolizasyon
Başlangıçta, ASan raporları ikili dosyalar ve paylaşılan kütüphanelerdeki uzaklıklara referanslar içerir. Kaynak dosya ve satır bilgilerini edinmenin iki yolu vardır:
-
llvm-symbolizer
ikili dosyasının/system/bin
dosyasında mevcut olduğ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ğiyle filtreleyin.
İkinci yaklaşım, ana bilgisayardaki sembolize edilmiş kitaplıkların kullanılabilirliği nedeniyle daha fazla veri (yani file:line
konumları) sağlayabilir.
Uygulamalarda ASan
ASan, Java kodunu göremez ancak JNI kitaplıklarındaki hataları tespit edebilir. Bunun için yürütülebilir dosyayı ASan ile oluşturmanız gerekir; bu durumda bu /system/bin/app_process( 32|64 )
. Bu, ASan'ın cihazdaki tüm uygulamalarda aynı anda etkinleştirilmesini sağlar, bu da ağır bir yüktür ancak 2 GB RAM'e sahip bir cihazın bunu kaldırabilmesi gerekir.
frameworks/base/cmds/app_process
içindeki app_process
derleme kuralına LOCAL_SANITIZE:=address
ekleyin. Şimdilik aynı dosyadaki app_process__asan
hedefini göz ardı edin (eğer 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 girintili satırlar bloğuna yine aynı miktarda girintili olan aşağıdaki satırları ekleyin:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
Oluşturma, adb senkronizasyonu, fastboot flash önyükleme ve yeniden başlatma.
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 daha fazla) uygulamayı çalıştırmak mümkündür, bu da uygulamanın daha yavaş başlatılması için bir miktar bellek yükünü değiştirir.
Bu, uygulamanızı wrap.
mülk. Aşağıdaki örnek, Gmail uygulamasını ASan altında çalıştırmaktadı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
dosyasına yeniden yazar. Ayrıca dinamik kitaplık arama yolunun başına /system/lib/asan
eklenir. Bu şekilde, asanwrapper
ile çalışırken /system/lib/asan
ASan-araçlı kütüphaneler /system/lib
normal kütüphanelere tercih edilir.
Bir hata bulunursa uygulama çöker ve rapor günlüğe yazdırılır.
SANITIZE_TARGET
Android 7.0 ve üzeri, ASan ile tüm Android platformunun aynı anda oluşturulması desteğini 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
ekstra kütüphaneler içerir ve cihaza da flashlanması gerekir. Aşağıdaki komut satırını kullanın:
fastboot flash userdata && fastboot flashall
Bu, iki grup paylaşılan kitaplık oluşturur: /system/lib
normal (ilk make çağrısı) ve /data/asan/lib
ASan-instrumented (ikinci make çağrısı). İkinci yapıdaki yürütülebilir dosyalar, ilk yapıdakilerin üzerine yazılır. ASan destekli 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 alır.
$SANITIZE_TARGET
değeri değiştiğinde derleme sistemi ara nesne dizinlerini gizler. Bu, /system/lib
altında yüklü ikili dosyaları 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't edilmedi
Bunun gibi yürütülebilir dosyalar SANITIZE_TARGET
yapısında atlanır ve ilk make çağrısındaki sürüm /system/bin
dosyasında bırakılır.
Bunun gibi kütüphaneler ASan olmadan inşa edilir. Bağlı oldukları statik kitaplıklardan bazı ASan kodlarını içerebilirler.