Demonstrations of execsnoop, the Linux eBPF/bcc version.
execsnoop traces new processes. For example, tracing the commands invoked when
running "man ls":
# ./execsnoop
PCOMM PID RET ARGS
bash 15887 0 /usr/bin/man ls
preconv 15894 0 /usr/bin/preconv -e UTF-8
man 15896 0 /usr/bin/tbl
man 15897 0 /usr/bin/nroff -mandoc -rLL=169n -rLT=169n -Tutf8
man 15898 0 /usr/bin/pager -s
nroff 15900 0 /usr/bin/locale charmap
nroff 15901 0 /usr/bin/groff -mtty-char -Tutf8 -mandoc -rLL=169n -rLT=169n
groff 15902 0 /usr/bin/troff -mtty-char -mandoc -rLL=169n -rLT=169n -Tutf8
groff 15903 0 /usr/bin/grotty
The output shows the parent process/command name (PCOMM), the PID, the return
value of the exec() (RET), and the filename with arguments (ARGS).
This works by traces the execve() system call (commonly used exec() variant),
and shows details of the arguments and return value. This catches new processes
that follow the fork->exec sequence, as well as processes that re-exec()
themselves. Some applications fork() but do not exec(), eg, for worker
processes, which won't be included in the execsnoop output.
The -x option can be used to include failed exec()s. For example:
# ./execsnoop -x
PCOMM PID RET ARGS
supervise 9660 0 ./run
supervise 9661 0 ./run
mkdir 9662 0 /bin/mkdir -p ./main
run 9663 0 ./run
chown 9664 0 /bin/chown nobody:nobody ./main
run 9665 0 /bin/mkdir -p ./main
supervise 9667 0 ./run
run 9660 -2 /usr/local/bin/setuidgid nobody /command/multilog t ./main
chown 9668 0 /bin/chown nobody:nobody ./main
run 9666 0 /bin/chmod 0777 main
run 9663 -2 /usr/local/bin/setuidgid nobody /command/multilog t ./main
run 9669 0 /bin/mkdir -p ./main
run 9661 -2 /usr/local/bin/setuidgid nobody /command/multilog t ./main
supervise 9670 0 ./run
[...]
This example shows various regular system daemon activity, including some
failures (trying to execute a /usr/local/bin/setuidgid, which I just noticed
doesn't exist).
A -t option can be used to include a timestamp column, and a -n option to match
on a name. Regular expressions are allowed.
For example, matching commands containing "mount":
# ./execsnoop -tn mount
TIME(s) PCOMM PID RET ARGS
2.849 mount 18049 0 /bin/mount -p
The -l option can be used to only show command where one of the arguments
matches specified line. The limitation is that we are looking only into first 20
arguments of the command. For example, matching all command where one of the argument
is "testpkg":
# ./execsnoop.py -l testpkg
PCOMM PID PPID RET ARGS
service 3344535 4146419 0 /usr/sbin/service testpkg status
systemctl 3344535 4146419 0 /bin/systemctl status testpkg.service
yum 3344856 4146419 0 /usr/local/bin/yum remove testpkg
python 3344856 4146419 0 /usr/local/bin/python /usr/local/bin/yum remove testpkg
yum 3344856 4146419 0 /usr/bin/yum remove testpkg
yum 3345086 4146419 0 /usr/local/bin/yum install testpkg
python 3345086 4146419 0 /usr/local/bin/python /usr/local/bin/yum install testpkg
yum 3345086 4146419 0 /usr/bin/yum install testpkg
rpm 3345452 4146419 0 /bin/rpm -qa testpkg
USAGE message:
# ./execsnoop -h
usage: execsnoop [-h] [-t] [-x] [-n NAME] [-l LINE] [--max-args MAX_ARGS]
Trace exec() syscalls
optional arguments:
-h, --help show this help message and exit
-t, --timestamp include timestamp on output
-x, --fails include failed exec()s
-n NAME, --name NAME only print commands matching this name (regex), any
arg
-l LINE, --line LINE only print commands where arg contains this line
(regex)
--max-args MAX_ARGS maximum number of arguments parsed and displayed,
defaults to 20
examples:
./execsnoop # trace all exec() syscalls
./execsnoop -x # include failed exec()s
./execsnoop -t # include timestamps
./execsnoop -n main # only print command lines containing "main"
./execsnoop -l tpkg # only print command where arguments contains "tpkg"