AlamatPembersih

AddressSanitizer (ASan) adalah alat berbasis kompiler cepat untuk mendeteksi bug memori dalam kode asli.

ASan mendeteksi:

  • Tumpukan dan tumpukan buffer overflow/underflow
  • Tumpukan penggunaan setelah gratis
  • Tumpukan digunakan di luar lingkup
  • Bebas ganda/bebas liar

ASan berjalan pada ARM 32-bit dan 64-bit, ditambah x86 dan x86-64. Overhead CPU ASan kira-kira 2x, overhead ukuran kode antara 50% dan 2x, dan overhead memori yang besar (tergantung pada pola alokasi Anda, tetapi dalam urutan 2x).

Android 10 dan cabang utama AOSP di AArch64 mendukung hardware-accelerated ASan (HWASan) , alat serupa dengan overhead RAM yang lebih rendah dan lebih banyak bug yang terdeteksi. HWASan mendeteksi penggunaan tumpukan setelah pengembalian, selain bug yang terdeteksi oleh ASan.

HWASan memiliki overhead CPU dan ukuran kode yang serupa, tetapi overhead RAM jauh lebih kecil (15%). HWASan bersifat nondeterministik. Hanya ada 256 kemungkinan nilai tag, jadi ada kemungkinan 0,4% untuk melewatkan bug apa pun. HWASan tidak memiliki zona merah berukuran terbatas seperti ASan untuk mendeteksi luapan dan karantina berkapasitas terbatas untuk mendeteksi penggunaan setelah bebas, sehingga tidak menjadi masalah bagi HWASan seberapa besar luapan tersebut atau berapa lama memori telah dibatalkan alokasinya. Hal ini membuat HWASan lebih baik dari ASan. Anda dapat membaca lebih lanjut tentang desain HWASan atau tentang penggunaan HWASan di Android .

ASan mendeteksi stack/global overflow selain heap overflow, dan cepat dengan overhead memori minimal.

Dokumen ini menjelaskan cara membangun dan menjalankan sebagian/seluruh Android dengan ASan. Jika Anda membuat aplikasi SDK/NDK dengan ASan, lihat Address Sanitizer sebagai gantinya.

Sanitasi masing-masing executable dengan ASan

Tambahkan LOCAL_SANITIZE:=address atau sanitize: { address: true } ke aturan build untuk file yang dapat dieksekusi. Anda dapat mencari kode untuk contoh yang ada atau menemukan pembersih lain yang tersedia.

Ketika bug terdeteksi, ASan mencetak laporan panjang ke output standar dan logcat , lalu menghentikan prosesnya.

Sanitasi perpustakaan bersama dengan ASan

Karena cara kerja ASan, perpustakaan yang dibangun dengan ASan hanya dapat digunakan oleh executable yang dibangun dengan ASan.

Untuk membersihkan perpustakaan bersama yang digunakan dalam beberapa executable, tidak semuanya dibangun dengan ASan, Anda memerlukan dua salinan perpustakaan. Cara yang disarankan untuk melakukannya adalah dengan menambahkan yang berikut ke Android.mk untuk modul yang dimaksud:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

Ini menempatkan perpustakaan di /system/lib/asan bukan /system/lib . Kemudian, jalankan executable Anda dengan:

LD_LIBRARY_PATH=/system/lib/asan

Untuk daemon sistem, tambahkan yang berikut ini ke bagian /init.rc atau /init.$device$.rc yang sesuai.

setenv LD_LIBRARY_PATH /system/lib/asan

Verifikasi bahwa proses menggunakan perpustakaan dari /system/lib/asan saat ada dengan membaca /proc/$PID/maps . Jika tidak, Anda mungkin perlu 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.

Pelacakan tumpukan yang lebih baik

ASan menggunakan unwinder berbasis frame-pointer yang cepat untuk mencatat jejak tumpukan untuk setiap peristiwa alokasi memori dan dealokasi dalam program. Sebagian besar Android dibuat tanpa penunjuk bingkai. Akibatnya, Anda sering kali hanya mendapatkan satu atau dua frame yang bermakna. Untuk memperbaikinya, bangun kembali perpustakaan dengan ASan (disarankan!), atau dengan:

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

Atau atur ASAN_OPTIONS=fast_unwind_on_malloc=0 di lingkungan proses. Yang terakhir ini bisa sangat intensif CPU, tergantung pada bebannya.

