Mostrando entradas con la etiqueta ram. Mostrar todas las entradas
Mostrando entradas con la etiqueta ram. Mostrar todas las entradas

lunes, 14 de julio de 2014

Cómo hacer un volcado de memoria (Memory Dump) en Linux?

Por diferentes motivos podríamos querer tener un volcado de memoria de un sistema Linux, por ejemplo:

  • Cuestiones legales, como en un caso de análisis forense sobre un host 
  • Cuestiones de debug, ante un crash del sistema
  • Cuestiones de la vida, curiosidad, etc
La idea de esta entrada es presentar una forma razonable de hacerlo en sistemas GNU/Linux.

Primera aproximación, a por /dev/mem

La primera idea y la mas documentada es leer el dispositivo /dev/mem . Gracias a algún programador (Wietse Venema según el man) existe una aplicación llamada memdump que se encarga precisamente de leer este dispositivo y devolvernos por STDOUT el contenido. Hasta acá parecía todo maravilloso y simple. Entonces probemos memdump:

root@corrientes:/home/jpavlik# memdump  > volcado.mem

La linea anterior me llevó directo a un gigantesco kernel panic y un consecuente reinicio de la PC (posiblemente un problema de mi versión de Ubuntu 13.04, dado que la misma prueba en otros sistemas no terminó en un crash pero tampoco en un dump satisfactorio), por lo tanto vamos a buscar otro camino.
Dado que /dev/mem es un dispositivo

root@corrientes:/home/jpavlik# file /dev/mem 
/dev/mem: character special
root@corrientes:/home/jpavlik# 

lo vamos a tratar como tal y leeremos con dd:

root@corrientes:/home/jpavlik# dd if=/dev/mem of=volcado.mem bs=1M 
dd: leyendo «/dev/mem»: Operación no permitida
1+0 registros leídos
1+0 registros escritos
1048576 bytes (1,0 MB) copiados, 0,125726 s, 8,3 MB/s
root@corrientes:/home/jpavlik# 

si bien esta vez no generamos un gran crash, tampoco obtuvimos un volcado real dado que solo logramos leer 1Mb... y la operación fue detenida.

Leyendo un poco en google resulta ser que existe una opción en tiempo de compilación del kernel que define si será posible o no acceder en espacio de usuario al dispositivo /dev/mem de manera irestricta o no. En nuestro caso

root@corrientes:/home/jpavlik# grep "CONFIG_STRICT_DEVMEM" /usr/src/linux-headers-3.8.0-35-generic/.config
CONFIG_STRICT_DEVMEM=y
root@corrientes:/home/jpavlik# 

la restricción se encuentra efectivamente activada. Dado que al parecer no es posible desactivarla en tiempo de ejecución hay que buscar otro camino que nos permita alcanzar nuestro objetivo.

LiME Forensics

LiME, Linux Memory Extractor es un módulo de linux que nos permitirá acceder a la memoria volatil de manera irestricta ya que a diferencia de memdup o dd, no se ejecuta en espacio de usuario sino en espacio de kernel. Algo muy interesante de LiME es que haciendo uso de la compilación cruzada es posible compilar el módulo para correrlo en dispositivos Android y lograr volcados de memoria de los mismos.
El código de LiME está accesible en http://code.google.com/p/lime-forensics/downloads/list?can=1&q=&colspec=Filename+Summary+Uploaded+ReleaseDate+Size+DownloadCount , una vez descargado podemos acceder a su documentación que viene en un PDF o compilarlo sin demasiadas vueltas:

jpavlik@corrientes:~/LiME$ ls
doc  lime-forensics-1.1-r17.tar.gz  src
jpavlik@corrientes:~/LiME$ cd src/
jpavlik@corrientes:~/LiME/src$ make
make -C /lib/modules/3.8.0-35-generic/build M=/home/jpavlik/LiME/src modules
make[1]: se ingresa al directorio «/usr/src/linux-headers-3.8.0-35-generic»
  CC [M]  /home/jpavlik/LiME/src/tcp.o
  CC [M]  /home/jpavlik/LiME/src/disk.o
  CC [M]  /home/jpavlik/LiME/src/main.o
/home/jpavlik/LiME/src/main.c: En la función ‘__check_dio’:
/home/jpavlik/LiME/src/main.c:56:1: aviso: devolución desde un tipo de puntero incompatible [activado por defecto]
  LD [M]  /home/jpavlik/LiME/src/lime.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/jpavlik/LiME/src/lime.mod.o
  LD [M]  /home/jpavlik/LiME/src/lime.ko
