GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo leo desde /proc/$pid/mem bajo Linux?

/proc/$pid/maps

/proc/$pid/mem muestra el contenido de la memoria de $pid asignado de la misma manera que en el proceso, es decir, el byte en el desplazamiento x en el pseudo-archivo es el mismo que el byte en la dirección x en el proceso. Si una dirección no está asignada en el proceso, la lectura del desplazamiento correspondiente en el archivo devuelve EIO (Error de entrada/salida). Por ejemplo, dado que la primera página de un proceso nunca se asigna (por lo que eliminar la referencia a un NULL el puntero falla limpiamente en lugar de acceder involuntariamente a la memoria real), leyendo el primer byte de /proc/$pid/mem siempre produce un error de E/S.

La forma de averiguar qué partes de la memoria del proceso están asignadas es leer /proc/$pid/maps . Este archivo contiene una línea por región asignada y se ve así:

08048000-08054000 r-xp 00000000 08:01 828061     /bin/cat
08c9b000-08cbc000 rw-p 00000000 00:00 0          [heap]

Los primeros dos números son los límites de la región (direcciones del primer byte y del último byte, en hexa). La siguiente columna contiene los permisos, luego hay información sobre el archivo (compensación, dispositivo, inodo y nombre) si se trata de una asignación de archivos. Ver el proc(5) man page o Comprender Linux /proc/id/maps para obtener más información.

Aquí hay una secuencia de comandos de prueba de concepto que vuelca el contenido de su propia memoria.

#! /usr/bin/env python
import re
maps_file = open("/proc/self/maps", 'r')
mem_file = open("/proc/self/mem", 'rb', 0)
output_file = open("self.dump", 'wb')
for line in maps_file.readlines():  # for each mapped region
    m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
    if m.group(3) == 'r':  # if this is a readable region
        start = int(m.group(1), 16)
        end = int(m.group(2), 16)
        mem_file.seek(start)  # seek to region start
        chunk = mem_file.read(end - start)  # read region contents
        output_file.write(chunk)  # dump contents to standard output
maps_file.close()
mem_file.close()
output_file.close()

/proc/$pid/mem

[Lo siguiente es de interés histórico. No se aplica a los núcleos actuales.]

Desde la versión 3.3 del kernel, puede acceder a /proc/$pid/mem normalmente, siempre que acceda solo acceda a las compensaciones asignadas y tenga permiso para rastrearlo (los mismos permisos que ptrace para acceso de solo lectura). Pero en kernels más antiguos, hubo algunas complicaciones adicionales.

Si intenta leer desde el mem pseudo-archivo de otro proceso, no funciona:obtienes un ESRCH (No hay tal proceso) error.

Los permisos en /proc/$pid/mem (r-------- ) son más liberales de lo que deberían ser. Por ejemplo, no debería poder leer la memoria de un proceso setuid. Además, tratar de leer la memoria de un proceso mientras el proceso la está modificando podría darle al lector una vista inconsistente de la memoria y, lo que es peor, hubo condiciones de carrera que podrían rastrear versiones anteriores del kernel de Linux (según este hilo lkml, aunque yo desconozco los detalles). Por lo tanto, se necesitan comprobaciones adicionales:

  • El proceso que quiere leer desde /proc/$pid/mem debe adjuntarse al proceso usando ptrace con el PTRACE_ATTACH bandera. Esto es lo que hacen los depuradores cuando comienzan a depurar un proceso; también es lo que strace hace a las llamadas al sistema de un proceso. Una vez que el lector haya terminado de leer desde /proc/$pid/mem , debe desconectarse llamando a ptrace con el PTRACE_DETACH bandera.
  • El proceso observado no debe estar ejecutándose. Normalmente llamando al ptrace(PTRACE_ATTACH, …) detendrá el proceso de destino (envía un STOP señal), pero hay una condición de carrera (la entrega de la señal es asíncrona), por lo que el rastreador debe llamar a wait (como se documenta en ptrace(2) ).

Un proceso que se ejecuta como root puede leer la memoria de cualquier proceso, sin necesidad de llamar a ptrace , pero el proceso observado debe detenerse, o la lectura aún devolverá ESRCH .

En el código fuente del kernel de Linux, el código que proporciona entradas por proceso en /proc está en fs/proc/base.c , y la función para leer desde /proc/$pid/mem es mem_read . La verificación adicional la realiza check_mem_permission .

Aquí hay un ejemplo de código C para adjuntar a un proceso y leer un fragmento de mem archivo (comprobación de errores omitida):

sprintf(mem_file_name, "/proc/%d/mem", pid);
mem_fd = open(mem_file_name, O_RDONLY);
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
waitpid(pid, NULL, 0);
lseek(mem_fd, offset, SEEK_SET);
read(mem_fd, buf, _SC_PAGE_SIZE);
ptrace(PTRACE_DETACH, pid, NULL, NULL);

Ya publiqué un script de prueba de concepto para descargar /proc/$pid/mem en otro hilo.


Este comando (de gdb) descarga la memoria de manera confiable:

gcore pid

Los volcados pueden ser grandes, use -o outfile si su directorio actual no tiene suficiente espacio.


Cuando ejecutas cat /proc/$$/mem la variable $$ es evaluado por bash que inserta su propio pid. Luego ejecuta cat que tiene un pid diferente. Terminas con cat tratando de leer la memoria de bash , su proceso padre. Dado que los procesos sin privilegios solo pueden leer su propio espacio de memoria, el núcleo lo niega.

He aquí un ejemplo:

$ echo $$
17823

Tenga en cuenta que $$ evalúa a 17823. Veamos qué proceso es.

$ ps -ef | awk '{if ($2 == "17823") print}'
bahamat  17823 17822  0 13:51 pts/0    00:00:00 -bash

Es mi caparazón actual.

$ cat /proc/$$/mem
cat: /proc/17823/mem: No such process

Aquí de nuevo $$ evalúa a 17823, que es mi shell. cat no puedo leer el espacio de memoria de mi shell.


Linux
  1. Linux:¿cómo leer desde /proc/$pid/mem en Linux?

  2. Linux:¿cómo obtener la dirección IPv4 para una interfaz desde /proc?

  3. Linux:¿cómo probar si un dispositivo de bloque es de solo lectura desde/sys o/proc?

  4. ¿Cómo leer un mensaje a la vez desde /var/mail?

  5. ¿Cómo obtengo la ruta de un proceso en Unix/Linux?

Cómo matar un proceso en Linux

Linux:¿cómo averiguar el espacio de nombres de un proceso en particular?

Una guía para el sistema de archivos '/proc' en Linux

Archivos /proc/cpuinfo y /proc/meminfo en Linux

/proc/[pid]/pagemaps y /proc/[pid]/maps | linux

¿Cómo obtener la cantidad de CPU/núcleos en Linux desde la línea de comandos?