Tools zum Anzeigen, auf welche Dateien ein Programm zugreift?

12

Ich möchte keine komplizierten Tools wie den AppArmor-Beschwerdemodus verwenden. Ich benötige einfache Tools, um festzustellen, auf welche Dateien ein bestimmtes Programm zugreift.

Boll19
quelle
7
Unter welchem ​​Betriebssystem?
Jeff Schaller
Könnte auch nützlich sein, um zu erklären, dass Sie erwarten, dass das Programm auf welche Weise auf Dateien fstat()lstat()
zugreift
Sowohl Suse als auch Ubuntu
Boll19
Egal wie ich wissen muss, programmieren fstat () oder lstat ()?
Boll19
Mit anderen Worten: Sergiy Kolodyazhnyys Kommentar: Wenn ein Programm die Länge, das Änderungsdatum, die Berechtigungen oder andere Eigenschaften einer Datei überprüft, aber nicht auf die Daten der Datei zugreift, würden Sie sie als "Zugriff auf die Datei" zählen oder nicht?
TelcoM

Antworten:

12

Per Chris Down können Sie strace -peinen bereits laufenden Prozess untersuchen, um festzustellen, welche Dateien von jetzt an geöffnet werden, bis Sie strace beenden oder der Prozess selbst abgeschlossen ist.

Wenn Sie möchten, dass Dateien für die gesamte Dauer eines Prozesses geöffnet werden, verwenden Sie sie von Anfang an stracemit dem Namen der ausführbaren Datei. Durch -fdas Hinzufügen wird sichergestellt, dass auch gegabelte Unterprozesse gemeldet werden. Beispiel

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

Verwenden Sie, um lsofzu sehen, welche Dateien ein Prozess derzeit geöffnet hat

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

Wenn Sie über SystemTap verfügen, können Sie den gesamten Host auf geöffnete Dateien überwachen.

[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
quelle
2
openist nicht der einzige relevante Systemaufruf. Beispielsweise ist es möglich, Dateideskriptoren zwischen Prozessen über einen Unix-Socket zu übergeben, und es gibt den openatSystemaufruf, mit dem auch eine Datei geöffnet werden kann.
Kasperd
---- SIGUSR1 {si_signo = SIGUSR1, si_code = SI_TKILL, si_pid = 6026, si_uid = 1002} ---- was ist das
Boll19
Kaspers, muss ich nur beim Befehl strace output nach 'openat' suchen?
Boll19
Der Versuch, eine Datei zu öffnen (aber die Datei ist möglicherweise nicht vorhanden), wird auch in den 'strace'-Ausgaben angezeigt?
Boll19
Boll19, Dateien, die nicht geöffnet werden können, weil sie nicht vorhanden sind, werden in straceden Zeilen ENOENT im Beispiel angezeigt.
Steve
5

Sie können opensnoopvon BCC verwenden, das eBPF unter der Haube verwendet:

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

Dies ist ziemlich performant, da kprobes verwendet wird, anstatt wie üblich syscalls neu starten zu stracemüssen.

Sie können dies auch mit strace(möglicherweise mit -f, um den untergeordneten Elementen des verfolgten Prozesses zu folgen) tun , aber seine Funktionsweise, bei der Syscalls als Teil von ptrace neu gestartet werden, verlangsamt Ihre Anwendung etwas:

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

Sie können Ihre Anwendung bei Bedarf auch auf diese Weise starten, indem Sie strace [executable]oder verwenden strace -f [executable].

Chris Down
quelle
5

Mein Lieblingswerkzeug zur Überwachung der von einer Anwendung geöffneten Dateien ist das leistungsstarke Überwachungsframework sysdig.

Zum Überwachen aller geöffneten Dateien, die von einem Programm mit dem Namen geöffnet wurden exe_file:

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

Überwachen aller auf dem Server geöffneten Dateien:

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

Erstellen einer Trace-Datei, die nur Schreibereignisse in Home-Verzeichnissen enthält (die wir später überprüfen können 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

Wenn Sie alles auf Syscall-Ebene sehen, führt ein Prozess mit dem Namen exe_fileFolgendes aus:

sudo sysdig proc.name=exe_file

Sysdig hat viele Meißel, sehen Sie nach interessanteren Dingen, die es tun kann:

Sie haben auch dtracedas, was unter Linux nicht viel verwendet wird, aber mit * BSD-Betriebssystemen immer noch viel verwendet wird:

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

Außerdem sysdig, straceund dtraceSie haben auch bekommen ltrace, die Aufzeichnungen / abfängt Signale / dynamische Bibliotheken / Systemaufrufe , die durch einen Prozess namens / empfangen werden:

ltraceist ein Programm, das den angegebenen Befehl einfach ausführt, bis er beendet wird. Es fängt die dynamischen Bibliotheksaufrufe ab und zeichnet sie auf, die vom ausgeführten Prozess aufgerufen werden, und die Signale, die von diesem Prozess empfangen werden. Es kann auch die vom Programm ausgeführten Systemaufrufe abfangen und drucken.

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

Wenn das Programm klein ist, können Sie es auch zerlegen objdump -d exe_fileoder zerlegen / dekompilieren Hopper, um alle Dateien anzuzeigen, mit denen es sich befasst.

Weitere Informationen finden Sie unter: Verstehen, was eine Linux-Binärdatei tut

Als ersten Ansatz würde ich auch tun:

strings exe_file

Dies ist ein kostengünstiger Ansatz, und mit etwas Glück können einige der Dateinamen mit etwas Glück im ASCII-Modus in der Binärdatei vorhanden sein.

Siehe auch verwandte Antwort Warum sind wahr und falsch so groß?

Bei Binärdateien / Dateien, die mit der Distribution geliefert werden, können Sie die Quellen auch aus den Quell-Repositorys der Distribution oder den offiziellen Repositorys des eigentlichen Dienstprogramms abrufen.

Als letzte Ressource können Sie immer Tools wie gdb oder rr verwenden , um die Binärdatei in Echtzeit zu debuggen.

Rui F Ribeiro
quelle
aaa43bb66: ~ # sudo proc.name = exe_file sysdig -p "% 12user.name% 6proc.pid% 12proc.name% 3fd.num% fd.typechar% fd.name" evt.type = open Treiberfehler kann nicht geladen werden Gerät öffnen / dev / sysdig0. Stellen Sie sicher, dass Sie über Root-Anmeldeinformationen verfügen und dass das sysdig-probe-Modul geladen ist.
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 um den Treiberfehler zu laden, öffnen Sie das Gerät / dev / sysdig0. Stellen Sie sicher, dass Sie Root-Anmeldeinformationen haben und dass das sysdig-probe-Modul geladen ist. <Code> * /
Boll19
@ Boll19 Habe dort einen Fehler, korrigiert. Diese Nachricht scheint einen sysdigFehler zu haben (verwenden Sie ARM?). Bitte stellen Sie eine neue Frage.
Rui F Ribeiro