¿Qué hace esto exactamente? No entiendo cómo puedes acceder a la memoria base con esto ... parece un poco extraño. ¿Es seguro?
dd if=/dev/urandom of=/dev/mem
¿Qué hace esto exactamente? No entiendo cómo puedes acceder a la memoria base con esto ... parece un poco extraño. ¿Es seguro?
dd if=/dev/urandom of=/dev/mem
Respuestas:
En realidad, en la mayoría de las plataformas, simplemente falla con un error, pero eso depende de la arquitectura del hardware. Definitivamente no hay garantía de que esto sea inofensivo a menos que ejecute el comando como un usuario sin privilegios. Con un usuario sin privilegios, el comando es perfectamente inofensivo porque no se puede abrir /dev/mem
.
Cuando ejecuta un comando como root, se supone que debe saber lo que está haciendo. El núcleo a veces le impedirá hacer algo peligroso, pero no siempre. /dev/mem
es una de esas cosas potencialmente peligrosas donde realmente se supone que debes saber lo que estás haciendo.
Voy a ver cómo funciona una escritura /dev/mem
en Linux. El principio general sería el mismo en otros Unices, pero cosas como las opciones del kernel son completamente diferentes.
Lo que sucede cuando un proceso lee o escribe en un archivo de dispositivo depende del núcleo. Un acceso a un archivo de dispositivo ejecuta un código en el controlador que maneja este archivo de dispositivo. Por ejemplo, escribir en /dev/mem
invoca la función write_mem
endrivers/char/mem.c
. Esta función toma 4 argumentos: una estructura de datos que representa el archivo abierto, un puntero a los datos a escribir, el número de bytes a escribir y la posición actual en el archivo.
Tenga en cuenta que solo llega tan lejos si la persona que llama tenía permiso para abrir el archivo en primer lugar. Los archivos del dispositivo obedecen los permisos de archivo normalmente. Los permisos normales de /dev/mem
son crw-r-----
propiedad de root:kmem
, por lo que si intenta abrirlo para escribir sin ser root, simplemente obtendrá un "permiso denegado" (EACCESS). Pero si eres root (o si root ha cambiado los permisos de este archivo), la apertura continúa y luego puedes intentar una escritura.
El código en la write_mem
función realiza algunas comprobaciones de cordura, pero estas comprobaciones no son suficientes para proteger contra todo lo malo. Lo primero que hace es convertir la posición actual del archivo *ppos
a una dirección física. Si eso falla (en la práctica, porque está en una plataforma con direcciones físicas de 32 bits pero con compensaciones de archivos de 64 bits y el desplazamiento del archivo es mayor que 2 ^ 32), la escritura falla con EFBIG (archivo demasiado grande). La siguiente comprobación es si el rango de direcciones físicas para escribir es válido en esta arquitectura de procesador en particular, y si se produce una falla en EFAULT (dirección incorrecta).
A continuación, en Sparc y m68k, cualquier parte de la escritura en la primera página física se omite silenciosamente.
Ahora hemos llegado al bucle principal que itera sobre los datos en bloques que pueden caber dentro de una página MMU .
/dev/mem
accede a la memoria física, no a la memoria virtual, pero las instrucciones del procesador para cargar y almacenar datos en la memoria usan direcciones virtuales, por lo que el código debe organizarse para asignar la memoria física en alguna dirección virtual. En Linux, dependiendo de la arquitectura del procesador y la configuración del núcleo, esta asignación existe de forma permanente o debe realizarse sobre la marcha; ese es el trabajo de xlate_dev_mem_ptr
(y unxlate_dev_mem_ptr
deshace lo xlate_dev_mem_ptr
que sea que haga). Luego, la función copy_from_user
lee del búfer que se pasó alwrite
llama al sistema y simplemente escribe en la dirección virtual donde está asignada actualmente la memoria física. El código emite instrucciones normales de almacenamiento de memoria, y lo que esto significa depende del hardware.
Antes de discutir que una escritura en una dirección física sí, hablaré sobre un cheque que ocurre antes de esta escritura. Dentro del bucle, la función page_is_allowed
bloquea los accesos a ciertas direcciones si la opción de configuración del núcleo CONFIG_STRICT_DEVMEM
está habilitada (que es el caso por defecto): solo devmem_is_allowed
se puede acceder a las direcciones permitidas por /dev/mem
, para otros la escritura falla con EPERM (operación no permitida). La descripción de esta opción establece:
Si esta opción está activada y IO_STRICT_DEVMEM = n, el archivo / dev / mem solo permite el acceso del espacio de usuario al espacio PCI y al código del BIOS y las regiones de datos. Esto es suficiente para dosemu y X y para todos los usuarios comunes de / dev / mem.
Esta es una descripción muy centrada en x86. De hecho, de manera más genérica, CONFIG_STRICT_DEVMEM
bloquea el acceso a las direcciones de memoria física que se asignan a la RAM, pero permite el acceso a las direcciones que no se asignan a la RAM. Los detalles de qué rangos de dirección física están permitidos dependen de la arquitectura del procesador, pero todos ellos excluyen la RAM donde se almacenan los datos del kernel y de los procesos de aterrizaje del usuario. La opción adicional CONFIG_IO_STRICT_DEVMEM
(deshabilitada a partir de Ubuntu 18.04) bloquea los accesos a las direcciones físicas que son reclamadas por un controlador.
Direcciones de memoria física que se asignan a RAM . Entonces, ¿hay direcciones de memoria física que no se asignan a la RAM? Si. Esa es la discusión que prometí anteriormente sobre lo que significa escribir en una dirección.
Una instrucción de almacenamiento de memoria no necesariamente escribe en la RAM. El procesador descompone la dirección y decide a qué periférico enviar la tienda. (Cuando digo "el procesador", incluyo controladores periféricos que pueden no provenir del mismo fabricante). La RAM es solo uno de esos periféricos. La forma en que se realiza el despacho depende mucho de la arquitectura del procesador, pero los fundamentos son más o menos los mismos en todas las arquitecturas. El procesador básicamente descompone los bits más altos de la dirección y los busca en algunas tablas que se rellenan en función de información codificada, información obtenida al sondear algunos buses e información configurada por el software. Puede haber una gran cantidad de almacenamiento en caché y almacenamiento en búfer, pero en pocas palabras, después de esta descomposición,autobús y luego depende del periférico manejarlo. (O el resultado de la búsqueda en la tabla podría ser que no hay periféricos en esta dirección, en cuyo caso el procesador ingresa en un estado de trampa donde ejecuta algún código en el núcleo que normalmente resulta en un SIGBUS para el proceso de llamada).
Una tienda a una dirección que se asigna a la RAM no "hace" nada más que sobrescribir el valor que se almacenó previamente en esta dirección, con la promesa de que una carga posterior en la misma dirección devolverá el último valor almacenado. Pero incluso la RAM tiene algunas direcciones que no se comportan de esta manera: tiene algunos registros que pueden controlar cosas como la frecuencia de actualización y el voltaje.
En general, una lectura o escritura en un registro de hardware hace lo que el hardware está programado para hacer. La mayoría de los accesos al hardware funcionan de esta manera: el software (normalmente el código del núcleo) accede a una determinada dirección física, llega al bus que conecta el procesador con el periférico, y el periférico hace lo suyo. Algunos procesadores (en particular, x86) también tienen instrucciones de CPU separadas que provocan lecturas / escrituras en periféricos que son distintos de la carga y almacenamiento de memoria, pero incluso en x86, muchos periféricos se alcanzan a través de carga / almacenamiento.
El comando dd if=/dev/urandom of=/dev/mem
escribe datos aleatorios en cualquier periférico asignado en la dirección 0 (y direcciones posteriores, siempre que las escrituras tengan éxito). En la práctica, espero que en muchas arquitecturas, la dirección física 0 no tenga ningún periférico asignado o RAM, y por lo tanto, el primer intento de escritura falla. Pero si hay un periférico asignado en la dirección 0, o si cambia el comando para escribir en una dirección diferente, activará algo impredecible en el periférico. Con datos aleatorios en direcciones crecientes, es poco probable que haga algo interesante, pero en principio podría apagar la computadora (probablemente haya una dirección que de hecho haga esto), sobrescribir alguna configuración del BIOS que hace que sea imposible arrancar, o incluso golpear algunas periférico con errores de manera que lo dañe.
alias Russian_roulette='dd if=/dev/urandom of=/dev/mem seek=$((4096*RANDOM+4096*32768*RANDOM))'
CONFIG_STRICT_DEVMEM
está habilitado.
Por página manual mem (4) :
/ dev / mem es un archivo de dispositivo de caracteres que es una imagen de la memoria principal de la computadora. Puede usarse, por ejemplo, para examinar (e incluso parchear) el sistema.
Entonces, en teoría, dd if=/dev/urandom of=/dev/mem
debería sobrescribir todo el espacio de direcciones de la memoria física que ha instalado, y dado que el núcleo y otros programas se ejecutan desde la memoria, esto debería bloquear efectivamente el sistema. En la práctica, hay un límite. Desde la misma página de manual:
Desde Linux 2.6.26, y dependiendo de la arquitectura, la opción de configuración del núcleo CONFIG_STRICT_DEVMEM limita las áreas a las que se puede acceder a través de este archivo.
Al intentar esto en la máquina virtual Ubuntu 18.04, devuelve un error dd: writing to '/dev/mem': Operation not permitted
incluso con sudo
y a pesar de los permisos para root crw-r-----
. De Ubuntu Wiki :
/ dev / mem protección
Algunas aplicaciones (Xorg) necesitan acceso directo a la memoria física desde el espacio del usuario. El archivo especial / dev / mem existe para proporcionar este acceso. En el pasado, era posible ver y cambiar la memoria del núcleo de este archivo si un atacante tenía acceso a la raíz. La opción de kernel CONFIG_STRICT_DEVMEM se introdujo para bloquear el acceso a la memoria que no es del dispositivo (originalmente llamado CONFIG_NONPROMISC_DEVMEM).
Entonces, técnicamente, no, no es seguro (ya que bloquearía el sistema) y si la opción del núcleo CONFIG_STRICT_DEVMEM
está deshabilitada, es un agujero de seguridad, pero por lo que veo hasta ahora, el comando no se ejecutaría si esa opción está habilitada. De acuerdo con el duplicado entre sitios , un reinicio solucionará cualquier problema con él, pero, por supuesto, los datos en la RAM en ese momento se perderían y no se descargarían en el disco (si es necesario).
Hay un método sugerido en el duplicado vinculado anteriormente, por busybox devmem
lo que si está decidido a perder el tiempo con RAM, puede haber una manera después de todo.
CONFIG_STRICT_DEVMEM
, puede acceder a las regiones de memoria donde se asigna un periférico, que es el punto de tener /dev/mem
. Si escribes cosas al azar en periféricos, puede pasar cualquier cosa. Obtiene "operación no permitida" si intenta acceder a una dirección que no está asignada, y el comando comienza en la dirección 0. Si la dirección 0 se asigna a algo malo depende de la arquitectura del hardware. Por lo que sé, es posible que nunca se asigne a nada en una PC, pero en general no es seguro.
head -c 1024 </dev/mem | od -tx1
), pero no sé si se usan cuando el procesador no está en modo real (modo 8088). No creo que puedan usarse en el modo de 64 bits: después de todo, los vectores de interrupción 8088 solo tienen 32 bits para la dirección. Y, por cierto, esto es accesible con CONFIG_STRICT_DEVMEM
set, así que supongo que Linux no lo usa.