Tidak memungkinkan program mode pengguna untuk mengakses memori ruang kernel dan menjalankan instruksi IN dan OUT mengalahkan tujuan memiliki mode CPU?

19

Ketika CPU dalam mode pengguna, CPU tidak dapat menjalankan instruksi yang diistimewakan dan tidak dapat mengakses memori ruang kernel.

Dan ketika CPU dalam mode kernel, CPU dapat menjalankan semua instruksi dan dapat mengakses semua memori.

Sekarang di Linux, program mode pengguna dapat mengakses semua memori (menggunakan /dev/mem) dan dapat menjalankan dua instruksi istimewa INdan OUT(menggunakan iopl()saya pikir).

Jadi program mode pengguna di Linux dapat melakukan banyak hal (saya pikir sebagian besar hal) yang dapat dilakukan dalam mode kernel.

Tidak memungkinkan program mode pengguna untuk memiliki semua kekuatan ini mengalahkan tujuan memiliki mode CPU?

pengguna341099
sumber

Jawaban:

23

Jadi program mode pengguna di Linux dapat melakukan banyak hal (saya pikir sebagian besar hal) yang dapat dilakukan dalam mode kernel.

Ya, tidak semua program mode pengguna bisa, hanya yang memiliki hak istimewa yang sesuai. Dan itu ditentukan oleh kernel.

/dev/memdilindungi oleh izin akses sistem file biasa, dan CAP_SYS_RAWIOkemampuan. iopl()dan ioperm()juga dibatasi melalui kemampuan yang sama.

/dev/memjuga dapat dikompilasi dari kernel ( CONFIG_DEVMEM).

Tidak memungkinkan program mode pengguna untuk memiliki semua kekuatan ini mengalahkan tujuan memiliki mode CPU?

Ya, mungkin. Itu tergantung pada apa yang Anda ingin proses ruang pengguna istimewa untuk dapat melakukan. Proses ruang pengguna juga dapat membuang seluruh hard drive jika mereka memiliki akses ke /dev/sda(atau yang setara), meskipun itu mengalahkan tujuan memiliki driver sistem file untuk menangani akses penyimpanan.

(Lalu ada juga fakta yang iopl()bekerja dengan memanfaatkan mode hak istimewa CPU pada i386, sehingga tidak bisa dikatakan mengalahkan tujuan mereka.)

ilkkachu
sumber
2
Bahkan iopltidak mengizinkan semua instruksi istimewa, jadi masih berguna untuk memastikan program ruang pengguna buggy tidak sengaja dijalankan invddengan melompat melalui pointer fungsi yang rusak yang menunjuk pada memori yang dapat dieksekusi dimulai dengan 0F 08byte. Saya menambahkan jawaban dengan beberapa alasan non-keamanan mengapa bermanfaat jika proses ruang pengguna meningkatkan hak istimewa mereka.
Peter Cordes
16

Hanya dengan cara yang sama yang modprobe"mengalahkan" keamanan dengan memuat kode baru ke dalam kernel.

Karena berbagai alasan, kadang-kadang lebih masuk akal untuk memiliki kode semi-privilege (seperti driver grafis di dalam server X) yang berjalan di ruang pengguna daripada thread kernel.

  • Mampu melakukannya killdengan lebih mudah, kecuali itu mengunci HW.
  • Setelah itu meminta halaman kode / data dari file di sistem file. (Memori kernel tidak dapat di-page)
  • Memberikannya ruang alamat virtual sendiri di mana bug di server X mungkin hanya crash server X, tanpa mencatat kernel.

Itu tidak melakukan banyak untuk keamanan, tetapi ada keandalan besar dan keunggulan arsitektur perangkat lunak.

Memanggang driver grafis ke dalam kernel dapat mengurangi switch konteks antara klien X dan server X, seperti hanya satu pengguna-> kernel-> pengguna daripada harus memasukkan data ke proses penggunaan-ruang lain, tetapi server X secara historis terlalu besar dan terlalu bermasalah. ingin mereka sepenuhnya di kernel.


Ya, kode jahat dengan privs ini dapat mengambil alih kernel jika diinginkan, gunakan /dev/memuntuk mengubah kode kernel.

Atau pada x86 misalnya, jalankan cliinstruksi untuk menonaktifkan interupsi pada inti tersebut setelah melakukan ioplpemanggilan sistem untuk mengatur tingkat hak istimewa IO untuk berdering 0.

Tetapi bahkan x86 iopl"only" memberikan akses ke beberapa instruksi : in / out (dan versi string sel / out), dan cli / sti. Itu tidak membiarkan Anda menggunakan rdmsratau wrmsrmembaca atau menulis "register model spesifik" (mis. IA32_LSTARYang menetapkan alamat titik entri kernel untuk syscallinstruksi x86-64 ), atau digunakan lidtuntuk mengganti tabel interrupt-descriptor (yang akan membuat Anda benar-benar mengambil melalui mesin dari kernel yang ada, setidaknya pada inti itu.)

Anda bahkan tidak dapat membaca register kontrol (seperti CR3 yang menyimpan alamat fisik direktori-halaman tingkat atas, yang mana suatu proses serangan mungkin berguna sebagai pengimbang /dev/memuntuk memodifikasi tabel halamannya sendiri sebagai alternatif untuk mengambil mmaplebih banyak /dev/mem. )

invd(batalkan semua cache tanpa write-back !! ( use case = BIOS awal sebelum RAM dikonfigurasi)) adalah kesenangan lain yang selalu membutuhkan CPL 0 penuh (level privilege saat ini), bukan hanya IOPL. Bahkan wbinvdistimewa karena sangat lambat (dan tidak terputus), dan harus mem - flush semua cache di semua core. (Lihat Apakah ada cara untuk menyiram seluruh cache CPU yang terkait dengan suatu program? Dan penggunaan instruksi WBINVD )

Bug yang mengakibatkan lompatan ke alamat yang buruk menjalankan data sebagai kode sehingga tidak bisa menjalankan instruksi ini secara tidak sengaja di server X ruang pengguna.


Level privilege saat ini (dalam mode terlindungi dan panjang) adalah 2 bit rendah cs(pemilih segmen kode) . mov eax, cs/ and eax, 3Bekerja dalam mode apa pun untuk membaca tingkat hak istimewa.

Untuk menulis level privilege, Anda melakukan jmp faratau call faruntuk mengatur CS:RIP(tetapi entri GDT / LDT untuk segmen target dapat membatasinya berdasarkan level privilege lama, itulah sebabnya ruang pengguna tidak dapat melakukan ini untuk meningkatkan dirinya sendiri). Atau Anda menggunakan intatau syscalluntuk beralih ke dering 0 pada titik masuk kernel.

Peter Cordes
sumber
Sebenarnya, saya cukup yakin itu hanya kode "selector" di Intel parlace. Itu adalah segmen di 8086/8088, mungkin di 80186, tetapi pada 80286, itu disebut sebagai pemilih, dan saya tidak berpikir mereka secara resmi mengubah terminologi itu sejak itu.
CVn