2 poin oleh GN⁺ 2024-10-27 | 1 komentar | Bagikan ke WhatsApp
  • 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) menambahkan VM_SEALED ke rentang VMA yang selaras halaman, dan kernel akan menolak perubahan melalui mprotect, munmap, mmap(MAP_FIXED), mremap, serta beberapa jalur madvise yang bersifat destruktif
  • Jika memfd_create atau memfd_secret lebih 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 lewat munmap/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_create dan memfd_secret lebih dekat ke keluarga file sealing
    • Dapat membuat file anonim berbasis RAM
    • memfd_secret membuat 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
  • mseal adalah 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)
    • start dan len menunjukkan awal dan panjang VMA valid yang akan disegel
    • len harus selaras halaman dengan benar
    • Saat ini flags belum digunakan dan harus bernilai 0
  • Implementasi berdasarkan Linux 6.12 memanggil do_mseal
    • current->mm menunjuk ke mm_struct, yaitu seluruh ruang alamat memori virtual proses pemanggil
    • mmap di dalam mm_struct menyimpan daftar vm_area_struct, yaitu area memori berurutan yang dibuat dengan mmap
    • Area seperti stack atau VDSO juga dapat direpresentasikan sebagai satu VMA
  • do_mseal menghitung alamat akhir rentang lalu mengunci area memori dengan mmap_write_lock_killable
  • check_mm_seal menelusuri 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
  • apply_mm_seal menelusuri kembali rentang yang sama dan menambahkan flag VM_SEALED ke VMA target melalui mseal_fixup

Operasi memori yang dilarang setelah penyegelan

  • Patchset kernel menambahkan pemeriksaan VM_SEALED ke mm/madvise.c, mm/mmap.c, mm/mprotect.c, mm/mremap.c, mm/mseal.c
  • mprotect dan pkey_mprotect secara internal memanggil can_modify_vma dari mprotect_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)
    • madvise dengan beberapa flag destruktif tertentu
  • 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 penyegelan munmap
  • Di Linux 6.10 ke atas, mseal bisa digunakan lewat pemanggilan syscall langsung, dan wrapper contohnya memakai nomor syscall 462 dengan flags=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, pemeriksaan can_modify_vma saat mprotect akan 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, mprotect tidak dapat benar-benar mengubah izin, dan eksekusi shellcode memicu segmentation fault

Keterbatasan penerapan pada stack dan heap

  • Jika mseal diadopsi 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 brk untuk mencoba mengembalikan ruang
    • Pada jalur ini, penyusutan dapat terjadi melalui arch_unmap dan do_vmi_unmap
    • Dalam status tersegel, unmapping seperti ini tidak diizinkan sehingga alokasi memori dinamis dapat rusak
  • 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 mseal lagi 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 mmap area executable baru dan menyalin payload dari area yang dapat dibaca, tetapi prosedurnya menjadi lebih merepotkan

Mitigasi eksploit khusus data berbasis unmapping

  • Pemblokiran mprotect juga 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
  • mseal dapat 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, malloc dan free masing-masing akan langsung memanggil mmap dan munmap
  • 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 free dipanggil, munmap dapat terjadi pada area memori yang bersebelahan dengan chunk
  • Contoh Dulin menargetkan area .gnu.hash dan .dynsym dengan munmap sewenang-wenang
    • Lalu mengisinya kembali dengan chunk mmap yang lebih besar
    • Sehingga satu entri PLT yang belum di-resolve dapat ditimpa
    • Ini menghidupkan kembali serangan bergaya GOT overwrite
  • PoC yang diringkas mengalokasikan dua chunk besar, memanipulasi field size dari top[-1], lalu dengan free(top) melakukan unmapping hingga area yang bersebelahan, dan mengisi ulang dengan data X lewat alokasi yang lebih besar
  • Teknik ini dapat tetap bekerja meskipun ada CFI, dan tidak memerlukan kebocoran ASLR sebelumnya
  • Dalam integrasi mseal ke 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 mmap yang tidak akan berkembang atau di-unmap selama masa hidup program

Cakupan penggunaan ke depan

  • mseal adalah 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 flags yang 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

 
GN⁺ 2024-10-27
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

    • Entah apakah ada selain thread yang ditautkan, tetapi secara umum gayanya blak-blakan ala Linus
      Di antara flag yang diusulkan ada yang memungkinkan seal diabaikan, dan Linus bereaksi kurang lebih seperti, “jadi di satu tempat munmap tidak 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
    • https://lwn.net/ml/linux-kernel/7071.1697661373@cvs.openbsd....
      Dalam email Theo de Raadt kepada Jeff Xu, ketika Jeff mengatakan bahwa pendekatan mimmutable() dan mseal() 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, dan ld.so yang akan bertanggung jawab
    • Matthew Wilcox juga menjawab Jeff Xu dengan keras, kira-kira “terima kasih sudah menunjukkan bahwa Anda tidak tahu apa yang perlu dicegah”
      Ia sepakat dengan Theo dan Linus, dan menilai ide dasar mimmutable() bagus, tetapi cara ide itu dipecah dan diimplementasikan mengerikan
    • Artikel ini mungkin membantu: https://lwn.net/Articles/948129/
  • Saya 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

    • Di sini multiproses bisa menjadi opsi
      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 penasaran, fitur keamanan yang tidak digunakan atau jarang digunakan apa saja di x86_64 yang bisa dipakai tanpa perlu sistem operasi menyediakan cara untuk menggunakan atau mengaktifkannya?
      Saya juga penasaran mengapa Anda menganggap mseal tidak dapat dibenarkan, dan apa yang menurut Anda lebih baik sebagai gantinya
  • Apakah bisa menimpa atau menonaktifkan system call mseal dengan trik LD_PRELOAD?

    • Berbeda dari metode perlindungan memori Linux yang sudah ada, mseal adalah system call yang ditujukan untuk mitigasi serangan eksekusi kode jarak jauh, bukan untuk menghadapi penyerang lokal yang ingin mengekstrak rahasia sensitif dari dalam memori
      Jika penyerang jarak jauh bisa mengubah lingkungan lokal, itu harus dianggap bahwa sistem sudah berhasil disusupi
    • Kemungkinan tidak bisa dengan LD_PRELOAD
      Agar 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 mseal berfungsi mungkin merupakan cara termudah untuk “menonaktifkan” fitur ini
      Namun program yang memakai mseal bisa memverifikasi apakah ia benar-benar bekerja, sehingga kernel yang telah dikompromikan juga perlu cara untuk menonaktifkan mseal secara diam-diam agar pemeriksaan aplikasi setelah diterapkan tidak terdeteksi
    • Jika sudah memiliki kendali pada tahap awal proses, ada cukup banyak cara untuk menimpanya
      Misalnya, menjalankan executable di bawah pelacakan ptrace untuk memantau system call lalu melewati mseal(2)
      System call ini bukan untuk model ancaman “penyerang sudah memiliki akses sebelum inisialisasi proses”
    • Wrapper pemanggilan mseal bisa ditimpa, tetapi system call itu sendiri tidak bisa ditimpa
      Setelah 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 syscall itu sendiri bisa ditimpa
    • Menurut https://lwn.net/Articles/978010/, glibc tunable akan ditambahkan
  • Meta: prototipe mseal() yang muncul di artikel perlu diedit
    Argumen pertama ditampilkan sebagai unsigned start addr, tetapi kemungkinan yang benar adalah unsigned long start_addr

    • Sekarang tampaknya sudah benar: int 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 dibahas

  • OpenBSD 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

    • mimmutable di 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 pada shm_open