Linux – Monitoring what program calls an executable file

executablefileslinuxmonitoring

I want to know what program calls a particular executable, including when that executable is used as an interpreter via a shebang line.

This is not quite the same problem as knowing what program accesses a particular file. For example, auditctl -w /usr/bin/myprogram tells me that the program is being executed by… itself, since the audit event is generated after the successful execve call.

One option is to replace the executable by a wrapper program, like this…

#!/bin/sh
logger "$0: executed by uid=$(id -u) ruid=$(id -ur) cmd=$(ps -o args= -p $PPID)"
exec "$0.real" "$@"

But this requires moving the actual file, which is disruptive (the file can't be read-only, it clashes with modifications made by a package manager, etc.). And it doesn't work if the program is used as an interpreter for a script, because shebang doesn't nest. (In that case, auditctl -w /usr/bin/interpreter does give a useful result, but I want a solution that works for both cases.) It also doesn't work for setuid programs if /bin/sh is bash since bash drops privileges.

How can I monitor executions of a particular executable including uses of the executable as a shebang interpreter, and in particular log useful information about the calling process (not just the PPID but at least the process name or the parent executable path, ideally also the invoking user and arguments)? Preferably without replacing the file with a wrapper. A Linux-specific solution is fine.

Best Answer

This would be hacky, but if it's a dynamically linked executable, you could set up a global preload in /etc/ld.so.preload which would only trigger a logging hook if it detected you were in the right executable.

Something like:

#define _XOPEN_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define TARGET "/some_executable"

__attribute__((constructor)) 
static void 
logger(int argc, char** argv){ 
    /*catch own argv right here and parent's later from /proc */

    static char buf[sizeof(TARGET)];

    readlink("/proc/self/exe", buf, sizeof(buf)-1);

    if ( 0==strcmp(TARGET, buf)){
        /* ... */
        syslog(/*...*/);
    }
}

The obvious disadvantage of this approach is it would slightly delay the execution of each dynamically linked executable on your system, but my measurements indicate the delay is quite small (<1ms where fork+exec costs about 2ms).

As for the dropped permission problem, you could have a small setuid-root binary that will unconditionally read and echo its grandparents proc files (the status file, most likely), possibly if and only if its parent is the executable whose parents you want to log. You could then spawn that setuid executable inside your logging hook to obtain the info on the executables parent (grandparent of the setuid helper).

Related Question