Безопасен ли dd if = / dev / urandom of = / dev / mem?

10

Что именно это делает? Я не понимаю, как вы могли получить доступ к базовой памяти с этим ... кажется странным. Это безопасно?

dd if=/dev/urandom of=/dev/mem
Coder14
источник
Что это за «сейф», о котором вы говорите? Безопасен в отношении чего?
вальтинатор
Чего вы хотите добиться с помощью этой команды?
Йохен

Ответы:

23

Не пытайтесь сделать это дома! Это может привести к сбою в работе вашей системы, а если вам действительно не повезет, это может повредить периферийное устройство или сделать ваш компьютер не загружаемым.

На самом деле, на большинстве платформ происходит сбой с ошибкой, но это зависит от аппаратной архитектуры. Совершенно определенно нет гарантии, что это безопасно, если вы не запускаете команду от имени непривилегированного пользователя. Для непривилегированного пользователя команда совершенно безвредна, потому что вы не можете открыть /dev/mem.

Когда вы запускаете команду от имени пользователя root, вы должны знать, что делаете. Ядро иногда мешает вам делать что-то опасное, но не всегда. /dev/memэто одна из тех потенциально опасных вещей, где вы действительно должны знать, что вы делаете.

Я собираюсь рассказать, как работает запись в /dev/memLinux. Общий принцип был бы таким же в других Unices, но такие вещи, как параметры ядра, совершенно разные.

Что происходит, когда процесс читает или записывает файл устройства, зависит от ядра. Доступ к файлу устройства запускает некоторый код в драйвере, который обрабатывает этот файл устройства. Например, запись в /dev/memвызывает функцию write_memвdrivers/char/mem.c . Эта функция принимает 4 аргумента: структуру данных, которая представляет открытый файл, указатель на данные для записи, количество байтов для записи и текущую позицию в файле.

Обратите внимание, что вы получите это далеко, только если у вызывающей стороны было разрешение открыть файл в первую очередь. Файлы устройства соответствуют разрешениям на доступ к файлам. Обычные права доступа /dev/memявляются crw-r-----собственностью root:kmem, так что если вы пытаетесь открыть его для записи , не будучи корнем, вы будете просто получить «доступ запрещен» (EACCESS). Но если вы являетесь пользователем root (или если root изменил права доступа к этому файлу), открытие проходит, и вы можете попытаться выполнить запись.

Код в write_memфункции выполняет некоторые проверки работоспособности, но этих проверок недостаточно для защиты от всего плохого. Первым делом он конвертирует текущую позицию файла *pposв физический адрес. Если это не удается (на практике, потому что вы находитесь на платформе с 32-разрядными физическими адресами, но смещениями 64-разрядных файлов и смещением файлов больше, чем 2 ^ 32), запись завершится неудачно с EFBIG (файл слишком большой). Следующая проверка заключается в том, допустим ли диапазон физических адресов для записи на этой конкретной архитектуре процессора, и в случае сбоя происходит EFAULT (неверный адрес).

Затем в Sparc и m68k любая часть записи на самой первой физической странице молча пропускается.

Теперь мы достигли основного цикла, который перебирает данные в блоках, которые могут уместиться на одной странице MMU . /dev/memосуществляет доступ к физической памяти, а не к виртуальной памяти, но инструкции процессора для загрузки и хранения данных в памяти используют виртуальные адреса, поэтому код должен быть организован для сопоставления физической памяти с некоторым виртуальным адресом. В Linux, в зависимости от архитектуры процессора и конфигурации ядра, это отображение либо существует постоянно, либо должно выполняться на лету; это работа xlate_dev_mem_ptrunxlate_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) блокирует доступ к физическим адресам, которые запрашивает драйвер.

Адреса физической памяти, которые отображаются в ОЗУ . То есть есть адреса физической памяти, которые не отображаются в ОЗУ? Да. Это обсуждение, которое я обещал выше о том, что значит писать по адресу.

