Pada tahun 2016, sekitar 86% dari semua kerentanan di Android terkait dengan keamanan memori. Sebagian besar kerentanan dieksploitasi oleh penyerang yang mengubah alur kontrol normal aplikasi untuk melakukan aktivitas berbahaya arbitrer dengan semua hak istimewa aplikasi yang dieksploitasi. Integritas alur kontrol (CFI) adalah mekanisme keamanan yang melarang perubahan pada grafik alur kontrol asli biner yang dikompilasi, sehingga secara signifikan mempersulit pelaksanaan serangan semacam itu.
Di Android 8.1, kami mengaktifkan penerapan CFI LLVM di stack media. Di Android 9, kami mengaktifkan CFI di lebih banyak komponen dan juga kernel. CFI Sistem diaktifkan secara default, tetapi Anda harus mengaktifkan CFI kernel.
CFI LLVM memerlukan kompilasi dengan Pengoptimalan Waktu Penautan (LTO). LTO mempertahankan representasi bitcode LLVM dari file objek hingga waktu penautan, yang memungkinkan compiler lebih memahami pengoptimalan yang dapat dilakukan. Mengaktifkan LTO akan mengurangi ukuran biner akhir dan meningkatkan performa, tetapi meningkatkan waktu kompilasi. Dalam pengujian di Android, kombinasi LTO dan CFI menghasilkan overhead yang dapat diabaikan untuk ukuran dan performa kode; dalam beberapa kasus, keduanya meningkat.
Untuk mengetahui detail teknis selengkapnya tentang CFI dan cara penanganan pemeriksaan kontrol penerusan lainnya, lihat dokumentasi desain LLVM.
Contoh dan sumber
CFI disediakan oleh compiler dan menambahkan instrumentasi ke dalam biner selama waktu kompilasi. Kami mendukung CFI di toolchain Clang dan sistem build Android di AOSP.
CFI diaktifkan secara default untuk perangkat Arm64 untuk kumpulan komponen di
/platform/build/target/product/cfi-common.mk
.
Fitur ini juga diaktifkan secara langsung dalam file makefile/blueprint serangkaian komponen media, seperti /platform/frameworks/av/media/libmedia/Android.bp
dan /platform/frameworks/av/cmds/stagefright/Android.mk
.
Menerapkan CFI sistem
CFI diaktifkan secara default jika Anda menggunakan Clang dan sistem build Android. Karena CFI membantu menjaga keamanan pengguna Android, Anda tidak boleh menonaktifkannya.
Sebenarnya, sebaiknya Anda mengaktifkan CFI untuk komponen tambahan. Kandidat ideal adalah kode native yang memiliki hak istimewa, atau kode native yang memproses input pengguna yang tidak tepercaya. Jika Anda menggunakan clang dan sistem build Android, Anda dapat mengaktifkan CFI di komponen baru dengan menambahkan beberapa baris ke file makefile atau blueprint.
Mendukung CFI dalam file makefile
Untuk mengaktifkan CFI dalam file build, seperti /platform/frameworks/av/cmds/stagefright/Android.mk
,
tambahkan:
LOCAL_SANITIZE := cfi # Optional features LOCAL_SANITIZE_DIAG := cfi LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt
LOCAL_SANITIZE
menentukan CFI sebagai sanitizer selama build.LOCAL_SANITIZE_DIAG
mengaktifkan mode diagnostik untuk CFI. Mode diagnostik mencetak informasi debug tambahan di logcat selama error, yang berguna saat mengembangkan dan menguji build Anda. Pastikan untuk menghapus mode diagnostik pada build produksi.LOCAL_SANITIZE_BLACKLIST
memungkinkan komponen untuk menonaktifkan instrumentasi CFI secara selektif untuk setiap fungsi atau file sumber. Anda dapat menggunakan daftar hitam sebagai upaya terakhir untuk memperbaiki masalah yang dihadapi pengguna yang mungkin terjadi. Untuk mengetahui detail selengkapnya, lihat Menonaktifkan CFI.
Mendukung CFI dalam file blueprint
Untuk mengaktifkan CFI dalam file blueprint, seperti /platform/frameworks/av/media/libmedia/Android.bp
,
tambahkan:
sanitize: { cfi: true, diag: { cfi: true, }, blacklist: "cfi_blacklist.txt", },
Pemecahan masalah
Jika mengaktifkan CFI di komponen baru, Anda mungkin mengalami beberapa masalah terkait error ketidakcocokan jenis fungsi dan error ketidakcocokan jenis kode assembly.
Error ketidakcocokan jenis fungsi terjadi karena CFI membatasi panggilan tidak langsung hanya untuk melompat ke fungsi yang memiliki jenis dinamis yang sama dengan jenis statis yang digunakan dalam panggilan. CFI membatasi panggilan fungsi anggota virtual dan non-virtual agar hanya melompat ke objek yang merupakan class turunan dari jenis statis objek yang digunakan untuk melakukan panggilan. Artinya, jika Anda memiliki kode yang melanggar salah satu asumsi ini, instrumentasi yang ditambahkan CFI akan dibatalkan. Misalnya, stack trace menunjukkan SIGABRT dan logcat berisi baris tentang integritas alur kontrol yang menemukan ketidakcocokan.
Untuk memperbaikinya, pastikan fungsi yang dipanggil memiliki jenis yang sama dengan yang dideklarasikan secara statis. Berikut dua contoh CL:
- Bluetooth: /c/platform/system/bt/+/532377
- NFC: /c/platform/system/nfc/+/527858
Masalah lain yang mungkin terjadi adalah mencoba mengaktifkan CFI dalam kode yang berisi panggilan tidak langsung ke assembly. Karena kode assembly tidak diketik, hal ini menyebabkan ketidakcocokan jenis.
Untuk memperbaikinya, buat wrapper kode native untuk setiap panggilan assembly, dan berikan wrapper tanda tangan fungsi yang sama dengan poiner panggilan. Kemudian, wrapper dapat memanggil kode assembly secara langsung. Karena cabang langsung tidak diinstrumentasi oleh CFI (cabang tersebut tidak dapat diarahkan ulang saat runtime sehingga tidak menimbulkan risiko keamanan), hal ini akan memperbaiki masalah tersebut.
Jika ada terlalu banyak fungsi assembly dan semuanya tidak dapat diperbaiki, Anda juga dapat memasukkan semua fungsi yang berisi panggilan tidak langsung ke assembly dalam daftar hitam. Tindakan ini tidak direkomendasikan karena menonaktifkan pemeriksaan CFI pada fungsi ini, sehingga membuka permukaan serangan.
Menonaktifkan CFI
Kami tidak mengamati overhead performa apa pun, jadi Anda tidak perlu menonaktifkan CFI. Namun, jika ada dampak yang terlihat oleh pengguna, Anda dapat menonaktifkan CFI secara selektif untuk setiap fungsi atau file sumber dengan menyediakan file daftar hitam sanitizer pada waktu kompilasi. Daftar hitam menginstruksikan compiler untuk menonaktifkan instrumentasi CFI di lokasi yang ditentukan.
Sistem build Android menyediakan dukungan untuk daftar hitam per komponen (yang memungkinkan Anda memilih file sumber atau fungsi individual yang tidak akan menerima instrumentasi CFI) untuk Make dan Soong. Untuk mengetahui detail selengkapnya tentang format file daftar hitam, lihat dokumen Clang upstream.
Validasi
Saat ini, tidak ada pengujian CTS khusus untuk CFI. Sebagai gantinya, pastikan pengujian CTS lulus dengan atau tanpa CFI diaktifkan untuk memverifikasi bahwa CFI tidak memengaruhi perangkat.