Execute-only Memory (XOM) untuk AArch64 Binaries

Bagian kode yang dapat dieksekusi untuk binari sistem AArch64 secara default ditandai hanya-eksekusi (tidak dapat dibaca) sebagai mitigasi pengerasan terhadap serangan penggunaan kembali kode yang tepat waktu. Kode yang mencampur data dan kode bersama-sama dan kode yang dengan sengaja memeriksa bagian-bagian ini (tanpa terlebih dahulu memetakan kembali segmen memori agar dapat dibaca) tidak lagi berfungsi. Aplikasi dengan SDK target 10 (API level 29 atau lebih tinggi) terpengaruh jika aplikasi mencoba membaca bagian kode dari pustaka sistem yang diaktifkan hanya-eksekusi (XOM) di memori tanpa terlebih dahulu menandai bagian tersebut sebagai dapat dibaca.

Untuk mendapatkan manfaat penuh dari mitigasi ini, diperlukan dukungan perangkat keras dan kernel. Tanpa dukungan ini, mitigasi mungkin hanya dapat dilaksanakan sebagian. Kernel umum Android 4.9 berisi tambalan yang sesuai untuk memberikan dukungan penuh untuk ini pada perangkat ARMv8.2.

Penerapan

Binari AArch64 yang dihasilkan oleh kompiler mengasumsikan bahwa kode dan data tidak bercampur. Mengaktifkan fitur ini tidak berdampak negatif pada kinerja perangkat.

Untuk kode yang harus melakukan introspeksi memori yang disengaja pada segmen yang dapat dieksekusi, disarankan untuk memanggil mprotect pada segmen kode yang memerlukan pemeriksaan agar dapat dibaca, lalu hapus keterbacaan saat pemeriksaan selesai.
Implementasi ini menyebabkan pembacaan ke dalam segmen memori yang ditandai sebagai hanya-eksekusi untuk menghasilkan kesalahan segmentasi ( SEGFAULT ). Ini mungkin terjadi sebagai akibat dari bug, kerentanan, data yang bercampur dengan kode (pengumpulan literal), atau introspeksi memori yang disengaja.

Dukungan dan dampak perangkat

Perangkat dengan perangkat keras yang lebih lama atau kernel yang lebih lama (lebih rendah dari 4.9) tanpa patch yang diperlukan mungkin tidak sepenuhnya mendukung atau memanfaatkan fitur ini. Perangkat tanpa dukungan kernel mungkin tidak menerapkan akses pengguna ke memori khusus eksekusi, namun kode kernel yang secara eksplisit memeriksa apakah halaman dapat dibaca masih dapat menerapkan properti ini, seperti process_vm_readv() .

Bendera kernel CONFIG_ARM64_UAO harus disetel di kernel untuk memastikan bahwa kernel menghormati halaman pengguna yang ditandai hanya-eksekusi. Perangkat ARMv8 sebelumnya, atau perangkat ARMv8.2 dengan User Access Override (UAO) dinonaktifkan, mungkin tidak sepenuhnya memanfaatkan ini dan mungkin masih dapat membaca halaman khusus-eksekusi menggunakan syscalls.

Memfaktorkan ulang kode yang ada

Kode yang telah di-porting dari AArch32 mungkin berisi data dan kode yang bercampur, menyebabkan masalah muncul. Dalam banyak kasus, memperbaiki masalah ini semudah memindahkan konstanta ke bagian .data dalam file rakitan.

Perakitan tulisan tangan mungkin perlu difaktorkan ulang untuk memisahkan konstanta yang dikumpulkan secara lokal.

Contoh:

Biner yang dihasilkan oleh compiler Clang seharusnya tidak memiliki masalah dengan data yang dicampur dalam kode. Jika kode yang dihasilkan kumpulan kompiler GNU (GCC) disertakan (dari perpustakaan statis), periksa biner keluaran untuk memastikan bahwa konstanta belum dikumpulkan ke dalam bagian kode.

Jika introspeksi kode diperlukan pada bagian kode yang dapat dieksekusi, pertama-tama panggil mprotect untuk menandai kode dapat dibaca. Kemudian setelah operasi selesai, panggil mprotect lagi untuk menandainya tidak dapat dibaca.

Mengaktifkan

Hanya-eksekusi diaktifkan secara default untuk semua binari 64-bit dalam sistem pembangunan.

menonaktifkan

Anda dapat menonaktifkan hanya-eksekusi pada tingkat modul, oleh seluruh pohon subdirektori, atau secara global untuk keseluruhan build.

XOM dapat dinonaktifkan untuk modul individual yang tidak dapat difaktorkan ulang, atau perlu membaca kode yang dapat dieksekusi, dengan menyetel variabel LOCAL_XOM dan xom ke false .

// Android.mk
LOCAL_XOM := false

// Android.bp
cc_binary { // or other module types
   ...
   xom: false,
}

Jika memori hanya-eksekusi dinonaktifkan di pustaka statis, sistem build akan menerapkan ini ke semua modul dependen dari pustaka statis tersebut. Anda dapat menimpa ini dengan menggunakan xom: true, .

Untuk menonaktifkan memori hanya-eksekusi di subdirektori tertentu (misalnya, foo/bar/), berikan nilai ke XOM_EXCLUDE_PATHS .

make -j XOM_EXCLUDE_PATHS=foo/bar

Atau, Anda dapat menyetel variabel PRODUCT_XOM_EXCLUDE_PATHS dalam konfigurasi produk Anda.

Anda dapat menonaktifkan binari hanya-eksekusi secara global dengan meneruskan ENABLE_XOM=false ke perintah make Anda.

make -j ENABLE_XOM=false

Validasi

Tidak ada CTS atau uji verifikasi yang tersedia untuk memori hanya-eksekusi. Anda dapat memverifikasi binari secara manual menggunakan readelf dan memeriksa flag segmen.