make[1]: se sale del directorio «/usr/src/linux-headers-3.8.0-35-generic»
strip --strip-unneeded lime.ko
mv lime.ko lime-3.8.0-35-generic.ko
make tidy
make[1]: se ingresa al directorio «/home/jpavlik/LiME/src»
rm -f *.o *.mod.c Module.symvers Module.markers modules.order \.*.o.cmd \.*.ko.cmd \.*.o.d
rm -rf \.tmp_versions
make[1]: se sale del directorio «/home/jpavlik/LiME/src»
jpavlik@corrientes:~/LiME/src$ 

el módulo debe haber sido compilado en el mismo directorio:

jpavlik@corrientes:~/LiME/src$ file lime-3.8.0-35-generic.ko 
lime-3.8.0-35-generic.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=0xef9209d7b1872ae63655f3df94d98986f7bdd105, not stripped
jpavlik@corrientes:~/LiME/src$ 

como todo módulo es necesario cargarlo para poder hacer uso de sus funcionalidades. Para esto acudimos el comando insmod (como root, claro) y le pasamos los argumentos necesarios para hacer un dump crudo (raw) a través de la red (la prueba la hacemos sobre una VM just in case...):

  • Desde la VM de la cual obtendremos el volcado de memoria ejecutamos
localhost src # insmod lime-3.3.8-gentoo.ko "path=tcp:4444 format=raw"

  • En la máquina donde recibiremos el volcado ejecutamos:
root@corrientes:~# nc 172.16.254.68 4444 > volcado.mem

Luego de unos segundos (dependiendo de la cantidad de ram de la VM y la velocidad de trasnferencia de la red) tendremos el archivo volcado.mem a nuestro disposición:

root@corrientes:~# ll volcado.mem -h
-rw-r--r-- 1 root root 256M jul 14 15:25 volcado.mem
root@corrientes:~# 

Podemos apreciar que el tamaño del archivo nos indica que la VM de origen tiene solo 256Mbytes asignados como memoria RAM. 

Y de esta manera conseguimos nuestro volcado de memoria, ahora habría que analizarlo según los objetivos de cada caso. 

Una primera aproximación de análisis muy simple, podríamos hacerla usando el comando strings y analizar las cadenas obtenidas.

miércoles, 31 de agosto de 2011

Usando tmpfs

