Integritas alur kontrol

Mulai tahun 2016, sekitar 86% dari semua kerentanan di Android terkait 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 tidak mengizinkan perubahan pada grafik alur kontrol asli dari biner yang dikompilasi, sehingga mempersulit penyerang untuk melakukan serangan tersebut.

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 perlu mengaktifkan CFI kernel.

CFI LLVM memerlukan kompilasi dengan Link-Time Optimization (LTO). LTO mempertahankan representasi bitcode LLVM dari file objek hingga waktu penautan, yang memungkinkan compiler untuk 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 terhadap ukuran dan performa kode; dalam beberapa kasus, keduanya meningkat.

Untuk mengetahui detail teknis selengkapnya tentang CFI dan cara pemeriksaan kontrol maju lainnya ditangani, lihat dokumentasi desain LLVM.

Contoh dan sumber

CFI disediakan oleh compiler dan menambahkan instrumentasi ke 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 serangkaian file blueprint/makefile komponen media, seperti /platform/frameworks/av/media/libmedia/Android.bp dan /platform/frameworks/av/cmds/stagefright/Android.mk.

Mengimplementasikan 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.

Bahkan, sebaiknya Anda mengaktifkan CFI untuk komponen tambahan. Kandidat ideal adalah kode native dengan hak istimewa, atau kode native yang memproses input pengguna yang tidak tepercaya. Jika menggunakan clang dan sistem build Android, Anda dapat mengaktifkan CFI di komponen baru dengan menambahkan beberapa baris ke file makefile atau file blueprint.

Mendukung CFI dalam file make

Untuk mengaktifkan CFI dalam file make, 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 pembersih 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. Namun, pastikan untuk menghapus mode diagnostik pada build produksi.
  • LOCAL_SANITIZE_BLACKLIST memungkinkan komponen 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 ada. 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 dengan error ketidakcocokan jenis fungsi dan error ketidakcocokan jenis kode assembly.

Error ketidakcocokan jenis fungsi terjadi karena CFI membatasi panggilan tidak langsung agar hanya 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 menampilkan 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 adalah dua contoh CL:

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 akan menyebabkan ketidakcocokan jenis.

Untuk memperbaikinya, buat wrapper kode native untuk setiap panggilan assembly, dan beri wrapper tanda tangan fungsi yang sama dengan pointer panggilan. Wrapper kemudian dapat langsung memanggil kode assembly. Karena cabang langsung tidak diinstrumentasikan oleh CFI (cabang tidak dapat diarahkan ulang saat runtime sehingga tidak menimbulkan risiko keamanan), hal ini akan memperbaiki masalah.

Jika ada terlalu banyak fungsi assembly dan tidak semuanya dapat diperbaiki, Anda juga dapat mencantumkan semua fungsi yang berisi panggilan tidak langsung ke assembly ke dalam daftar hitam. Tindakan ini tidak direkomendasikan karena menonaktifkan pemeriksaan CFI pada fungsi ini, sehingga membuka platform serangan.

Menonaktifkan CFI

Kami tidak mengamati overhead performa apa pun, sehingga Anda tidak perlu menonaktifkan CFI. Namun, jika ada dampak yang dihadapi pengguna, Anda dapat menonaktifkan CFI secara selektif untuk setiap fungsi atau file sumber dengan menyediakan file daftar yang dikecualikan dari pembersihan pada waktu kompilasi. Daftar yang tidak diizinkan akan menginstruksikan compiler untuk menonaktifkan instrumentasi CFI di lokasi yang ditentukan.

Sistem build Android menyediakan dukungan untuk daftar yang tidak diizinkan per komponen (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 yang tidak diizinkan, 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.