Kontrol Aliran Integritas

Pada 2016, sekitar 86% dari semua kerentanan di Android terkait dengan keamanan memori. Sebagian besar kerentanan dieksploitasi oleh penyerang yang mengubah aliran kontrol normal aplikasi untuk melakukan aktivitas jahat sewenang-wenang dengan semua hak istimewa aplikasi yang dieksploitasi. Integritas aliran kontrol (CFI) adalah mekanisme keamanan yang melarang perubahan pada grafik aliran kontrol asli dari biner yang dikompilasi, sehingga secara signifikan lebih sulit untuk melakukan serangan tersebut.

Di Android 8.1, kami mengaktifkan implementasi CFI LLVM di tumpukan media. Di Android 9, kami mengaktifkan CFI di lebih banyak komponen dan juga kernel. Sistem CFI aktif secara default tetapi Anda harus mengaktifkan kernel CFI.

CFI LLVM memerlukan kompilasi dengan Link-Time Optimization (LTO) . LTO mempertahankan representasi bitcode LLVM dari file objek hingga waktu tautan, yang memungkinkan kompiler untuk memberikan alasan yang lebih baik tentang pengoptimalan apa yang dapat dilakukan. Mengaktifkan LTO mengurangi ukuran biner akhir dan meningkatkan kinerja, tetapi meningkatkan waktu kompilasi. Dalam pengujian di Android, kombinasi LTO dan CFI menghasilkan overhead yang dapat diabaikan untuk ukuran dan kinerja kode; dalam beberapa kasus keduanya membaik.

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

Contoh dan sumber

CFI disediakan oleh compiler dan menambahkan instrumentasi ke dalam biner selama waktu kompilasi. Kami mendukung CFI di rantai alat Dentang dan sistem pembangunan Android di AOSP.

CFI diaktifkan secara default untuk perangkat Arm64 untuk kumpulan komponen di /platform/build/target/product/cfi-common.mk . Ini juga langsung diaktifkan dalam satu set file makefile/blueprint komponen media, seperti /platform/frameworks/av/media/libmedia/Android.bp dan /platform/frameworks/av/cmds/stagefright/Android.mk .

Menerapkan sistem CFI

CFI diaktifkan secara default jika Anda menggunakan Dentang dan sistem build Android. Karena CFI membantu menjaga keamanan pengguna Android, Anda tidak boleh menonaktifkannya.

Bahkan, kami sangat menganjurkan Anda untuk mengaktifkan CFI untuk komponen tambahan. Kandidat yang ideal adalah kode asli yang diistimewakan, atau kode asli yang memproses masukan pengguna yang tidak tepercaya. Jika Anda menggunakan dentang dan sistem build Android, Anda dapat mengaktifkan CFI di komponen baru dengan menambahkan beberapa baris ke file makefile atau file cetak biru Anda.

Mendukung CFI di makefiles

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 menetapkan CFI sebagai pembersih selama pembuatan.
  • 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 secara selektif menonaktifkan instrumentasi CFI untuk fungsi individual atau file sumber. Anda dapat menggunakan daftar hitam sebagai upaya terakhir untuk memperbaiki masalah yang dihadapi pengguna yang mungkin ada. Untuk detail selengkapnya, lihat Menonaktifkan CFI .

Mendukung CFI dalam file cetak biru

Untuk mengaktifkan CFI dalam file cetak biru, seperti /platform/frameworks/av/media/libmedia/Android.bp , tambahkan:

   sanitize: {
        cfi: true,
        diag: {
            cfi: true,
        },
        blacklist: "cfi_blacklist.txt",
    },

Penyelesaian masalah

Jika Anda mengaktifkan CFI di komponen baru, Anda mungkin mengalami beberapa masalah dengan kesalahan ketidakcocokan jenis fungsi dan kesalahan ketidakcocokan jenis kode perakitan .

Kesalahan ketidakcocokan tipe fungsi terjadi karena CFI membatasi panggilan tidak langsung untuk hanya melompat ke fungsi yang memiliki tipe dinamis yang sama dengan tipe statis yang digunakan dalam panggilan. CFI membatasi panggilan fungsi anggota virtual dan non-virtual untuk hanya melompat ke objek yang merupakan kelas turunan dari tipe statis objek yang digunakan untuk melakukan panggilan. Ini berarti, ketika Anda memiliki kode yang melanggar salah satu dari asumsi ini, instrumentasi yang ditambahkan CFI akan dibatalkan. Misalnya, pelacakan tumpukan menunjukkan SIGABRT dan logcat berisi baris tentang integritas aliran kontrol yang menemukan ketidakcocokan.

Untuk memperbaikinya, pastikan bahwa fungsi yang dipanggil memiliki tipe 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 Majelis. Karena kode rakitan tidak diketik, ini menghasilkan ketidakcocokan jenis.

Untuk memperbaikinya, buat pembungkus kode asli untuk setiap panggilan Majelis, dan berikan pembungkus tanda tangan fungsi yang sama dengan penunjuk panggilan. Pembungkus kemudian dapat langsung memanggil kode perakitan. Karena cabang langsung tidak diinstrumentasi oleh CFI (mereka tidak dapat ditunjuk kembali saat runtime sehingga tidak menimbulkan risiko keamanan), ini akan memperbaiki masalah.

Jika ada terlalu banyak fungsi rakitan dan semuanya tidak dapat diperbaiki, Anda juga dapat membuat daftar hitam semua fungsi yang berisi panggilan tidak langsung ke rakitan. Ini tidak disarankan karena menonaktifkan pemeriksaan CFI pada fungsi ini, sehingga membuka permukaan serangan.

Menonaktifkan CFI

Kami tidak mengamati overhead kinerja apa pun, jadi Anda tidak perlu menonaktifkan CFI. Namun, jika ada dampak yang dihadapi pengguna, Anda dapat secara selektif menonaktifkan CFI untuk masing-masing fungsi atau file sumber dengan menyediakan file daftar hitam pembersih pada waktu kompilasi. Daftar hitam menginstruksikan kompiler untuk menonaktifkan instrumentasi CFI di lokasi yang ditentukan.

Sistem build Android menyediakan dukungan untuk daftar hitam per komponen (memungkinkan Anda memilih file sumber atau fungsi individual yang tidak akan menerima instrumentasi CFI) untuk Make dan Soong. Untuk detail selengkapnya tentang format file daftar hitam, lihat dokumen Clang upstream .

Validasi

Saat ini, tidak ada tes CTS khusus untuk CFI. Sebagai gantinya, pastikan tes CTS lulus dengan atau tanpa mengaktifkan CFI untuk memverifikasi bahwa CFI tidak memengaruhi perangkat.