Simbolisasi

Awalnya, laporan ASan berisi referensi ke offset dalam biner dan perpustakaan bersama. Ada dua cara untuk mendapatkan file sumber dan informasi baris:

  • Pastikan biner llvm-symbolizer ada di /system/bin . llvm-symbolizer dibuat dari sumber di third_party/llvm/tools/llvm-symbolizer .
  • Filter laporan melalui skrip external/compiler-rt/lib/asan/scripts/symbolize.py .

Pendekatan kedua dapat menyediakan lebih banyak data (yaitu, lokasi file:line ) karena ketersediaan perpustakaan yang disimbolkan pada host.

ASan di aplikasi

ASan tidak bisa melihat kode Java, tapi bisa mendeteksi bug di perpustakaan JNI. Untuk itu, Anda perlu membuat executable dengan ASan, yang dalam hal ini adalah /system/bin/app_process( 32|64 ) . Hal ini mengaktifkan ASan di semua aplikasi pada perangkat secara bersamaan, yang merupakan beban berat, namun perangkat dengan RAM 2 GB seharusnya dapat menangani hal ini.

Tambahkan LOCAL_SANITIZE:=address ke aturan pembuatan 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 ini).

Edit bagian service zygote dari file system/core/rootdir/init.zygote( 32|64 ).rc yang sesuai untuk menambahkan baris berikut ke blok baris berindentasi 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

Bangun, sinkronisasi adb, boot flash fastboot, dan reboot.

Menggunakan properti bungkus

Pendekatan di bagian sebelumnya menempatkan ASan ke dalam setiap aplikasi di sistem (sebenarnya, ke dalam setiap turunan proses Zygote). Dimungkinkan untuk menjalankan hanya satu (atau beberapa) aplikasi dengan ASan, menukar sejumlah overhead memori untuk startup aplikasi yang lebih lambat.

Hal ini dapat dilakukan dengan memulai aplikasi Anda dengan wrap. Properti. Contoh berikut menjalankan aplikasi Gmail di 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 menjadi /system/bin/asan/app_process , yang dibangun dengan ASan. Itu juga menambahkan /system/lib/asan di awal jalur pencarian perpustakaan dinamis. Dengan cara ini perpustakaan yang diinstrumentasi ASan dari /system/lib/asan lebih disukai daripada perpustakaan normal di /system/lib ketika dijalankan dengan asanwrapper .

Jika bug ditemukan, aplikasi mogok, dan laporan dicetak ke log.

SANITASI_TARGET

Android 7.0 dan lebih tinggi mencakup dukungan untuk membangun seluruh platform Android dengan ASan sekaligus. (Jika Anda membuat rilis yang lebih tinggi dari Android 9, HWASan adalah pilihan yang lebih baik.)

Jalankan perintah berikut di pohon build yang sama.

make -j42
SANITIZE_TARGET=address make -j42

Dalam mode ini, userdata.img berisi perpustakaan tambahan dan harus di-flash ke perangkat juga. Gunakan baris perintah berikut:

fastboot flash userdata && fastboot flashall

Ini membangun dua set perpustakaan bersama: normal di /system/lib (pemanggilan make pertama), dan instrumen ASan di /data/asan/lib (pemanggilan make kedua). Executable dari build kedua akan menimpa executable dari build pertama. Eksekusi yang diinstrumentasi ASan mendapatkan jalur pencarian perpustakaan berbeda yang mencakup /data/asan/lib sebelum /system/lib melalui penggunaan /system/bin/linker_asan di PT_INTERP .

Sistem pembangunan menghancurkan direktori objek perantara ketika nilai $SANITIZE_TARGET telah berubah. Hal ini memaksa pembangunan kembali semua target sambil mempertahankan biner yang terpasang di bawah /system/lib .

Beberapa target tidak dapat dibangun dengan ASan:

  • Executable yang ditautkan secara statis
  • LOCAL_CLANG:=false
  • LOCAL_SANITIZE:=false tidak disertakan untuk SANITIZE_TARGET=address

Eksekusi seperti ini dilewati dalam build SANITIZE_TARGET , dan versi dari pemanggilan make pertama dibiarkan di /system/bin .

Perpustakaan seperti ini dibangun tanpa ASan. Mereka dapat berisi beberapa kode ASan dari perpustakaan statis yang mereka andalkan.

Dokumentasi pendukung