¿Herramientas para mostrar a qué archivos accede un programa?

12

No voy por herramientas complicadas como el modo de queja AppArmor, necesito herramientas fáciles para decirme a qué archivos accede un programa específico.

Boll19
fuente
77
¿Bajo qué sistema operativo?
Jeff Schaller
También podría ser útil para explicarle que espera que el programa acceda a los archivos de qué manera: leer, escribir, agregar, solo obtener fstat()o lstat()información, etc.
Sergiy Kolodyazhnyy
Tanto Suse como Ubuntu
Boll19
No importa de qué manera tengo que saber, ¿fstat () o lstat () están programando?
Boll19
El comentario de Sergiy Kolodyazhnyy en otras palabras: si un programa verifica la longitud, la fecha de modificación, los permisos u otras propiedades de un archivo pero no accede a los datos del archivo, ¿lo consideraría como "acceso al archivo" o no?
telcoM

Respuestas:

12

Según Chris Down, puede usar strace -ppara examinar un proceso que ya se está ejecutando , para ver qué archivos se abre desde ahora hasta el momento en que termina la secuencia o el proceso termina.

Si desea ver los archivos abiertos durante todo el proceso, desde el principio, utilícelos stracecon el nombre del ejecutable. Agregar -fasegura que cualquier subproceso bifurcado también sea reportado. Ejemplo

