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 time column, a -t option 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 -Ttn mount TIME TIME(s) PCOMM PID PPID RET ARGS 14:08:23 2.849 mount 18049 1045 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 The --cgroupmap option filters based on a cgroup set. It is meant to be used with an externally created map. # ./execsnoop --cgroupmap /sys/fs/bpf/test01 For more details, see docs/special_filtering.md The -U option include UID on output: # ./execsnoop -U UID PCOMM PID PPID RET ARGS 1000 ls 171318 133702 0 /bin/ls --color=auto 1000 w 171322 133702 0 /usr/bin/w The -u options filters output based process UID. You also can use username as argument, in that cause UID will be looked up using getpwnam (see man 3 getpwnam). # ./execsnoop -Uu 1000 UID PCOMM PID PPID RET ARGS 1000 ls 171335 133702 0 /bin/ls --color=auto 1000 man 171340 133702 0 /usr/bin/man getpwnam 1000 bzip2 171341 171340 0 /bin/bzip2 -dc 1000 bzip2 171342 171340 0 /bin/bzip2 -dc 1000 bzip2 171345 171340 0 /bin/bzip2 -dc 1000 manpager 171355 171340 0 /usr/bin/manpager 1000 less 171355 171340 0 /usr/bin/less USAGE message: # ./execsnoop -h usage: execsnoop.py [-h] [-T] [-t] [-x] [--cgroupmap CGROUPMAP] [--mntnsmap MNTNSMAP] [-u USER] [-q] [-n NAME] [-l LINE] [-U] [--max-args MAX_ARGS] [-P PPID] Trace exec() syscalls optional arguments: -h, --help show this help message and exit -T, --time include time column on output (HH:MM:SS) -t, --timestamp include timestamp on output -x, --fails include failed exec()s --cgroupmap CGROUPMAP trace cgroups in this BPF map only --mntnsmap MNTNSMAP trace mount namespaces in this BPF map only -u USER, --uid USER trace this UID only -q, --quote Add quotemarks (") around arguments. -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) -U, --print-uid print UID column --max-args MAX_ARGS maximum number of arguments parsed and displayed, defaults to 20 -P PPID, --ppid PPID trace this parent PID only examples: ./execsnoop # trace all exec() syscalls ./execsnoop -x # include failed exec()s ./execsnoop -T # include time (HH:MM:SS) ./execsnoop -P 181 # only trace new processes whose parent PID is 181 ./execsnoop -U # include UID ./execsnoop -u 1000 # only trace UID 1000 ./execsnoop -u user # get user UID and trace only them ./execsnoop -t # include timestamps ./execsnoop -q # add "quotemarks" around arguments ./execsnoop -n main # only print command lines containing "main" ./execsnoop -l tpkg # only print command where arguments contains "tpkg" ./execsnoop --cgroupmap mappath # only trace cgroups in this BPF map ./execsnoop --mntnsmap mappath # only trace mount namespaces in the map