Não estou procurando ferramentas complicadas, como o modo de reclamação do AppArmor, preciso de ferramentas fáceis para me dizer quais arquivos são acessados por um programa específico.
fstat()
ou obter lstat()
informações, etc.
Não estou procurando ferramentas complicadas, como o modo de reclamação do AppArmor, preciso de ferramentas fáceis para me dizer quais arquivos são acessados por um programa específico.
fstat()
ou obter lstat()
informações, etc.
Respostas:
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 rastreio ou o processo em si termina.
Se você deseja ver os arquivos abertos por toda a duração de um processo, use desde o início strace
com o nome do executável. A adição -f
garante que qualquer subprocesso bifurcado também seja relatado. 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 está aberto no momento
# 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ê possui o SystemTap, pode monitorar o host inteiro em busca de arquivos que estão sendo 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"
[...]
#
open
não é a única chamada de sistema relevante. Por exemplo, é possível passar descritores de arquivo entre processos em um soquete unix, e há a openat
chamada do sistema que também pode abrir um arquivo.
strace
, consulte as linhas ENOENT no exemplo.
Você pode usar o opensnoop
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 tem um bom desempenho, pois usa o 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 os filhos do processo rastreado), mas sua maneira de operar, envolvendo a reinicialização de syscalls como parte do ptrace , torna o aplicativo um pouco mais lento:
# 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 maneira, se desejar, usando strace [executable]
ou strace -f [executable]
.
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 rastreamento que conterá apenas eventos de gravação em diretórios pessoais (com os quais podemos inspecionar posteriormente 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 do syscall, um processo chamado exe_file
:
sudo sysdig proc.name=exe_file
O Sysdig tem muitos cinzéis, veja para coisas mais interessantes que ele pode fazer:
Você também percebeu dtrace
que não é muito usado no Linux, mas ainda é muito usado nos sistemas operacionais * BSD:
# Files opened by process,
dtrace -n 'syscall::open*:entry { printf("%s %s",execname,copyinstr(arg0)); }'
Além disso sysdig
, strace
e dtrace
você também tem ltrace
quais registros / intercepta sinais / bibliotecas dinâmicas / chamadas de sistema que são chamadas / recebidas por um processo:
ltrace
é um programa que simplesmente executa o comando especificado até que ele saia. Ele intercepta e registra as chamadas da biblioteca dinâmica chamadas pelo processo executado e os sinais recebidos por esse processo. Também pode interceptar e imprimir as chamadas do sistema executadas pelo 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) +++
Se o programa for pequeno, considere também desmontá-lo objdump -d exe_file
ou desmontá-lo / descompilá-lo Hopper
, para ver todos os arquivos com os quais lida.
Para obter mais detalhes, consulte: Entendendo o que um binário Linux está fazendo
Como primeira abordagem, eu também faria:
strings exe_file
É uma abordagem de baixo custo e, com sorte, alguns nomes de arquivos podem estar presentes no modo ASCII no arquivo binário com sorte.
Veja também a resposta relacionada Por que o verdadeiro e o falso são tão grandes?
Se os binários / arquivos que acompanham a distribuição, você também pode buscar as fontes nos repositórios de fontes da distribuição ou nos 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.
sysdig
bug (você está usando o ARM?), Poste uma nova pergunta para ele.