Що саме це робить? Я не розумію, як ви могли отримати доступ до базової пам'яті за допомогою цього ... здається дивним. Це безпечно?
dd if=/dev/urandom of=/dev/mem
Що саме це робить? Я не розумію, як ви могли отримати доступ до базової пам'яті за допомогою цього ... здається дивним. Це безпечно?
dd if=/dev/urandom of=/dev/mem
Відповіді:
Насправді, на більшості платформ воно просто не вдається з помилкою, але це залежить від апаратної архітектури. Однозначно немає гарантії, що це нешкідливо, якщо ви не виконаєте команду як непривілейований користувач. Для непривілейованого користувача команда є абсолютно нешкідливою, тому що ви не можете її відкрити /dev/mem
.
Коли ви запускаєте команду як root, ви повинні знати, що ви робите. Ядро іноді заважатиме вам робити щось небезпечне, але не завжди. /dev/mem
- це одна з тих потенційно небезпечних речей, де ти насправді повинен знати, що робиш.
Я збираюся ознайомитись із тим, як /dev/mem
працює запис на Linux. Загальний принцип був би таким же в інших Unices, але такі речі, як параметри ядра, зовсім інші.
Що відбувається, коли процес читає або записує у файл пристрою, залежить від ядра. Доступ до файлу пристрою виконує деякий код у драйвері, який обробляє цей файл пристрою. Наприклад, запис для /dev/mem
виклику функції write_mem
вdrivers/char/mem.c
. Ця функція бере 4 аргументи: структура даних, яка представляє відкритий файл, вказівник на дані, які потрібно записати, кількість байтів для запису та поточне положення у файлі.
Зауважте, що ви дістаєтесь так далеко, лише якщо абонент мав дозвіл на відкриття файлу. Файли пристрою зазвичай дотримуються дозволів файлів. Нормальні права дозволу /dev/mem
є crw-r-----
власником root:kmem
, тому якщо ви спробуєте відкрити його для запису, не використовуючи root, ви просто отримаєте "дозвіл відмовлено" (EACCESS). Але якщо ви root (або якщо root змінив дозволи цього файлу), відкриття проходить, і тоді ви можете спробувати записати.
Код у цій write_mem
функції робить деякі перевірки правильності, але цих перевірок недостатньо для захисту від усього поганого. Перше, що він робить - перетворити поточну позицію файлу *ppos
у фізичну адресу. Якщо це не вдається (на практиці, оскільки ви знаходитесь на платформі з 32-бітовими фізичними адресами, але 64-розрядні зсуви файлів і зсув файлу більше 2 ^ 32), запис не вдається з EFBIG (файл занадто великий). Наступна перевірка полягає в тому, чи є діапазон фізичних адрес для запису дійсним для даної архітектури процесора, і чи є помилка результатом EFAULT (неправильна адреса).
Далі, на Sparc та m68k будь-яка частина запису на першій фізичній сторінці безшумно пропускається.
Зараз ми дійшли до основного циклу, який повторює дані в блоках, які можуть вміщуватися в межах однієї сторінки MMU .
/dev/mem
отримує доступ до фізичної пам'яті, а не до віртуальної пам'яті, але вказівки процесора для завантаження та зберігання даних у пам'яті використовують віртуальні адреси, тому код потрібно організувати для відображення фізичної пам'яті за деякою віртуальною адресою. В Linux, залежно від архітектури процесора та конфігурації ядра, це відображення існує або постійно, або має бути зроблено на ходу; це робота xlate_dev_mem_ptr
(і unxlate_dev_mem_ptr
скасовує все, що xlate_dev_mem_ptr
робить). Потім функція copy_from_user
зчитується з буфера, який був переданий вwrite
системний виклик і просто записується на віртуальну адресу, де фізична пам'ять на даний момент відображена. Код надсилає звичайні інструкції щодо зберігання пам’яті, а що це означає, залежить від обладнання.
Перш ніж я обговорюю, що записується на фізичну адресу, я обговорюю перевірку, що відбувається до цього запису. Всередині циклу функція page_is_allowed
блокує доступ до певних адрес, якщо CONFIG_STRICT_DEVMEM
включена опція конфігурації ядра (що за замовчуванням є): через них devmem_is_allowed
можна отримати лише ті адреси, дозволені якими /dev/mem
, для інших запис не вдається з EPERM (операція не дозволена). В описі цього параметра зазначено:
Якщо цей параметр увімкнено, а IO_STRICT_DEVMEM = n, файл / dev / mem дозволяє лише користувачеві простору доступ до простору PCI та коду BIOS та областям даних. Цього достатньо для дозиму та X та всіх звичайних користувачів / dev / mem.
Це дуже орієнтований на x86 опис. Фактично, загалом, CONFIG_STRICT_DEVMEM
блокує доступ до адрес фізичної пам'яті, які відображають в оперативній пам'яті, але дозволяє отримати доступ до адрес, які не відображаються в оперативній пам'яті. Деталі дозволених діапазонів фізичної адреси залежать від архітектури процесора, але всі вони виключають оперативну пам’ять, де зберігаються дані ядра та наземних процесів користувача. Додатковий параметр CONFIG_IO_STRICT_DEVMEM
(відключений на Ubuntu 18.04) блокує доступ до фізичних адрес, які вимагає драйвер.
Адреси фізичної пам'яті, які відображають в ОЗП . Отже, є адреси фізичної пам'яті, які не відображаються в ОЗУ? Так. Це обговорення, яке я пообіцяв вище про те, що означає написати на адресу.
Інструкція сховища пам'яті не обов'язково записувати в оперативну пам'ять. Процесор розкладає адресу і вирішує, до якої периферії відправити магазин. (Коли я кажу "процесор", я охоплюю периферійні контролери, які можуть не надходити від одного виробника.) ОЗУ - це лише одна з таких периферійних пристроїв. Те, як здійснюється відправка, дуже залежить від архітектури процесора, але основи більш-менш однакові для всіх архітектур. Процесор в основному розбиває більш високі біти адреси і шукає їх у деяких таблицях, заповнених на основі жорстко кодованої інформації, інформації, отриманої зондуванням деяких шин, та інформації, налаштованої програмним забезпеченням. Можливо, буде задіяно багато кешування та буферизації, але в двох словах, після цього розкладання,автобус, і тоді до периферійних пристроїв впоратися з цим. (Або результатом пошуку таблиці може бути те, що за цією адресою немає периферійного пристрою; у цьому випадку процесор переходить у стан лову, де він виконує якийсь код у ядрі, що зазвичай призводить до SIGBUS для процесу виклику.)
Магазин на адресу, яка відображається в оперативній пам'яті, не "робить" нічого іншого, крім перезапис значення, яке раніше зберігалося за цією адресою, з обіцянкою, що наступне завантаження за тією ж адресою поверне останнє збережене значення. Але навіть ОЗУ має кілька адрес, які не так поводяться: у неї є кілька регістрів, які можуть контролювати такі речі, як частота оновлення та напруга.
Взагалі, читання або запис у реєстр апаратних засобів робить все те, що апаратно запрограмовано. Більшість доступів до апаратних засобів працює таким чином: програмне забезпечення (як правило, код ядра) отримує доступ до певної фізичної адреси, це доходить до шини, яка з'єднує процесор з периферією, а периферія робить свою справу. Деякі процесори (зокрема x86) також мають окремі інструкції процесора, які викликають читання / запис на периферійні пристрої, відмінні від завантаження та зберігання пам'яті, але навіть на x86 багато периферійних пристроїв досягаються через завантаження / зберігання.
Команда dd if=/dev/urandom of=/dev/mem
записує випадкові дані в будь-яку периферію, яка відображається за адресою 0 (та наступними адресами, доки успіх запису). На практиці я вважаю, що у багатьох архітектурах фізична адреса 0 не має певного периферійного відображення до неї або має оперативну пам’ять, і тому сама перша спроба запису не вдається. Але якщо є периферійна карта, відображена за адресою 0, або якщо ви змінили команду для запису на іншу адресу, ви запустите щось непередбачуване в периферії. З випадковими даними при збільшенні адрес навряд чи можна зробити щось цікаве, але в принципі це може вимкнути комп’ютер (можливо, це адреса, яка насправді робить це), перезаписати деякі настройки BIOS, які унеможливлюють завантаження або навіть натискають на деякі баггі периферійний таким чином, що шкодить йому.
alias Russian_roulette='dd if=/dev/urandom of=/dev/mem seek=$((4096*RANDOM+4096*32768*RANDOM))'
CONFIG_STRICT_DEVMEM
воно включене.
На пам'ять сторінки вручну (4) :
/ dev / mem - це файл пристрою символів, який є зображенням основної пам'яті комп'ютера. Він може бути використаний, наприклад, для вивчення (і навіть виправлення) системи.
Тож теоретично dd if=/dev/urandom of=/dev/mem
слід перезаписати весь адресний простір встановленої фізичної пам'яті, а оскільки ядро та інші програми працюють із пам'яті, це повинно ефективно руйнувати систему. На практиці існує обмеження. З тієї ж сторінки чоловіка:
Оскільки Linux 2.6.26 і залежно від архітектури, опція конфігурації ядра CONFIG_STRICT_DEVMEM обмежує області, до яких можна отримати доступ через цей файл.
Спробувавши це на віртуальній машині Ubuntu 18.04, він повертає помилку dd: writing to '/dev/mem': Operation not permitted
навіть з sudo
і незважаючи на дозволи для root crw-r-----
. З Ubuntu Wiki :
/ dev / mem захист
Деякі програми (Xorg) потребують прямого доступу до фізичної пам'яті з користувальницького простору. Для забезпечення цього доступу існує спеціальний файл / dev / mem. Раніше можна було переглядати та змінювати пам'ять ядра з цього файлу, якщо зловмисник мав кореневий доступ. Параметр ядра CONFIG_STRICT_DEVMEM був введений для блокування доступу до пам'яті пристрою (спочатку називався CONFIG_NONPROMISC_DEVMEM).
Таким чином, технічно, ні це не є безпечним (оскільки це призведе до виходу з ладу системи), і якщо параметр ядра CONFIG_STRICT_DEVMEM
відключений, це отвір для безпеки, але, як я бачу, команда не запустилася, якщо цю опцію ввімкнено. Згідно з дублікатом між веб-сайтів , перезавантаження виправить будь-які проблеми з нею, але, звичайно, дані в оперативній пам’яті в цей час будуть втрачені і не видаляються на диск (якщо такі були).
Існує запропонований метод на дублікаті, пов'язаному раніше, використовуючи, busybox devmem
тому якщо ви вирішили возитися з оперативною пам’яттю, все-таки може бути спосіб.
CONFIG_STRICT_DEVMEM
, ви можете отримати доступ до областей пам'яті, де відображена периферія, що є сутністю /dev/mem
. Якщо ви запишете випадкові речі на периферійні пристрої, все може статися. Якщо ви намагаєтеся отримати доступ до адреси, яка не відображається, ви отримуєте "операцію не дозволено", і команда починається з адреси 0. Будь-яка адреса 0 відображається на щось погане, залежить від апаратної архітектури. Наскільки я знаю, це може ніколи не підключатися ні до чого на ПК, але це взагалі не безпечно.
head -c 1024 </dev/mem | od -tx1
), але я не знаю, чи використовуються вони, коли процесор не знаходиться в реальному режимі (режим 8088). Я не думаю, що їх можна використовувати в 64-бітному режимі: зрештою, вектори переривання 8088 мають лише 32 біти для адреси. І, до речі, це доступно з CONFIG_STRICT_DEVMEM
набором, тому я думаю, що Linux не використовує його.