Does anyone know a simple way to monitor root process spawn

I want to exec a script when a new root process spawns. (on Linux) How can I simply do that ?

Thanks


Solution 1:

This sounds like a perfect job for auditd. Once you have auditd running, a default service on modern RedHat based systems, you can craft a rule that will do exactly what you want by executing

auditctl -a task,always -F uid=0

Breaking this command rule down, making excessive use of the man page, we find that:

   -a list,action
          task       Add  a  rule to the per task list. This rule list is used
                     only at the time a task is created -- when fork() or
                     clone() are called by the parent task. When using this
                     list, you should only use fields that are known at task
                     creation time, such as the uid, gid, etc.
          always     Allocate an audit context, always fill it in at syscall 
                     entry time, and always write out a record at syscall exit
                     time.

So always write out a record for this action whenever a fork or clone system call exits.

The final option can be thought of as a filter string, in our use -F uid=0 simply restricts us to cases where the uid of the process owner is 0.

Note that this rule can be executed at run time by making sure that auditd is properly configured, and adding the rule
-a task,always -F uid=0
into the relevant file for your distribution, most likely /etc/audit/audit.rules

Just keep in mind that this will be pretty dang noisy, and whomever is doing your log reviews will need to be prepared for it.

Solution 2:

I don't think there's a clean way to do this without recompiling your kernel with CONFIG_PROC_EVENTS and/or CONFIG_KPROBES (although I'd love to know if there is a way of doing it, so I've upvoted your question).

I did have an idea of using iwatch/inotify for directory creation inside /proc but it didn't seem to work, neither did auditctl. It looks like your best choice, although dirty, is to continually parse ps for a change from a script. The following Perl code would do it, although would be prone to miss some and ignores ps (as it would otherwise trigger itself):

perl -e 'my %pids; while(1) { my @pids = `ps -U root -u root`; foreach (@pids) { next if /ps$/; ($pid) = /^\s*(\d+)\D/; if (!$pids{$pid}) { $pids{$pid}++; print "Process $pid created (" . `cat /proc/$pid/cmdline` . ")\n"; } } }

Solution 3:

You can do this using exec-snoop (based on ebpf), tracepoints, audit, the netlink process connector, and some other mechanisms. I've written a comparison of all the methods here.

Solution 4:

The best way I can think of would be to build off the snoopy library. snoopy is a very small shared library that gets hooked into /etc/ld.so.preload and wraps around execve() system calls. It's configurable to log all exec()'s, or just those from root. In it's current incarnation, snoopy logs to syslog every time a matching event (a syscall to execve()) happens. It's not a large program though (a couple hundreds lines of code, at most), and could be modified without that much difficulty to execute a script instead of (or in addition to) logging the activity. Snoopy is written in C.

A few things to note:

  • If you run a script every time a root process is spawned, your script will be a root process, which will need to spawn the script again, which will be another root process, etc. Be careful that you don't get into a loop there.
  • On a typical Linux box, there are a lot of processes that get run as root, and spawned regularly. For example, cron may spawn system cronjobs as root every minute or few minutes. If you're just looking for this to happen when a user logs in as root, it will be more work.