# strace -e open -f /bin/id
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/proc/thread-self/attr/current", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/proc/self/task/1581/attr/current", O_RDONLY|O_CLOEXEC) = 3
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
open("/usr/share/locale/en_US.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en_US/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
open("/etc/group", O_RDONLY|O_CLOEXEC)  = 3
open("/etc/group", O_RDONLY|O_CLOEXEC)  = 3
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
+++ exited with 0 +++
#

Utilizando lsofpara ver qué archivos tiene abierto actualmente un proceso

# lsof -p $(pidof NetworkManager)
COMMAND   PID USER   FD      TYPE             DEVICE  SIZE/OFF     NODE NAME
NetworkMa 722 root  cwd       DIR              253,0       224       64 /
NetworkMa 722 root  rtd       DIR              253,0       224       64 /
NetworkMa 722 root  txt       REG              253,0   2618520   288243 /usr/sbin/NetworkManager
NetworkMa 722 root  mem       REG              253,0     27776    34560 /usr/lib64/libnss_dns-2.17.so
[...]
#

Si tiene SystemTap, puede monitorear todo el host en busca de archivos abiertos.

[root@localhost tmp]# cat mon
#!/usr/bin/env stap
probe syscall.open { printf ("pid %d program %s opened %s\n", pid(), execname(), filename) }
# ./mon
pid 14813 program touch opened "/etc/ld.so.cache"
pid 14813 program touch opened "/lib64/libc.so.6"
pid 14813 program touch opened 0x7f7a8c6ec8d0
pid 14813 program touch opened "foo2"
[...]
#
Steve
fuente
2
openno es la única llamada al sistema relevante. Por ejemplo, es posible pasar descriptores de archivo entre procesos a través de un socket Unix, y existe la openatllamada al sistema que también puede abrir un archivo.
kasperd
---- SIGUSR1 {si_signo = SIGUSR1, si_code = SI_TKILL, si_pid = 6026, si_uid = 1002} ---- qué es eso
Boll19
kaspers, ¿solo necesito buscar 'openat' en el comando de salida strace?
Boll19
¿Intentar abrir un archivo (pero el archivo puede no existir) también se muestra en las salidas 'strace'?
Boll19
Boll19, los archivos que no se abren debido a que no existen se informan felizmente dentro strace, vea las líneas ENOENT en el ejemplo.
Steve
5

Puede usar opensnoopde BCC, que usa eBPF bajo el capó:

# ./opensnoop -p 1576
PID    COMM      FD ERR PATH
1576   snmpd     11   0 /proc/sys/net/ipv6/conf/lo/forwarding
1576   snmpd     11   0 /proc/sys/net/ipv6/neigh/lo/base_reachable_time_ms
1576   snmpd      9   0 /proc/diskstats
1576   snmpd      9   0 /proc/stat
1576   snmpd      9   0 /proc/vmstat
[...]

Esto es bastante eficiente ya que usa kprobes en lugar de tener que reiniciar las llamadas al sistema, como lo stracehace.

También puede hacer esto con strace(posiblemente -fpara seguir los elementos secundarios del proceso rastreado), pero su forma de operar, que implica reiniciar syscalls como parte de ptrace , ralentizará un poco su aplicación:

# strace -e open -p 15735
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/gconv/gconv-modules", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/python2.7/site-packages", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 4
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/etc/localtime", O_RDONLY|O_CLOEXEC) = 8
[...]

También puede iniciar su aplicación de esta manera si lo desea, usando strace [executable]o strace -f [executable].

Chris Down
fuente
5

Mi herramienta favorita para monitorear qué archivos abre una aplicación es el poderoso marco de monitoreo sysdig.

Para monitorear todos los archivos abiertos abiertos por un programa llamado exe_file:

sudo sysdig -p "proc.name=exe_file %12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open

Supervisión de todos los archivos abiertos en el servidor:

sudo sysdig -p "%12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open

Crear un archivo de rastreo que solo contendrá eventos de escritura en directorios de inicio (que podemos inspeccionar más adelante con sysdig -r writetrace.scap.gz):

sudo sysdig -p "%user.name %proc.name %fd.name" "evt.type=write and fd.name contains /home/" -z -w writetrace.scap.gz

Al ver todo a nivel de syscall, un proceso llamado exe_filehace:

sudo sysdig proc.name=exe_file

Sysdig tiene muchos cinceles, vea más cosas interesantes que puede hacer:

También tiene dtraceque no se usa mucho en Linux, pero todavía se usa mucho con los sistemas operativos * BSD:

# Files opened by process,
dtrace -n 'syscall::open*:entry { printf("%s %s",execname,copyinstr(arg0)); }'

Además sysdig, stracey dtracetambién tiene ltrace, qué graba / intercepta señales / bibliotecas dinámicas / llamadas al sistema que son llamadas / recibidas por un proceso:

ltracees un programa que simplemente ejecuta el comando especificado hasta que sale. Intercepta y registra las llamadas a la biblioteca dinámica que son llamadas por el proceso ejecutado y las señales que recibe ese proceso. También puede interceptar e imprimir las llamadas al sistema ejecutadas por el programa.

$ltrace exe_file
_libc_start_main(0x400624, 1, 0x7ffcb7b6d7c8, 0x400710 <unfinished ...>  
time(0)                                                                              = 1508018406  
srand(0x59e288e6, 0x7ffcb7b6d7c8, 0x7ffcb7b6d7d8, 0)                                 = 0  
sprintf("mkdir -p -- '/opt/sms/AU/mo'", "mkdir -p -- '%s'", "/opt/sms/AU/mo")        = 28  
system("mkdir -p -- '/opt/sms/AU/mo'" <no return ...>  
--- SIGCHLD (Child exited) ---  
<... system resumed> )                                                               = 0  
rand(2, 0x7ffcb7b6d480, 0, 0x7f9d6d4622b0)                                           = 0x2d8ddbe1  
sprintf("/opt/sms/AU/mo/tmp.XXXXXX", "%s/tmp.XXXXXX", "/opt/sms/AU/mo")      = 29  
mkstemp(0x7ffcb7b6d5c0, 0x40080b, 0x40081a, 0x7ffffff1)                              = 3  
sprintf("/opt/sms/AU/mo/tmp.XXXXXX", "%s/tmp.XXXXXX", "/opt/sms/AU/mo")      = 29  
mkstemp(0x7ffcb7b6d5c0, 0x40080b, 0x40081a, 0x7ffffff1)                              = 4  
+++ exited (status 0) +++  

Si el programa es pequeño, también puede considerar desarmarlo objdump -d exe_fileo desarmarlo / descompilarlo Hopper, para ver todos los archivos con los que trata.

Para obtener más detalles, consulte: Comprender qué está haciendo un binario de Linux

Como primer enfoque, también haría:

strings exe_file

Es un enfoque de bajo costo, y con suerte, algunos de los nombres de los archivos podrían estar presentes en modo ASCII en el archivo binario con suerte.

Ver también la respuesta relacionada ¿Por qué son tan verdaderos y falsos tan grandes?

Si los archivos binarios / archivos que vienen con la distribución también puede buscar las fuentes de los repositorios de fuentes de la distribución, o los repositorios oficiales de la utilidad real.

Como último recurso, siempre puede usar herramientas como gdb o rr para depurar el binario en tiempo real.

Rui F Ribeiro
fuente
aaa43bb66: ~ # sudo proc.name = exe_file sysdig -p "% 12user.name% 6proc.pid% 12proc.name% 3fd.num% fd.typechar% fd.name" evt.type = abierto No se puede cargar el error del controlador dispositivo de apertura / dev / sysdig0. Asegúrese de tener credenciales de root y que el módulo sysdig-probe esté cargado.
Boll19
/ * <pre> aaa43bb66: ~ # sudo proc.name = exe_file sysdig -p "% 12user.name% 6proc.pid% 12proc.name% 3fd.num% fd.typechar% fd.name" evt.type = abierto Incapaz cargar el error del controlador al abrir el dispositivo / dev / sysdig0. Asegúrese de tener credenciales raíz y de que el módulo sysdig-probe esté cargado. <code> * /
Boll19
@ Boll19 Tengo un error allí, lo corrigió. Ese mensaje parece un sysdigerror (¿está utilizando ARM?), Publique una nueva pregunta para él.
Rui F Ribeiro