Analisis mendalam syscall mseal baru di Linux
(blog.trailofbits.com)- mseal di Linux 6.10 adalah syscall mitigasi eksploit yang menyegel area memori virtual saat runtime, sehingga penyerang yang telah memperoleh hak eksekusi kode akan lebih sulit mengubah izin atau tata letak VMA setelahnya
mseal(start, len, flags)menambahkanVM_SEALEDke rentang VMA yang selaras halaman, dan kernel akan menolak perubahan melaluimprotect,munmap,mmap(MAP_FIXED),mremap, serta beberapa jalurmadviseyang bersifat destruktif- Jika
memfd_createataumemfd_secretlebih dekat ke file anonim berbasis RAM dan kontrol akses memori rahasia, mseal berfokus pada pencegahan perubahan izin, unmapping, dan remapping setelah eksekusi kode oleh penyerang jarak jauh - Target pertahanan utamanya adalah serangan yang mengeksekusi shellcode dengan melewati NX lewat
mprotect(PROT_EXEC), serta eksploit khusus data yang membuat lubang di memori lewatmunmap/remapping lalu mengisinya dengan data penyerang - Integrasi ke glibc setelah 2.41 dimungkinkan, tetapi stack dan heap bukan target penyegelan otomatis karena dapat membesar dan mengecil saat runtime, sehingga pengembang harus hati-hati menentukan waktu dan cakupan penerapannya
Perlindungan yang diberikan mseal
- Penyegelan memori (memory sealing) adalah fitur yang membuat rentang VMA saat runtime menjadi hampir tidak dapat diubah dari modifikasi berbahaya di kemudian hari
- Bahkan jika penyerang memperoleh primitive eksekusi kode, pada VMA yang disegel akan sulit mengubah izin atau memanipulasi tata letak demi keuntungan mereka melalui operasi memori virtual
- Tim Keamanan Chrome memperkenalkan syscall ini untuk mendukung strategi V8 CFI di ChromeOS berbasis Linux
- Setelah beberapa kali diskusi dan penulisan ulang, fitur ini masuk ke kernel Linux, dan melalui integrasi glibc cakupan penggunaannya dapat meluas di luar browser
Perbedaan dengan keluarga memfd
memfd_createdanmemfd_secretlebih dekat ke keluarga file sealing- Dapat membuat file anonim berbasis RAM
memfd_secretmembuat hanya proses yang memiliki file descriptor yang dapat mengakses area memori tersebut- Dapat dimanfaatkan untuk pemetaan user-space bergaya “secure enclave” guna melindungi data sensitif di memori
msealadalah syscall yang ditujukan untuk mitigasi eksploit terhadap penyerang jarak jauh yang mengejar eksekusi kode, bukan penyerang lokal yang berusaha membocorkan informasi sensitif
Cara kerja di dalam kernel
- Signature syscall ini adalah
int mseal(unsigned long start, size_t len, unsigned long flags)startdanlenmenunjukkan awal dan panjang VMA valid yang akan disegellenharus selaras halaman dengan benar- Saat ini
flagsbelum digunakan dan harus bernilai0
- Implementasi berdasarkan Linux 6.12 memanggil
do_msealcurrent->mmmenunjuk kemm_struct, yaitu seluruh ruang alamat memori virtual proses pemanggilmmapdi dalammm_structmenyimpan daftarvm_area_struct, yaitu area memori berurutan yang dibuat denganmmap- Area seperti stack atau VDSO juga dapat direpresentasikan sebagai satu VMA
do_msealmenghitung alamat akhir rentang lalu mengunci area memori denganmmap_write_lock_killablecheck_mm_sealmenelusuri setiap VMA dalam rentang target dan terlebih dahulu memeriksa validitas batas- Jika ada memori yang tidak dialokasikan di tengah rentang, fungsi ini mengembalikan
-ENOMEM - Pemeriksaan tahap pertama ini dilakukan agar tidak terjadi situasi saat hanya sebagian VMA yang tersegel ketika muncul error
- Jika ada memori yang tidak dialokasikan di tengah rentang, fungsi ini mengembalikan
apply_mm_sealmenelusuri kembali rentang yang sama dan menambahkan flagVM_SEALEDke VMA target melaluimseal_fixup
Operasi memori yang dilarang setelah penyegelan
- Patchset kernel menambahkan pemeriksaan
VM_SEALEDkemm/madvise.c,mm/mmap.c,mm/mprotect.c,mm/mremap.c,mm/mseal.c mprotectdanpkey_mprotectsecara internal memanggilcan_modify_vmadarimprotect_fixup, dan jika VMA disegel akan mengembalikan-EPERM- Pada VMA yang disegel, operasi berikut tidak diizinkan
- Perubahan bit izin melalui
mprotect,pkey_mprotect - Unmapping melalui
munmap - Penggantian mapping yang disegel dengan mapping yang dapat diubah dan tidak disegel melalui
mmap(MAP_FIXED) - Perluasan atau penyusutan ukuran melalui
mremap - Pemindahan ke tujuan baru melalui
mremap(MREMAP_MAYMOVE | MREMAP_FIXED) madvisedengan beberapa flag destruktif tertentu
- Perubahan bit izin melalui
- Pada pemindahan
mremap, pemeriksaan penyegelan diterapkan baik ke VMA sumber maupun tujuan - Jika tidak ada
MREMAP_DONTUNMAP, VMA sumber akan di-unmap, dan pada saat itu juga harus lolos pemeriksaan penyegelanmunmap - Di Linux 6.10 ke atas,
msealbisa digunakan lewat pemanggilan syscall langsung, dan wrapper contohnya memakai nomor syscall462denganflags=0
Memblokir eksekusi shellcode melalui penguatan NX
- Penyerang dapat tetap memilih eksekusi shellcode meskipun ada teknik reuse kode seperti ROP
- Menyebarkan shellcode ke stack atau heap yang tidak dapat dieksekusi
- Menjalankan rantai ROP awal melalui kerentanan
- Mematikan bit NX pada area berisi shellcode dengan
mprotect(PROT_EXEC) - Melompat ke area itu dan mengeksekusi shellcode
- Serangan terhadap daemon SMB MikroTik RouterOS yang memanfaatkan CVE-2018-7445 adalah contoh alur ini
- Menyebarkan shellcode berbasis socket ke heap yang tidak dapat dieksekusi
- Rantai ROP yang dibuat melalui stack overflow mengubah izin memori heap
- Lalu mengeksekusi shellcode
- Jika VMA terkait disegel dengan
mseal, pemeriksaancan_modify_vmasaatmprotectakan mencegah perubahan izin - Pada kode contoh, jika halaman shellcode di stack tidak disegel, eksekusi dimungkinkan setelah
mprotect(PROT_READ|PROT_WRITE|PROT_EXEC) - Jika halaman yang sama disegel dengan
mseal,mprotecttidak dapat benar-benar mengubah izin, dan eksekusi shellcode memicu segmentation fault
Keterbatasan penerapan pada stack dan heap
- Jika
msealdiadopsi setelah glibc 2.41, dynamic loader akan menerapkan penyegelan pada himpunan VMA yang telah ditentukan sebelumnya - Dalam rencana saat ini, stack dan heap tidak akan disegel secara otomatis
- Stack dan heap dapat berkembang saat runtime, sehingga penyegelan otomatis bisa merusak perilaku aplikasi
- Allocator heap dapat memanggil syscall
brkuntuk mencoba mengembalikan ruang - Pada jalur ini, penyusutan dapat terjadi melalui
arch_unmapdando_vmi_unmap - Dalam status tersegel, unmapping seperti ini tidak diizinkan sehingga alokasi memori dinamis dapat rusak
- Allocator heap dapat memanggil syscall
- Pengembang harus menilai, sesuai konteks aplikasi, pada waktu dan area mana penyegelan aman untuk diterapkan
- Makro contoh berulang kali menyegel halaman dari stack frame terpilih yang mungkin berisi data tidak tepercaya
- Memanggil
mseallagi pada VMA yang sudah disegel diperlakukan sebagai no-op sehingga tidak menimbulkan error - Fitur seperti pertumbuhan stack otomatis atau stack splitting memerlukan perhatian tersendiri
- Jika penyerang tetap bersikeras memakai shellcode, mereka masih bisa
mmaparea executable baru dan menyalin payload dari area yang dapat dibaca, tetapi prosedurnya menjadi lebih merepotkan
Mitigasi eksploit khusus data berbasis unmapping
- Pemblokiran
mprotectjuga mencegah area yang disegel berubah menjadi writable, sehingga membantu melindungi variabel data yang jika dimodifikasi dapat memperkuat primitive eksploit - Para maintainer Chrome mempertimbangkan teknik yang mengirim pointer rusak ke syscall unmapping dan remapping untuk melubangi memori lalu mengisinya kembali dengan data yang dikendalikan penyerang
- Cara ini tidak langsung mengubah transisi alur kontrol seperti alamat kembali stack atau function pointer, sehingga dapat melewati jaminan CFI forward-edge dan backward-edge
- Dalam browser yang mengimplementasikan JIT compiler, teknik ini bisa sangat berguna
- Turbofan milik V8 dapat membuat area yang beralih antara RW dan RX
- Penyerang dapat memicu pembuatan kode eksekusi melalui JavaScript hot-path selama proses kompilasi JIT
- Dengan mengisi area yang telah di-unmap, mereka dapat menimpa data penting dan membuat perubahan yang berujung pada eksekusi kode
- Ini adalah eksploit khusus data yang memengaruhi alur kontrol dengan memanipulasi data tertentu di memori, tanpa perlu mengambil alih alur kontrol secara langsung atau membutuhkan kebocoran pointer
msealdapat mencegah skenario hole-punching semacam ini dengan memblokir unmapping dan remapping
Kasus House of Muney
- House of Muney menggunakan teknik serupa berbasis unmapping dalam eksploit heap user-space
- Qualys memakai teknik ini dalam eksploit nyata terhadap bug Qmail lama
- Teknik ini bergantung pada sifat bahwa saat chunk alokasi besar melebihi
M_MAP_THRESHOLD,mallocdanfreemasing-masing akan langsung memanggilmmapdanmunmap - Karena chunk besar tidak memiliki cache freelist perantara, prosedur eksploit menjadi lebih sederhana
- Jika metadata ukuran di bagian atas chunk alokasi dipalsukan menjadi ukuran halaman lain lalu
freedipanggil,munmapdapat terjadi pada area memori yang bersebelahan dengan chunk - Contoh Dulin menargetkan area
.gnu.hashdan.dynsymdenganmunmapsewenang-wenang- Lalu mengisinya kembali dengan chunk
mmapyang lebih besar - Sehingga satu entri PLT yang belum di-resolve dapat ditimpa
- Ini menghidupkan kembali serangan bergaya GOT overwrite
- Lalu mengisinya kembali dengan chunk
- PoC yang diringkas mengalokasikan dua chunk besar, memanipulasi field size dari
top[-1], lalu denganfree(top)melakukan unmapping hingga area yang bersebelahan, dan mengisi ulang dengan dataXlewat alokasi yang lebih besar - Teknik ini dapat tetap bekerja meskipun ada CFI, dan tidak memerlukan kebocoran ASLR sebelumnya
- Dalam integrasi
msealke glibc, penyegelan pada himpunan VMA yang direncanakan diharapkan secara otomatis memitigasi serangan ini dengan melindungi kode biner yang dipetakan dan library dinamis dari trik unmapping dan remapping - Pengembang yang menginginkan penguatan tambahan dapat secara selektif menyegel alokasi
mmapyang tidak akan berkembang atau di-unmap selama masa hidup program
Cakupan penggunaan ke depan
msealadalah fitur mitigasi yang relatif baru di kernel Linux, dan mungkin masih ada kasus penggunaan lain yang belum banyak dibahas- Jika integrasi glibc selesai dan matang, perbaikan yang disesuaikan dengan kebutuhan syscall ini bisa terus berlanjut
- Parameter
flagsyang saat ini belum digunakan juga dapat memperoleh kegunaan yang lebih spesifik di masa depan - Saat menerapkannya ke perangkat lunak nyata, umur hidup memori yang akan disegel dan kebutuhan perubahannya harus dievaluasi bersama-sama
1 komentar
Komentar Hacker News
Akan bagus kalau ada orang dalam yang merangkum keberatan dan kekhawatiran apa saja yang muncul dalam diskusi sengit di kernel mailing list
Saya cenderung menghindari mailing list itu sendiri karena kadang terlalu pedas, dan sakit kepala saya sudah cukup parah
Mekanismenya sendiri terlihat masuk akal, tetapi cukup mengejutkan bahwa fitur seperti ini belum ada di kernel
Di antara flag yang diusulkan ada yang memungkinkan seal diabaikan, dan Linus bereaksi kurang lebih seperti, “jadi di satu tempat
munmaptidak boleh dilakukan, tetapi di tempat lain seal mau diabaikan?”Setelah itu ia berkata lebih tegas bahwa “begitu sudah disegel, ya sudah disegel”, dan tidak boleh ada pola “sebagian tempat mematuhi seal dan tempat lain yang sewenang-wenang tidak”
Belakangan ia bahkan mengatakan bahwa seal tidak bisa diabaikan dan bukan bahan negosiasi, dan jika ada usulan lagi untuk mengabaikan seal lewat flag, ia akan memasukkannya ke ignore list
Dalam email Theo de Raadt kepada Jeff Xu, ketika Jeff mengatakan bahwa pendekatan
mimmutable()danmseal()berbeda, tetapi keduanya bertujuan membuat aplikasi Linux lebih aman dengan menyegel memori dari penyerang, Theo menjawab, “sepertinya Anda membuat mseal hanya untuk Chrome”Ia menilai ini tidak akan cocok untuk aplikasi secara umum, dengan alasan terlalu rumit dan, berdasarkan pengalaman
mimmutable(), aplikasi tidak menanganinya sendiri;execve(), inisialisasi libc, danld.soyang akan bertanggung jawabIa sepakat dengan Theo dan Linus, dan menilai ide dasar
mimmutable()bagus, tetapi cara ide itu dipecah dan diimplementasikan mengerikanSaya penasaran bagaimana system call ini digunakan
Chrome menginginkannya, tetapi karena penyerang bisa memetakan ulang dengan flag lain, halaman yang sudah disegel tidak bisa di-unmap
Kalau begitu, bukankah halaman yang dialokasikan saat runtime praktis tidak bisa dipakai kecuali memang ingin dipertahankan selama seluruh masa hidup proses?
Jika begitu, bukankah ini sulit diterapkan pada target yang sangat menarik seperti memori sandbox JS?
Saya penasaran apakah pekerjaan semacam ini diselesaikan dengan menjalankannya di proses terpisah, menyegel memorinya, lalu mematikan proses setelah selesai
Saya tidak begitu paham cara Chrome mengelola memori dan proses, jadi saya tidak yakin mengapa ini bukan masalah, dan juga penasaran apakah ini alasan fitur ini sering dijelaskan tidak berguna bagi kebanyakan program
Setahu saya Chrome memakainya secara luas, dan karena proses terpisah memang diperlukan juga untuk alasan seperti isolasi lewat namespace, mungkin arahnya ke sana
Diskusi setelah
mseal(), 20 Oktober 2023: https://lwn.net/Articles/948129/mseal()makin mendekat, 19 Januari 2024: https://lwn.net/Articles/958438/Penyegelan memori untuk GNU C Library, 12 Juni 2024: https://lwn.net/Articles/978010/
Arsitektur x86_64 modern punya banyak fitur yang membantu pemrograman dan komputasi yang aman, jadi menyedihkan bahwa sistem operasi masih harus mengimplementasikan panggilan seperti ini
Menurut saya, sikap menambal sistem tua yang dibangun di atas warisan dan pola pikir usang, serta paradigma yang tidak cocok dengan dunia dan pengetahuan saat ini, memperlambat kemajuan komputasi dan secara harfiah menempatkan miliaran orang dalam bahaya
Tentu saya tidak bermaksud mengatakan bahwa perubahan seperti ini bukan langkah ke arah yang benar, tetapi jika kita melepaskan ideal lama bahwa sistem operasi harus tetap bekerja seperti itu, lalu mempertimbangkan sistem dan pengetahuan saat ini serta apa yang diinginkan orang dari sistem, kita bisa membayangkan sistem yang terbebas dari beban dan risiko yang kini ditanggung pengembang dan pengguna
Memang benar bug arsitektur itu ada, tetapi karena perangkat lunak bahkan belum memanfaatkan fitur yang ada dengan benar, memakai bug arsitektur sebagai bantahan berarti meleset dari inti persoalan
Jika dibangun di atas fondasi yang goyah, akan selalu ada cara kompromi yang lebih murah
Saya juga penasaran mengapa Anda menganggap
msealtidak dapat dibenarkan, dan apa yang menurut Anda lebih baik sebagai gantinyaApakah bisa menimpa atau menonaktifkan system call
msealdengan trikLD_PRELOAD?msealadalah system call yang ditujukan untuk mitigasi serangan eksekusi kode jarak jauh, bukan untuk menghadapi penyerang lokal yang ingin mengekstrak rahasia sensitif dari dalam memoriJika penyerang jarak jauh bisa mengubah lingkungan lokal, itu harus dianggap bahwa sistem sudah berhasil disusupi
LD_PRELOADAgar efektif, targetnya harus berupa fungsi yang diimpor, sedangkan system call mentah tidak bisa dicegat dengan cara seperti itu
Diskusi tentang pencegatan system call Linux: https://stackoverflow.com/questions/69859/how-could-i-interc...
Membuat sendiri kernel yang dipatch agar berpura-pura
msealberfungsi mungkin merupakan cara termudah untuk “menonaktifkan” fitur iniNamun program yang memakai
msealbisa memverifikasi apakah ia benar-benar bekerja, sehingga kernel yang telah dikompromikan juga perlu cara untuk menonaktifkanmsealsecara diam-diam agar pemeriksaan aplikasi setelah diterapkan tidak terdeteksiMisalnya, menjalankan executable di bawah pelacakan
ptraceuntuk memantau system call lalu melewatimseal(2)System call ini bukan untuk model ancaman “penyerang sudah memiliki akses sebelum inisialisasi proses”
msealbisa ditimpa, tetapi system call itu sendiri tidak bisa ditimpaSetelah saya cari, semua penimpaan system call berbasis preload tampaknya dilakukan dengan mengganti wrapper, dan jika melakukan system call secara langsung, sepertinya tidak bisa ditimpa
Secara teknis, mungkin saja fungsi
syscallitu sendiri bisa ditimpaMeta: prototipe
mseal()yang muncul di artikel perlu dieditArgumen pertama ditampilkan sebagai
unsigned start addr, tetapi kemungkinan yang benar adalahunsigned long start_addrint mseal(unsigned long start, size_t len, unsigned long flags)Di “Memory Sealing ‘Mseal’ System Call Merged for Linux 6.10” (2024) https://news.ycombinator.com/item?id=40474510#40474551, bagaimana CPython seharusnya mendukung system call
mseal()sudah pernah dibahasOpenBSD sudah punya fitur ini sejak lama https://man.openbsd.org/mimmutable.2
Saya penasaran mengapa fitur yang tampak begitu wajar ini baru sekarang masuk ke Linux
mimmutabledi OpenBSD diperkenalkan pada OpenBSD 7.3, yang dirilis pada 10 April 2023, jadi bukan “sejak lama”Sebaliknya, Linux dan FreeBSD sudah lama memiliki
memfd_create, sedangkan OpenBSD tidak punya file anonim dan bergantung padashm_open