Инструкция хранения памяти не обязательно записывает в RAM. Процессор разбирает адрес и решает, на какое периферийное устройство отправить хранилище. (Когда я говорю «процессор», я имею в виду периферийные контроллеры, которые могут не принадлежать одному и тому же производителю.) ОЗУ - это только одна из этих периферийных устройств. То, как выполняется диспетчеризация, очень зависит от архитектуры процессора, но основные принципы более или менее одинаковы для всех архитектур. Процессор в основном разбирает старшие биты адреса и просматривает их в некоторых таблицах, которые заполняются на основе жестко закодированной информации, информации, полученной при проверке некоторых шин, и информации, сконфигурированной программным обеспечением. Может быть много кеширования и буферизации, но в двух словах, после этого разложения,автобус, а затем дело до периферии, чтобы справиться с этим. (Или результатом поиска в таблице может быть отсутствие периферийного устройства по этому адресу, и в этом случае процессор переходит в состояние прерывания, где он выполняет некоторый код в ядре, что обычно приводит к 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))'
Жиль "ТАК - прекрати быть злым"
источник
Спасибо! Это то, что я искал! Меня просто смутило, разрешает ли / dev / mem доступ к памяти для таких вещей, как периферийные устройства и аппаратные средства!
Coder14
Не удается подключить периферийное устройство по физическому адресу 0 на компьютере x86; эта конфигурация никогда не загрузится.
Джошуа
Это не верно
Yvain
1
Конечно, вы можете повредить ядро, но не биос
Yvain
1
@ Yvain Что не так? И на самом деле вы не можете повредить ядро, если CONFIG_STRICT_DEVMEMоно включено.
Жиль "ТАК - перестань быть злым"
12

Это безопасно, если вы правильно настроили ядро ​​(безопасно, потому что оно не будет работать)

За страницу справки mem (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 существует для предоставления этого доступа. В прошлом было возможно просматривать и изменять память ядра из этого файла, если у злоумышленника был root-доступ. Опция ядра CONFIG_STRICT_DEVMEM была введена для блокировки доступа к памяти вне устройства (первоначально называлась CONFIG_NONPROMISC_DEVMEM).

Технически, нет, это небезопасно (так как это приведет к краху системы), и если опция ядра CONFIG_STRICT_DEVMEMотключена, это дыра в безопасности, но из того, что я вижу до сих пор, команда не запустится, если эта опция включена. Согласно межсайтовому дубликату , перезагрузка исправит все проблемы с ним, но, конечно, данные в ОЗУ в это время будут потеряны и не будут записаны на диск (если таковые были).

Для дубликата, связанного ранее, предложен метод, busybox devmemпоэтому, если вы решили возиться с оперативной памятью, в конце концов, возможно, найдется способ.

Сергей Колодяжный
источник
6
«Это безопасно» Нет, это, безусловно, нет. Даже при этом CONFIG_STRICT_DEVMEMвы можете получить доступ к областям памяти, где отображается периферийное устройство, и в этом весь смысл /dev/mem. Если вы пишете случайные вещи на периферию, все может случиться. Вы получаете «операция не разрешена», если вы пытаетесь получить доступ к адресу, который не отображается, и команда начинается с адреса 0. Соответствует ли адрес 0 чему-то плохому, зависит от аппаратной архитектуры. Насколько я знаю, он может никогда не отображаться на ПК, но в целом он небезопасен.
Жиль "ТАК - перестань быть злым"
1
@Gilles На x86 (не уверен насчет x86-64), первые 1 КБ ОЗУ (адреса от 0x0 до 0x3ff) содержат векторы прерываний; адрес в четыре байта на вектор. Если вам удастся перезаписать эти файлы случайным мусором, все виды интересных вещей могут произойти очень скоро. Скорее всего, вы получите двойной или тройной сбой, и система выйдет из строя, но нет никаких гарантий ...
CVn
@aCVn Конечно, есть что-то сопоставленное ( head -c 1024 </dev/mem | od -tx1), но я не знаю, используются ли они, когда процессор не находится в реальном режиме (режим 8088). Я не думаю, что они могут использоваться в 64-битном режиме: в конце концов, векторы прерываний 8088 имеют только 32 бита для адреса. И, кстати, это доступно через CONFIG_STRICT_DEVMEMset, так что я думаю, что Linux не использует его.
Жиль "ТАК - перестань быть злым"
@Gilles: страница 0 на x86 зарезервирована для v86, загрузчика и т.д .; это таблица векторов прерываний реального режима. В защищенном режиме IVT находится где-то еще (регистр машины говорит, где).
Джошуа