I'm not going for complicated tools like AppArmor complain mode, I need easy tools to tell me which files are accessed by a specific program.
3 Answers
Per Chris Down, you can use strace -p to examine an already running process, to see what files it opens from now until the time you terminate strace or the process itself finishes.
If you want to see files opened for the entire duration of a process, right from the start, use strace with the executable name. Adding -f ensures that any forked sub-processes also get reported. Example
# 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 +++
#
Using lsof to see what files a process currently has open
# 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
[...]
#
If you have SystemTap, you can monitor the entire host for files being opened.
[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
openisn't the only relevant system call. For example it is possible to pass file descriptors between processes over a unix socket, and there is theopenatsystem call which can also open a file.kasperd– kasperd2018-01-27 17:47:34 +00:00Commented Jan 27, 2018 at 17:47 -
---- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_TKILL, si_pid=6026, si_uid=1002} ---- whats thatBoll19– Boll192018-01-28 06:55:13 +00:00Commented Jan 28, 2018 at 6:55
-
kaspers, do I only need to search for 'openat' at the strace output command?Boll19– Boll192018-01-29 05:33:47 +00:00Commented Jan 29, 2018 at 5:33
-
Trying open a file (but the file may not be exist) is displayed in the 'strace' outputs too?Boll19– Boll192018-01-29 05:41:14 +00:00Commented Jan 29, 2018 at 5:41
-
Boll19, files that fail to open due to them not existing are happily reported within
strace, see the ENOENT lines in the example.steve– steve2018-02-03 13:44:03 +00:00Commented Feb 3, 2018 at 13:44
You can use opensnoop from BCC, which uses eBPF under the hood:
# ./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
[...]
This is quite performant since it uses kprobes instead of having to restart syscalls, like strace does.
You can also do this with strace (potentially with -f to follow the traced process' children), but its way of operating, involving restarting syscalls as part of ptrace will slow down your application somewhat:
# 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
[...]
You can also start your application this way if desired, using strace [executable], or strace -f [executable].
My favorite tool for monitoring which files an application opens is the powerful monitoring framework sysdig.
For monitoring all the open files opened by a program named exe_file:
sudo sysdig -p "proc.name=exe_file %12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open
Monitoring all the files opened in the server:
sudo sysdig -p "%12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open
Creating a trace file that will only contain writing events in home directories (which we can inspect later with 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
Seeing everything at syscall level a process named exe_file does:
sudo sysdig proc.name=exe_file
Sysdig has many chisels, see for more interesting things it can do:
You also have got dtrace that is not much used in Linux, but is still use a lot with *BSD operating systems:
# Files opened by process,
dtrace -n 'syscall::open*:entry { printf("%s %s",execname,copyinstr(arg0)); }'
Besides sysdig, strace and dtrace, you also have got ltrace, which records/intercepts signals/dynamic libraries/system calls which are called/received by a process:
ltraceis 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) +++
If the program is small, you might also consider disassembling it with objdump -d exe_file or disassembling/decompiling it with Hopper, to see all the files it deals with.
For more details see: Understanding what a Linux binary is doing
As a first approach, I would also do:
strings exe_file
It is a low cost approach, and with luck some of the files names might just be present in ASCII mode in the binary file with luck.
See also related answer Why are true and false so large?
If binaries/files that come with the distribution you can also fetch the sources from the sources repositories of the distribution, or the official repositories of the actual utility.
As a last resource, you can always use tools like gdb or rr to debug the binary in real time.
-
aaa43bb66:~ # sudo proc.name=exe_file sysdig -p "%12user.name %6proc.pid %12proc.name %3fd.num %fd.typechar %fd.name" evt.type=open Unable to load the driver error opening device /dev/sysdig0. Make sure you have root credentials and that the sysdig-probe module is loaded.Boll19– Boll192018-01-29 05:45:58 +00:00Commented Jan 29, 2018 at 5:45
-
/*<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 to load the driver error opening device /dev/sysdig0. Make sure you have root credentials and that the sysdig-probe module is loaded.<code>*/Boll19– Boll192018-01-29 05:53:34 +00:00Commented Jan 29, 2018 at 5:53
-
@Boll19 Got an error there, corrected it. That message seems about a
sysdigbug (are you using ARM?), please post a new question for it.Rui F Ribeiro– Rui F Ribeiro2018-01-29 09:51:20 +00:00Commented Jan 29, 2018 at 9:51
fstat()orlstat()info, etc.