Чи не дозволяє програмі режиму користувача отримати доступ до пам’яті простору ядра та виконувати вказівки IN і OUT, щоб не порушити мету створення режимів процесора?


19

Коли процесор перебуває в режимі користувача, процесор не може виконувати привілейовані інструкції та не може отримати доступ до пам'яті простору ядра.

А коли ЦП знаходиться в режимі ядра, ЦП може виконати всі інструкції та отримати доступ до всієї пам'яті.

Тепер у Linux програма користувальницького режиму може отримати доступ до всієї пам'яті (за допомогою /dev/mem) та може виконати дві привілейовані інструкції INта OUT(використовуючи, iopl()я думаю).

Отже програма користувальницького режиму в Linux може робити більшість речей (я думаю, більшість речей), що можна зробити в режимі ядра.

Чи не дозволяє програма користувальницького режиму мати всю цю потужність, перемагає призначення режимів процесора?

Відповіді:


23

Отже програма користувальницького режиму в Linux може робити більшість речей (я думаю, більшість речей), що можна зробити в режимі ядра.

Ну, не всі програми в режимі користувача можуть, лише ті, що мають відповідні привілеї. І це визначається ядром.

/dev/memзахищений звичайними дозволами доступу до файлової системи та CAP_SYS_RAWIOможливістю. iopl()а ioperm()також обмежуються через однакові можливості.

/dev/memможе також бути складений з ядра зовсім ( CONFIG_DEVMEM).

Чи не дозволяє програма користувальницького режиму мати всю цю потужність, перемагає призначення режимів процесора?

Ну, можливо. Це залежить від того, що ви хочете, щоб процес привілейованого простору користувача міг робити. Процеси в просторі користувача можуть також переносити весь жорсткий диск, якщо він має доступ до /dev/sda(або еквівалент), навіть якщо це перешкоджає призначенню драйвера файлової системи для обробки доступу до пам’яті.

(Тоді також є факт, що iopl()працює, використовуючи режими привілеїв процесора на i386, тому не можна сказати, що вони перемогли їхню мету.)


2
Навіть ioplне дає всіх привілейованих інструкцій, тому вона все ще корисна для того, щоб переконатися, що програма-баггі-простір користувача не випадково запускається invd, перестрибуючи пошкоджений вказівник функції, який вказує на виконувану пам'ять, починаючи з 0F 08байтів. Я додав відповідь із деяких причин, що не стосуються безпеки, чому корисно, щоб процеси в просторі користувачів підвищували свої привілеї.
Пітер Кордес

16

Тільки так, як modprobe"перемагає" безпеку, завантажуючи новий код у ядро.

З різних причин іноді має сенс мати напівпривілейований код (наприклад, графічні драйвери всередині сервера X), що працює в просторі користувача, а не в потоці ядра.

  • Вміти killце легше, якщо тільки він не замикає HW.
  • Запросивши на сторінку запит свого коду / даних з файлів у файловій системі. (Пам'ять ядра не є сторінковим)
  • Надаючи йому власний віртуальний адресний простір, де помилки на сервері X можуть просто зірвати X-сервер, не знімаючи ядро.

Це не дуже сприяє безпеці, але є великі переваги надійності та архітектури програмного забезпечення.

Введення графічних драйверів у ядро ​​може зменшити контекстні комутації між клієнтами X та сервером X, як-от лише один користувач-> kernel-> користувач, замість того, щоб отримувати дані в інший процес використання простору використання, але X-сервери історично занадто великі і занадто глючні бажати їх повністю в ядрі.


Так, зловмисний код із цими приватними кодами може захопити ядро, якщо воно захоче, використовуючи /dev/memдля зміни коду ядра.

Наприклад, на x86, запустіть cliінструкцію щодо відключення переривань на цьому ядрі після ioplвиклику системи, щоб встановити рівень привілеїв вводу-виводу на дзвінок 0.

Але навіть x86 iopl"тільки" надає доступ до деяких вказівок : вхід / вихід (і рядкові версії вводу / виходу) та cli / sti. Це не дозволяє використовувати rdmsrабо wrmsrчитати чи записувати "типові регістри моделей" (наприклад, IA32_LSTARяка встановлює адресу точки введення ядра для syscallінструкції x86-64 ), або використовувати lidtдля заміни таблиці дескрипторів переривання (що дозволило б вам повністю прийняти над машиною з існуючого ядра, принаймні на цьому ядрі.)

Ви навіть не можете читати контрольні регістри (як, наприклад, CR3, який містить фізичну адресу сторінки-каталогу верхнього рівня, що атакувальний процес може бути корисним як зміщення /dev/memдля зміни власних таблиць сторінок як альтернативу mmapбільшій кількості) /dev/mem. )

invd(недійсні всі кеші без зворотного запису !! ( використовуйте case = ранній BIOS до налаштування оперативної пам’яті)) - це ще одна забава, яка завжди потребує повного CPL 0 (поточний рівень привілеїв), а не лише IOPL. Навіть wbinvdпривілейований, тому що він такий повільний (і не перериваючий), і він повинен обмітати всі кеші по всіх ядрах. (Див Чи є спосіб , щоб очистити весь кеш процесора , пов'язаний з програмою? І використання інструкції WBINVD )

Помилки, які призводять до переходу на неправильну адресу, що працює з даними, як код, таким чином, не можуть виконати жодну з цих інструкцій випадково на сервері X-простору користувача.


Поточний рівень привілеїв (у захищеному та тривалому режимі) - це низькі 2 біти cs(селектор кодового сегмента) . mov eax, cs/ and eax, 3працює в будь-якому режимі для читання рівня привілеїв.

Щоб записати рівень привілеїв, ви робите a jmp farабо call farвстановлюєте CS:RIP(але запис GDT / LDT для цільового сегмента може обмежувати його на основі старого рівня привілеїв, через що користувальницький простір не може цього зробити, щоб підвищити себе). Або ви використовуєте intабо syscallдля переключення на дзвінок 0 у точці введення ядра.


Насправді я впевнений, що це просто "селектор" в пакеті Intel. Це був сегмент у 8086/8088, можливо, у 80186, але до 80286 це називалося селектором, і я не думаю, що вони офіційно змінили цю термінологію з тих пір.
CVn
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.