AddressSanitizer (ASan) adalah alat cepat berbasis compiler untuk mendeteksi {i>bug memori<i} dalam kode native.
ASan dapat mendeteksi:
- Stack dan luapan/underflow buffer heap
- Penggunaan heap setelah tersedia
- Penggunaan stack di luar cakupan
- Double free/wild free
ASan dapat dijalankan pada ARM 32 bit dan 64 bit, serta x86 dan x86-64. Overhead CPU ASan kira-kira 2x, overhead ukuran kodenya antara 50% dan 2x, dan overhead memori yang besar (bergantung pada pola alokasi Anda, tetapi pada urutan 2x).
Android 10 dan cabang utama AOSP di AArch64 mendukung Hardware-assist AddressSanitizer (HWASan), alat serupa dengan {i>overhead<i} RAM yang lebih rendah dan berbagai bug yang terdeteksi. HWASan mendeteksi penggunaan stack setelah ditampilkan, selain bug terdeteksi oleh ASan.
HWASan memiliki overhead ukuran CPU dan kode yang serupa, tetapi overhead RAM yang jauh lebih kecil (15%). HWASan tidak dapat ditentukan. Hanya ada 256 kemungkinan nilai tag, jadi nilai rata-rata sebesar 0,4% kemungkinan hilangnya {i>bug<i} apa pun. HWASan tidak memiliki zona merah ukuran terbatas ASan untuk mendeteksi overflow dan karantina kapasitas terbatas untuk mendeteksi use-after-free, jadi tidak masalah bagi HWASan seberapa besar overflow atau berapa lama dibatalkan alokasinya. Ini membuat HWASan lebih baik daripada ASan. Anda dapat membaca selengkapnya tentang desain dari HWASan atau tentang penggunaan HWASan di Android.
ASan mendeteksi stack/overflow global sebagai tambahan heap overflow, dan cepat dengan overhead memori minimal.
Dokumen ini menjelaskan cara membangun dan menjalankan sebagian/semua Android dengan ASan. Jika Anda membangun aplikasi SDK/NDK dengan ASan, lihat Address Sanitizer sebagai gantinya.
Membersihkan setiap file yang dapat dieksekusi dengan ASan
Tambahkan LOCAL_SANITIZE:=address
atau sanitize: { address: true }
ke
aturan build untuk file yang dapat dieksekusi. Anda dapat menelusuri kode untuk contoh yang ada atau untuk menemukan
pembersih lainnya yang tersedia.
Saat bug terdeteksi, ASan akan mencetak laporan panjang ke
ke logcat
, lalu membuat proses error.
Membersihkan library bersama dengan ASan
Karena cara kerja ASan, perpustakaan yang dibangun dengan ASan hanya dapat digunakan oleh yang dapat dieksekusi yang dibangun dengan ASan.
Untuk membersihkan pustaka bersama yang digunakan
dalam banyak {i>executable<i}, tidak semua
yang dibuat dengan ASan, Anda memerlukan dua salinan library. Tujuan
cara yang direkomendasikan untuk melakukannya adalah dengan menambahkan kode berikut ke Android.mk
untuk modul yang dimaksud:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
Tindakan ini akan menempatkan library di /system/lib/asan
, bukan
/system/lib
. Kemudian, jalankan file yang dapat dieksekusi dengan:
LD_LIBRARY_PATH=/system/lib/asan
Untuk {i>daemon<i} sistem, tambahkan yang berikut ini
ke bagian yang sesuai dari
/init.rc
atau /init.$device$.rc
.
setenv LD_LIBRARY_PATH /system/lib/asan
Memastikan bahwa proses tersebut menggunakan library dari /system/lib/asan
saat ditampilkan dengan membaca /proc/$PID/maps
. Jika tidak, Anda mungkin perlu
untuk menonaktifkan 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.
Stack trace yang lebih baik
ASan menggunakan unwinder berbasis frame pointer yang cepat untuk merekam stack untuk setiap peristiwa alokasi dan dealokasi memori dalam program. Paling sering Android dibuat tanpa pointer frame. Akibatnya, Anda sering mendapatkan hanya satu atau dua {i>frame<i} yang bermakna. Untuk memperbaikinya, bangun ulang library dengan ASan (direkomendasikan!), atau dengan:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
Atau, tetapkan ASAN_OPTIONS=fast_unwind_on_malloc=0
dalam proses
lingkungan fleksibel App Engine. Yang terakhir bisa sangat membutuhkan
CPU, tergantung pada
beban tersebut.
Simbolisasi
Awalnya, laporan ASan berisi referensi ke offset dalam biner dan library. Ada dua cara untuk mendapatkan file sumber dan informasi baris:
- Pastikan biner
llvm-symbolizer
ada di/system/bin
.llvm-symbolizer
dibuat dari sumber dalam bahasathird_party/llvm/tools/llvm-symbolizer
. - Filter laporan melalui
external/compiler-rt/lib/asan/scripts/symbolize.py
{i>script<i}.
Pendekatan kedua dapat memberikan lebih banyak data (yaitu, file:line
lokasi) karena
ketersediaan library simbol
pada {i>host<i}.
ASan dalam aplikasi
ASan tidak dapat melihat ke dalam kode Java, tetapi dapat mendeteksi bug dalam JNI
library. Untuk itu, Anda perlu membangun {i>
executable<i} dengan ASan, yang
kasus ini adalah /system/bin/app_process(32|64)
. Ini
mengaktifkan ASan di semua aplikasi pada perangkat secara bersamaan, yang merupakan
beban yang berat, tetapi perangkat dengan RAM 2 GB seharusnya dapat menangani hal ini.
Tambahkan LOCAL_SANITIZE:=address
ke
aturan build app_process
di frameworks/base/cmds/app_process
. Abaikan
target app_process__asan
di file yang sama untuk saat ini (jika
masih ada saat Anda membaca pesan ini).
Edit bagian service zygote
dari
file system/core/rootdir/init.zygote(32|64).rc
yang sesuai untuk menambahkan
baris berikut ke blok baris indentasi yang berisi class main
, juga
diindentasi dengan jumlah yang sama:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
Build, sinkronisasi adb, booting flash fastboot, dan mulai ulang.
Menggunakan properti wrap
Pendekatan di bagian sebelumnya menempatkan ASan ke dalam setiap aplikasi dalam sistem (sebenarnya, ke dalam setiap keturunan Zygote ). Anda hanya dapat menjalankan satu (atau beberapa) aplikasi dengan ASan, menukar beberapa overhead memori untuk startup aplikasi yang lebih lambat.
Hal ini dapat dilakukan dengan memulai aplikasi Anda dengan properti wrap.
.
Contoh berikut menjalankan aplikasi Gmail dengan ASan:
adb root
adb shell setenforce 0 # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"
Dalam konteks ini, asanwrapper
menulis ulang /system/bin/app_process
ke /system/bin/asan/app_process
, yang dibuat dengan
ASan. Kode ini juga menambahkan /system/lib/asan
di awal
jalur penelusuran library dinamis. Dengan cara ini, ASan diinstrumentasikan
library dari /system/lib/asan
lebih disukai daripada library normal
dalam /system/lib
saat dijalankan dengan asanwrapper
.
Jika bug ditemukan, aplikasi akan error, dan laporan akan dicetak ke log.
SANITKAN_TARGET
Android 7.0 dan yang lebih tinggi menyertakan dukungan untuk membangun seluruh platform Android dengan ASan sekaligus. (Jika Anda membangun rilis yang lebih tinggi dari Android 9, HWASan adalah pilihan yang lebih baik.)
Jalankan perintah berikut dalam struktur build yang sama.
make -j42
SANITIZE_TARGET=address make -j42
Dalam mode ini, userdata.img
berisi library tambahan dan harus
di-flash ke perangkat juga. Gunakan command line berikut:
fastboot flash userdata && fastboot flashall
Cara ini membangun dua set pustaka bersama: normal di
/system/lib
(yang pertama melakukan pemanggilan), dan diinstrumentasi oleh ASan dalam
/data/asan/lib
(yang kedua melakukan pemanggilan). Dapat dijalankan dari
akan menimpa build dari build pertama. Diinstrumentasi dengan ASan
{i>executable<i} mendapatkan jalur pencarian
perpustakaan berbeda yang menyertakan
/data/asan/lib
sebelum /system/lib
melalui penggunaan
/system/bin/linker_asan
di PT_INTERP
.
Direktori objek perantara sistem build meng-clone saat
Nilai $SANITIZE_TARGET
telah diubah. Hal ini memaksa sistem merancang ulang
target sambil mempertahankan biner yang diinstal di /system/lib
.
Beberapa target tidak dapat dibuat dengan ASan:
- File yang dapat dieksekusi yang ditautkan secara statis
LOCAL_CLANG:=false
targetLOCAL_SANITIZE:=false
tidak ASan untukSANITIZE_TARGET=address
File yang dapat dieksekusi seperti ini dilewati di build SANITIZE_TARGET
, dan
dari pemanggilan make yang pertama,
ditinggalkan di /system/bin
.
Library seperti ini dibangun tanpa ASan. Dapat berisi beberapa ASan kode dari pustaka statis yang mereka andalkan.