Ferramentas para mostrar quais arquivos são acessados por um programa?

12

Eu não estou indo para ferramentas complicadas como o modo de reclamação do AppArmor, eu preciso de ferramentas fáceis para me dizer quais arquivos são acessados por um programa específico.

    
por Boll19 27.01.2018 / 12:01

3 respostas

11

Por Chris Down, você pode usar strace -p para examinar um processo já em execução , para ver quais arquivos ele abre a partir de agora até o momento em que você encerra o strace ou o processo em si.

Se você quiser ver os arquivos abertos pela duração total de um processo, desde o início, use strace com o nome do executável. Adicionar -f garante que todos os subprocessos bifurcados também sejam reportados. Exemplo

# 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 +++
#

Usando lsof para ver quais arquivos um processo atualmente abriu

# 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
[...]
#

Se você tiver o SystemTap, poderá monitorar todo o host em busca de arquivos abertos.

[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"
[...]
#
    
por 27.01.2018 / 12:41
5

Minha ferramenta favorita para monitorar quais arquivos um aplicativo abre é a poderosa estrutura de monitoramento sysdig .

Para monitorar todos os arquivos abertos abertos por um programa chamado exe_file :

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

Monitorando todos os arquivos abertos no servidor:

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

Criando um arquivo de rastreio que conterá apenas eventos de gravação em diretórios base (que podemos inspecionar mais tarde com 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

Vendo tudo no nível syscall, um processo chamado exe_file faz:

sudo sysdig proc.name=exe_file

O Sysdig tem muitos cinzéis, veja as coisas mais interessantes que ele pode fazer:

Você também tem dtrace que não é muito usado no Linux, mas ainda usa muito com sistemas operacionais * BSD:

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

Além de sysdig , strace e dtrace , você também tem ltrace , que registra / intercepta sinais / bibliotecas dinâmicas / chamadas de sistema que são chamadas / recebidas por um processo:

ltrace is a program that simply runs the specified command until it exits. It intercepts and records the dynamic library calls which are called by the executed process and the signals which are received by that process. It can also intercept and print the system calls executed by the program.

$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) +++  

Se o programa for pequeno, você também pode considerar desmontá-lo com objdump -d exe_file ou desmontá-lo / descompactá-lo com Hopper , para ver todos os arquivos com os quais ele lida.

Para mais detalhes, consulte: Entendendo o que é um binário do Linux fazendo

Como primeira abordagem, eu também faria:

strings exe_file

É uma abordagem de baixo custo e, com sorte, alguns dos nomes dos arquivos podem estar presentes no modo ASCII no arquivo binário com sorte.

Veja também a resposta relacionada Por que são verdadeiras e falsas? tão grande?

Se binários / arquivos que vêm com a distribuição, você também pode buscar as fontes dos repositórios de fontes da distribuição, ou os repositórios oficiais do utilitário real.

Como último recurso, você sempre pode usar ferramentas como gdb ou rr para depurar o binário em tempo real.

    
por 27.01.2018 / 17:13
4

Você pode usar opensnoop do BCC, que usa o eBPF sob o 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
[...]

Isso é bastante eficiente, já que usa kprobes em vez de ter que reiniciar o syscalls, como strace faz.

Você também pode fazer isso com strace (potencialmente com -f para seguir o processo de rastreio 'children), mas sua maneira de operar, envolvendo reiniciar o syscalls como parte de ptrace irá desacelerar seu aplicativo um pouco:

# 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
[...]

Você também pode iniciar seu aplicativo dessa forma, se desejar, usando strace [executable] ou strace -f [executable] .

    
por 27.01.2018 / 12:08