GNU/Linux >> Belajar Linux >  >> Linux

Mengapa ada kebutuhan untuk memodifikasi tabel system call di Linux?

Anda dapat memeriksa apakah itu hanya-baca dengan melihat simbol kernel. "R" berarti hanya-baca.

$ grep sys_call_table /proc/kallsyms
0000000000000000 R sys_call_table
0000000000000000 R ia32_sys_call_table
0000000000000000 R x32_sys_call_table

Jadi mereka adalah read-only, dan sejak kernel 2.6.16. Namun, rootkit kernel memiliki kemampuan untuk membuatnya dapat ditulis kembali. Yang perlu dilakukan hanyalah menjalankan fungsi seperti ini dalam mode kernel (secara langsung atau melalui gadget ROP yang cukup fleksibel, yang jumlahnya banyak) dengan masing-masing alamat sebagai argumen:

static void set_addr_rw(const unsigned long addr)
{
    unsigned int level;
    pte_t *pte = lookup_address(addr, &level);

    if (pte->pte &~ _PAGE_RW)
        pte->pte |= _PAGE_RW;

    local_flush_tlb();
}

Ini mengubah izin tabel syscall dan memungkinkan untuk mengeditnya. Jika ini tidak berhasil karena alasan apa pun, proteksi tulis di kernel dapat dinonaktifkan secara global dengan ASM berikut:

cli
mov %cr0, %eax
and $~0x10000, %eax
mov %eax, %cr0
sti

Ini menonaktifkan interupsi, menonaktifkan bit WP (Write-Protect) di CR0, dan mengaktifkan kembali interupsi. Menggunakan perakitan memungkinkan ini berfungsi meskipun write_cr0(read_cr0() & ~0x10000) gagal karena fungsi yang telah ditentukan untuk menulis ke CR0 sekarang menyematkan bit sensitif. Pastikan Anda mengaktifkan kembali WP setelahnya!

Jadi mengapa ditandai sebagai read-only jika sangat mudah untuk dinonaktifkan? Salah satu alasannya adalah adanya kerentanan yang memungkinkan memodifikasi memori kernel tetapi tidak harus mengeksekusi kode secara langsung. Dengan menandai area kritis kernel sebagai hanya-baca, akan menjadi lebih sulit untuk mengeksploitasinya tanpa menemukan tambahan kerentanan untuk menandai halaman sebagai dapat ditulisi (atau menonaktifkan perlindungan tulis sama sekali). Sekarang, ini tidak memberikan keamanan yang sangat kuat, jadi alasan utama ditandai sebagai hanya-baca adalah untuk memudahkan penghentian kebetulan ditimpa dari menyebabkan kerusakan sistem yang parah dan tidak dapat dipulihkan.

* Contoh khusus yang diberikan adalah untuk prosesor x86_64. Tabel pertama adalah untuk syscall dalam mode 64-bit asli (x64). Yang kedua adalah untuk syscall dalam mode 32-bit (IA32). Yang ketiga adalah untuk ABI syscall x32 yang jarang digunakan yang memungkinkan program menggunakan semua fitur mode 64-bit (mis. SSE alih-alih x87 untuk operasi floating point) saat menggunakan pointer dan nilai 32-bit.

† ​​API internal kernel selalu berubah, jadi fungsi persis ini mungkin tidak berfungsi pada kernel lama atau kernel baru. Menonaktifkan CR0.WP secara global namun di ASM dijamin untuk bekerja pada semua sistem x86 terlepas dari versi kernelnya.


Seperti dicatat oleh forest, Linux modern tidak mengizinkan ini, tetapi mudah untuk ditimpa.

Namun, secara historis itu berguna (dan mungkin masih) untuk tujuan keamanan:hot-patching terhadap kerentanan. Di tahun 1990-an dan awal 2000-an, setiap kali kerentanan baru diumumkan untuk syscall, saya tidak benar-benar membutuhkannya (ptrace adalah yang sangat umum saat itu), saya akan menulis modul kernel untuk menimpa alamat fungsi di tabel syscall dengan alamat fungsi yang baru saja dijalankan return -ENOSYS; . Ini menghilangkan permukaan serangan sampai kernel yang ditingkatkan tersedia. Untuk beberapa syscall yang meragukan, saya tidak perlu berulang kali memiliki kerentanan, saya hanya melakukan ini terlebih dahulu untuk mereka dan membiarkan modul diaktifkan sepanjang waktu.


Linux
  1. Cara memeriksa versi Kernel di Linux

  2. Linux – Mengapa Tidak Ada Sistem File Rootfs Di Sistem?

  3. Linux – Metode Panggilan Sistem di Kernel Baru?

  1. Linux – Mengapa Ada Kebijakan Kernel Linux Untuk Tidak Pernah Melanggar Ruang Pengguna?

  2. Linux – Mengapa Kernel Tidak Dapat Menjalankan Init?

  3. Mengapa kita membutuhkan bootloader di perangkat tertanam?

  1. Mengapa kita membutuhkan file .so.1 di Linux?

  2. Panggilan sistem Linux tercepat

  3. Bagaimana cara meneruskan parameter ke panggilan sistem Linux?