Bien, entrada corta si las hay!!! Esto va a ser una PEQUEÑA demostración del uso de tmpfs. Qué es tmpfs??? Wiki knows (http://es.wikipedia.org/wiki/Tmpfs#Linux). Es una suerte de sistema de archivos en memoria volátil (RAM y swap si es necesario, ojo!!!).

Ventajas:
-Las operaciones de lectura y escritura son MUCHO mas rápidas que en otros medios de IO como los discos rígidos (IDEAL para montar directorios de CACHEs).
-Es sencillo de utilizar.
 Desventajas:
-Es volátil!!! no se mantiene luego de un reinicio del equipo por ejemplo.
-Su espacio está limitado por la cantidad de memoria RAM disponible y la swap del sistema.

Demostración simple de uso y rendimiento en escritura:

Creamos un directorio llamado prueba_tmpfs

root@moon:~# mkdir prueba_tmpfs

Antes de montar veamos cómo se el consumo de memoria con free -m.

root@moon:~# free -m
                     total       used       free     shared    buffers     cached
Mem:          1975       1167        807          0         25        538
-/+ buffers/cache:        603       1371
Swap:         5789          0       5789

Montamos un sistema de archivos tipo tmpfs (-t tmpfs) de 1GigaByte en el directorio que acabamos de crear.

root@moon:~# mount -t tmpfs -o size=1G tmpfs prueba_tmpfs/
Vemos los puntos de montaje existentes y nos encontramos con nuestro tmpfs recien montado.

root@moon:~# mount 
...
 tmpfs on /root/prueba_tmpfs type tmpfs (rw,size=1G)


Pegamos una mirada con free para ver qué pasó y vemos que si bien el directorio se montó, no se ocupó memoria del sistema aún.

root@moon:~# free -m
                     total       used       free     shared    buffers     cached
Mem:          1975       1167        807          0         25        538
-/+ buffers/cache:        603       1371
Swap:         5789          0       5789

Veamos qué beneficios nos trae tmpfs, escribamos algo!!! Para probar utilizamos un simple dd.

root@moon:~# dd if=/dev/zero of=prueba_tmpfs/prueba bs=1M count=768
768+0 registros de entrada
768+0 registros de salida
805306368 bytes (805 MB) copiados, 1,58104 s, 509 MB/s

Nos encontramos con una velocidad de escritura de 509 Mbytes por segundo!!! (509MBytes*8 = 4072Mbits por seg aprox 4Gbits por segundo!!! lo cual es consistente con el ancho de banda teórico de las memorias DDR2 de 667 Mhz que tiene mi laptop :D). Una velocidad MAS que interesante.

Podemos ver un cambio significativo en free -m. Pasamos de 807 a 37 Mbytes libres, es decir consumimos 807-37=770 (consistente con los 768 que escribimos con el dd).

root@moon:~# free -m
                     total       used       free     shared    buffers     cached
Mem:          1975       1937         37          0         25       1306
-/+ buffers/cache:        605       1369
Swap:         5789          0       5789

mmm ahora le toca al sata de la laptop hacer su mejor esfuerzo xD (competencia un tanto injusta jajaja). Escribimos de la misma manera que antes, pero a un archivo fuera del directorio donde montamos el tmpfs, en este caso el archivo se llama simplemente prueba.

root@moon:~# dd if=/dev/zero of=prueba bs=1M count=768
768+0 registros de entrada
768+0 registros de salida
805306368 bytes (805 MB) copiados, 12,3028 s, 65,5 MB/s

La velocidad fue de 65,5 Mbytes por segundo (65,5Mbytes * 8 = 524 Mbits por segundo, bastante por debajo del máximo teórico de los SATA II, por debajo inclusive del SATA I). Con esto queda claro que la diferencia es IMPORTANTE, la escritura sobre tmpfs fue casi 8 veces mas rápida (509/65,5=7,7).

Demostración simple de uso y rendimiento en lectura:

Todo muy lindo en la escritura, pero en la lectura qué será? :O.

Primero leemos del tmpfs y vemos una velocidad bastante mayor a la que obtuvimos en escritura. Pasando los 7Gbits por segundo!!!, esto seguramente se debe a algún manejo extraño de caches por parte del kernel, porque esta velocidad excede el límite teórico de las memorias de la laptop.

root@moon:~# dd if=prueba_tmpfs/prueba of=/dev/null bs=1M
768+0 registros de entrada
768+0 registros de salida
805306368 bytes (805 MB) copiados, 0,873211 s, 922 MB/s

Con respecto a la lectura en disco... Obtuve una velocidad muy similar a la de escritura, lo cual NO es muy común en este tipo de dispositivos.

root@moon:~# dd if=prueba of=/dev/null bs=1M
768+0 registros de entrada
768+0 registros de salida
805306368 bytes (805 MB) copiados, 13,5713 s, 59,3 MB/s

Por lo general los discos rígidos leen a mayor velocidad de la que escriben, por lo tanto podríamos suponer que la velocidad de escritura obtenida anteriormente es producto de algún manejo eficiente de cache o una suerte de inteligencia en la escritura de datos repetidos (solamente ceros, obtenidos de /dev/zero).

Qué pasa si...?:

Intentamos escribir mas bytes de los que tiene asignado nuestro directorio en tmpfs:

root@moon:~# dd if=/dev/zero of=prueba_tmpfs/prueba bs=1M count=1024
dd: escribiendo «prueba_tmpfs/prueba»: No hay espacio libre en el dispositivo
1022+0 registros de entrada
1021+0 registros de salida
1071640576 bytes (1,1 GB) copiados, 2,47776 s, 433 MB/s
root@moon:~#

Como era de esperarse no pudimos escribir mas de lo que definimos como tamaño del tmpfs :D.

Creamos un tmpfs mayor que nuestra RAM (mi laptop tiene 2Gbytes de RAM):

Es absolutamente posible hacerlo, PERO...

root@moon:~# mount -t tmpfs -o size=3G tmpfs prueba_tmpfs
root@moon:~# mount | grep prueba_tmpfs
tmpfs on /root/prueba_tmpfs type tmpfs (rw,size=3G)
a medida que comencemos a ocupar el espacio del tmpfs, nos comeremos (si, casi literalmente) la memoria ram del equipo, este comenzará a intercambiar páginas con poco uso a la memoria de intercambio (swap) y eventualmente el sistema podría quedar inutilizable. Moraleja? no es recomendable hacerlo (cosas que pasan xD).


Conclusión:

Definitivamente es una opción muy interesante principalmente para utilizar como directorio para caches.

En mi caso en particular utilicé tmpfs para el directorio donde munin crea/actualiza los archivos rrd, en un servidor que monitorea mas de 100 servidores, y el cambio fue notable. Antes de esto los gráficos se cortaban porque el proceso de graficar no terminaba antes de que llegaran las nuevas mediciones.