Инструменты для отображения, какие файлы доступны для программы?

12

Я не собираюсь прибегать к сложным инструментам, таким как режим жалоб AppArmor, мне нужны простые инструменты, чтобы сказать мне, к каким файлам обращается определенная программа.

Boll19
источник
7
Под какой операционной системой?
Джефф Шаллер
Также может быть полезно объяснить, как вы ожидаете, что программа получит доступ к файлам, каким образом - чтение, запись, добавление, получение fstat()или получение lstat()информации и т. Д.
Сергей Колодяжный,
И Suse, и Ubuntu
Boll19
Не важно, каким образом я должен знать, это программирование fstat () или lstat ()?
Boll19
Другими словами, комментарий Сергея Колодяжного: если программа проверяет длину файла, дату изменения, разрешения или другие свойства, но не обращается к данным файла, вы бы посчитали это «доступом к файлу» или нет?
Телеком

Ответы:

12

Согласно Крису Дауну, вы можете использовать strace -pдля изучения уже запущенного процесса, чтобы увидеть, какие файлы он открывает с этого момента до момента, когда вы завершите работу strace или завершится сам процесс.

Если вы хотите, чтобы файлы открывались на протяжении всего процесса, с самого начала используйте его straceс именем исполняемого файла. Добавление -fгарантирует, что о любых разветвленных подпроцессах также будет сообщено. пример

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

Использование lsofдля просмотра файлов , открытых в данный момент у процесса

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

Если у вас есть SystemTap, вы можете контролировать весь хост на наличие открываемых файлов.

[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"
[...]
#
Стив
источник
2
openне единственный соответствующий системный вызов. Например, можно передавать файловые дескрипторы между процессами через сокет Unix, и существует openatсистемный вызов, который также может открыть файл.
Касперд
---- SIGUSR1 {si_signo = SIGUSR1, si_code = SI_TKILL, si_pid = 6026, si_uid = 1002} ---- что это
Boll19
kaspers, мне нужно только искать 'openat' в команде вывода strace?
Болл 19
Попытка открыть файл (но файл может не существовать) также отображается в выводах 'strace'?
Boll19
Boll19, файлы, которые не открываются из-за того, что они не существуют, с радостью сообщаются внутри strace, см. Строки ENOENT в примере.
Стив
5

Вы можете использовать opensnoopиз BCC, который использует eBPF под капотом:

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

Это довольно эффективно, так как он использует kprobes вместо перезапуска системных вызовов, как это straceпроисходит.

Вы также можете сделать это с strace(возможно, с помощью -fдля отслеживания дочерних элементов отслеживаемого процесса), но его способ работы, включающий перезапуск системных вызовов как часть ptrace , несколько замедлит ваше приложение:

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

При желании вы также можете запустить свое приложение, используя strace [executable]или strace -f [executable].

Крис Даун
источник
5

Мой любимый инструмент для отслеживания файлов, которые открывает приложение, - это мощная инфраструктура мониторинга sysdig.

Для мониторинга всех открытых файлов, открытых программой с именем exe_file:

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

Отслеживание всех файлов, открытых на сервере:

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

Создание файла трассировки, который будет содержать только записи событий в домашних каталогах (которые мы можем проверить позже 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

Видя все на уровне системного вызова, процесс по имени exe_fileделает:

sudo sysdig proc.name=exe_file

У Sysdig есть много долот, см. Более интересные вещи, которые он может сделать:

У вас также есть dtraceто, что мало используется в Linux, но все еще широко используется с операционными системами * BSD:

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

Кроме того sysdig, straceи у dtraceвас также есть ltrace, какие записи / перехватывает сигналы / динамические библиотеки / системные вызовы, которые вызываются / принимаются процессом:

ltraceэто программа, которая просто запускает указанную команду до ее выхода. Он перехватывает и записывает динамические библиотечные вызовы, которые вызываются исполняемым процессом, и сигналы, полученные этим процессом. Он также может перехватывать и распечатывать системные вызовы, выполняемые программой.

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

Если программа небольшая, вы можете также рассмотреть возможность ее дизассемблирования objdump -d exe_fileили дизассемблирования / декомпиляции Hopper, чтобы увидеть все файлы , с которыми она имеет дело.

Для более подробной информации смотрите: Понимание того, что делает бинарный файл Linux

В качестве первого подхода я бы также сделал:

strings exe_file

Это недорогой подход, и в случае удачи некоторые имена файлов могут просто присутствовать в режиме ASCII в двоичном файле, если повезет.

См. Также связанный ответ. Почему истина и ложь так велики?

Если двоичные файлы / файлы поставляются вместе с дистрибутивом, вы также можете получить исходные коды из репозиториев исходных текстов дистрибутива или из официальных репозиториев реальной утилиты.

В качестве последнего ресурса вы всегда можете использовать такие инструменты, как gdb или rr для отладки двоичного файла в режиме реального времени.

Руи Ф Рибейро
источник
aaa43bb66: ~ # sudo proc.name = exe_file sysdig -p "% 12user.name% 6proc.pid% 12proc.name% 3fd.num% fd.typechar% fd.name" evt.type = open Невозможно загрузить ошибку драйвера открывающее устройство / dev / sysdig0. Убедитесь, что у вас есть учетные данные root и загружен модуль sysdig-probe.
Boll19
/ * <pre> aaa43bb66: ~ # sudo proc.name = exe_file sysdig -p "% 12user.name% 6proc.pid% 12proc.name% 3fd.num% fd.typechar% fd.name" evt.type = open Unable загрузить драйвер при открытии устройства ошибки / dev / sysdig0. Убедитесь, что у вас есть учетные данные пользователя root и что модуль sysdig-probe загружен. <Code> * /
Boll19
@ Boll19 Там есть ошибка, исправлена. Это сообщение об sysdigошибке (вы используете ARM?), Пожалуйста, напишите новый вопрос.
Руи Ф. Рибейро