Memori khusus eksekusi (XOM) untuk biner AArch64

Bagian kode yang dapat dieksekusi untuk biner sistem AArch64 secara default ditandai sebagai khusus eksekusi (tidak dapat dibaca) sebagai mitigasi hardening terhadap serangan penggunaan kembali kode just-in-time. Kode yang menggabungkan data dan kode serta kode yang sengaja memeriksa bagian ini (tanpa memetakan ulang segmen memori terlebih dahulu agar dapat dibaca) tidak lagi berfungsi. Aplikasi dengan target SDK 10 (API level 29 atau yang lebih tinggi) akan terpengaruh jika aplikasi mencoba membaca bagian kode library sistem yang mengaktifkan memori khusus eksekusi (XOM) dalam memori tanpa menandai bagian tersebut sebagai dapat dibaca terlebih dahulu.

Untuk mendapatkan manfaat sepenuhnya dari mitigasi ini, dukungan hardware dan kernel diperlukan. Tanpa dukungan ini, mitigasi mungkin hanya diterapkan sebagian. Kernel umum Android 4.9 berisi patch yang sesuai untuk memberikan dukungan penuh untuk ini di perangkat ARMv8.2.

Implementasi

Biner AArch64 yang dihasilkan oleh compiler mengasumsikan bahwa kode dan data tidak tercampur. Mengaktifkan fitur ini tidak memengaruhi performa perangkat secara negatif.

Untuk kode yang harus melakukan introspeksi memori yang disengaja pada segmen yang dapat dieksekusi, sebaiknya panggil mprotect pada segmen kode yang memerlukan pemeriksaan agar dapat dibaca, lalu hapus keterbacaan saat pemeriksaan selesai.
Implementasi ini menyebabkan pembacaan ke segmen memori yang ditandai sebagai khusus eksekusi sehingga menyebabkan error segmentasi (SEGFAULT). Hal ini dapat terjadi sebagai akibat dari bug, kerentanan, data yang dicampur dengan kode (penggabungan literal), atau introspeksi memori yang disengaja.

Dukungan dan dampak perangkat

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

Flag kernel CONFIG_ARM64_UAO harus ditetapkan di kernel untuk memastikan kernel mematuhi halaman userland yang ditandai sebagai hanya eksekusi. Perangkat ARMv8 sebelumnya, atau perangkat ARMv8.2 dengan User Access Override (UAO) dinonaktifkan, mungkin tidak mendapatkan manfaat sepenuhnya dari hal ini dan mungkin masih dapat membaca halaman khusus eksekusi menggunakan syscall.

Memfaktorkan ulang kode yang ada

Kode yang telah di-port dari AArch32 mungkin berisi data dan kode yang tercampur, sehingga menyebabkan masalah. Dalam banyak kasus, memperbaiki masalah ini semudah memindahkan konstanta ke bagian .data dalam file assembly.

Assembly tulisan tangan mungkin perlu difaktorkan ulang untuk memisahkan konstanta yang digabungkan secara lokal.

Contoh:

Biner yang dihasilkan oleh compiler Clang seharusnya tidak memiliki masalah dengan data yang tercampur dalam kode. Jika kode yang dihasilkan koleksi compiler GNU (GCC) disertakan (dari library statis), periksa biner output untuk memastikan bahwa konstanta belum digabungkan ke dalam bagian kode.

Jika introspeksi kode diperlukan di bagian kode yang dapat dieksekusi, panggil mprotect terlebih dahulu untuk menandai kode agar dapat dibaca. Kemudian, setelah operasi selesai, panggil mprotect lagi untuk menandainya sebagai tidak dapat dibaca.

Mengaktifkan XOM

Hanya eksekusi diaktifkan secara default untuk semua biner 64-bit dalam sistem build.

Menonaktifkan XOM

Anda dapat menonaktifkan hanya eksekusi di tingkat modul, berdasarkan seluruh hierarki subdirektori, atau secara global untuk seluruh build.

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

// Android.mk
LOCAL_XOM := false

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

Jika memori khusus eksekusi dinonaktifkan di library statis, sistem build akan menerapkan hal ini ke semua modul dependen dari library statis tersebut. Anda dapat mengganti hal ini menggunakan xom: true,.

Untuk menonaktifkan memori khusus eksekusi di subdirektori tertentu (misalnya, foo/bar/), teruskan nilai ke XOM_EXCLUDE_PATHS.

make -j XOM_EXCLUDE_PATHS=foo/bar

Atau, Anda dapat menetapkan variabel PRODUCT_XOM_EXCLUDE_PATHS di konfigurasi produk.

Anda dapat menonaktifkan biner khusus eksekusi secara global dengan meneruskan ENABLE_XOM=false ke perintah make.

make -j ENABLE_XOM=false

Validasi

Tidak ada CTS atau pengujian verifikasi yang tersedia untuk memori khusus eksekusi. Anda dapat memverifikasi biner secara manual menggunakan readelf dan memeriksa flag segmen.