I want to exec a script when a new root process spawns. (on Linux) How can I simply do that ?
Thanks
I want to exec a script when a new root process spawns. (on Linux) How can I simply do that ?
Thanks
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.
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.
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"; } } }
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: