Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Pembersih Alamat

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

ASan mendeteksi:

  • Stack dan heap buffer overflow/underflow
  • Tumpukan digunakan setelah gratis
  • Stack digunakan di luar ruang 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 pada urutan 2x).

Android 10 dan cabang master AOSP di AArch64 dukungan hardware-accelerated Asan (HWASan) , alat serupa dengan overhead RAM yang lebih rendah dan kisaran yang lebih besar dari bug terdeteksi. HWASan mendeteksi penggunaan tumpukan setelah kembali, selain bug yang terdeteksi oleh ASan.

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

ASan mendeteksi luapan tumpukan/global selain luapan tumpukan, dan cepat dengan overhead memori minimal.

Dokumen ini menjelaskan cara membangun dan menjalankan sebagian/semua Android dengan ASan. Jika Anda sedang membangun sebuah SDK / aplikasi NDK dengan Asan, melihat Alamat Sanitizer sebagai gantinya.

Sanitasi executable individu dengan ASan

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

Ketika bug terdeteksi, Asan mencetak verbose melaporkan kedua ke output standar dan logcat dan kemudian crash proses.

Membersihkan 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 di beberapa executable, tidak semuanya dibuat dengan ASan, Anda memerlukan dua salinan perpustakaan. Cara yang disarankan untuk melakukan ini adalah dengan menambahkan berikut ini untuk Android.mk untuk modul tersebut:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

Puts ini perpustakaan di /system/lib/asan bukan /system/lib . Kemudian, jalankan executable Anda dengan:

LD_LIBRARY_PATH=/system/lib/asan

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

setenv LD_LIBRARY_PATH /system/lib/asan

Memverifikasi bahwa proses ini menggunakan perpustakaan dari /system/lib/asan saat ini 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.

Jejak tumpukan yang lebih baik

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

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

Atau mengatur ASAN_OPTIONS=fast_unwind_on_malloc=0 dalam lingkungan proses. Yang terakhir bisa sangat intensif CPU, tergantung pada bebannya.

Simbolisasi

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

  • Pastikan bahwa llvm-symbolizer biner hadir di /system/bin . llvm-symbolizer dibangun dari sumber-sumber di third_party/llvm/tools/llvm-symbolizer .
  • Menyaring laporan melalui external/compiler-rt/lib/asan/scripts/symbolize.py naskah.

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

ASan di aplikasi

ASan tidak dapat melihat kode Java, tetapi dapat mendeteksi bug di perpustakaan JNI. Untuk itu, Anda perlu untuk membangun dieksekusi dengan Asan, yang dalam hal ini adalah /system/bin/app_process( 32|64 ) . Ini memungkinkan ASan di semua aplikasi pada perangkat secara bersamaan, yang merupakan beban berat, tetapi perangkat dengan RAM 2 GB harus dapat menangani ini.

Menambahkan LOCAL_SANITIZE:=address ke app_process membangun aturan dalam frameworks/base/cmds/app_process . Mengabaikan app_process__asan target dalam file yang sama untuk saat ini (jika masih ada pada saat Anda membaca ini).

Edit service zygote bagian yang sesuai system/core/rootdir/init.zygote( 32|64 ).rc file untuk menambahkan baris berikut ke blok dari garis indentasi mengandung class main , juga menjorok 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 dalam sistem (sebenarnya, ke dalam setiap turunan dari proses Zygote). Dimungkinkan untuk menjalankan hanya satu (atau beberapa) aplikasi dengan ASan, memperdagangkan beberapa 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 bawah ASan:

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

Dalam konteks ini, asanwrapper penulisan ulang /system/bin/app_process ke /system/bin/asan/app_process , yang dibangun dengan Asan. Ia juga menambahkan /system/lib/asan pada awal jalan yang dinamis pencarian perpustakaan. Dengan cara ini Asan-diinstrumentasi perpustakaan dari /system/lib/asan lebih disukai untuk perpustakaan normal dalam /system/lib ketika menjalankan dengan asanwrapper .

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

SANITIZE_TARGET

Android 7.0 dan yang lebih tinggi menyertakan dukungan untuk membangun seluruh platform Android dengan ASan sekaligus. (Jika Anda membuat rilis 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 ekstra dan harus melintas ke perangkat juga. Gunakan baris perintah berikut:

fastboot flash userdata && fastboot flashall

Hal ini akan membangun dua set shared library: normal dalam /system/lib (yang pertama make doa), dan Asan-instrumen di /data/asan/lib (kedua make doa). Eksekusi dari build kedua menimpa yang dari build pertama. Executable Asan-diinstrumentasi mendapatkan jalur pencarian perpustakaan yang berbeda yang mencakup /data/asan/lib sebelum /system/lib melalui penggunaan /system/bin/linker_asan di PT_INTERP .

Membangun sistem clobbers direktori objek menengah ketika $SANITIZE_TARGET nilai telah berubah. Pasukan ini membangun kembali semua target sambil menjaga binari dipasang di bawah /system/lib .

Beberapa target tidak dapat dibangun dengan ASan:

  • Eksekusi yang terhubung secara statis
  • LOCAL_CLANG:=false target
  • LOCAL_SANITIZE:=false tidak ASan'd untuk SANITIZE_TARGET=address

Executable seperti ini dilewati dalam SANITIZE_TARGET membangun, dan versi dari pertama make doa yang tersisa di /system/bin .

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

Dokumentasi pendukung