Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef FORKMONITOR_H
- #define FORKMONITOR_H
- #define FORKMONITOR_ENVNAME "FORKMONITOR_SOCKET"
- #ifndef UNIX_PATH_MAX
- #define UNIX_PATH_MAX 108
- #endif
- #define TYPE_EXEC 1 /* When a binary is executed */
- #define TYPE_DONE 2 /* exit() or return from main() */
- #define TYPE_FORK 3
- #define TYPE_VFORK 4
- #define TYPE_EXIT 5 /* _exit() or _Exit() */
- #define TYPE_ABORT 6 /* abort() */
- struct message {
- pid_t pid; /* Process ID */
- pid_t ppid; /* Parent process ID */
- pid_t sid; /* Session ID */
- pid_t pgid; /* Process group ID */
- uid_t uid; /* Real user ID */
- gid_t gid; /* Real group ID */
- uid_t euid; /* Effective user ID */
- gid_t egid; /* Effective group ID */
- unsigned short len; /* Length of data[] */
- unsigned char type; /* One of the TYPE_ constants */
- char data[0]; /* Optional payload, possibly longer */
- };
- #endif /* FORKMONITOR_H */
- #define _POSIX_C_SOURCE 200809L
- #define _GNU_SOURCE
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/un.h>
- #include <dlfcn.h>
- #include <limits.h>
- #include <string.h>
- #include <stdio.h>
- #include <errno.h>
- #include "forkmonitor.h"
- static pid_t (*actual_fork)(void) = NULL;
- static pid_t (*actual_vfork)(void) = NULL;
- static void (*actual_abort)(void) = NULL;
- static void (*actual__exit)(int) = NULL;
- static void (*actual__Exit)(int) = NULL;
- static int commfd = -1;
- #define MINIMUM_COMMFD 31
- static void notify(const int type, struct message *const msg, const size_t extra)
- {
- const int saved_errno = errno;
- msg->pid = getpid();
- msg->ppid = getppid();
- msg->sid = getsid(0);
- msg->pgid = getpgrp();
- msg->uid = getuid();
- msg->gid = getgid();
- msg->euid = geteuid();
- msg->egid = getegid();
- msg->len = extra;
- msg->type = type;
- /* Since we don't have any method of dealing with send() errors
- * or partial send()s, we just fire one off and hope for the best. */
- send(commfd, msg, sizeof (struct message) + extra, MSG_EOR | MSG_NOSIGNAL);
- errno = saved_errno;
- }
- void libforkmonitor_init(void) __attribute__((constructor));
- void libforkmonitor_init(void)
- {
- const int saved_errno = errno;
- int result;
- /* Save the actual fork() call pointer. */
- if (!actual_fork)
- *(void **)&actual_fork = dlsym(RTLD_NEXT, "fork");
- /* Save the actual vfork() call pointer. */
- if (!actual_vfork)
- *(void **)&actual_vfork = dlsym(RTLD_NEXT, "vfork");
- /* Save the actual abort() call pointer. */
- if (!actual_abort)
- *(void **)&actual_abort = dlsym(RTLD_NEXT, "abort");
- /* Save the actual _exit() call pointer. */
- if (!actual__exit)
- *(void **)&actual__exit = dlsym(RTLD_NEXT, "_exit");
- if (!actual__exit)
- *(void **)&actual__exit = dlsym(RTLD_NEXT, "_Exit");
- /* Save the actual abort() call pointer. */
- if (!actual__Exit)
- *(void **)&actual__Exit = dlsym(RTLD_NEXT, "_Exit");
- if (!actual__Exit)
- *(void **)&actual__Exit = dlsym(RTLD_NEXT, "_exit");
- /* Open an Unix domain datagram socket to the observer. */
- if (commfd == -1) {
- const char *address;
- /* Connect to where? */
- address = getenv(FORKMONITOR_ENVNAME);
- if (address && *address) {
- struct sockaddr_un addr;
- memset(&addr, 0, sizeof addr);
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, address, sizeof addr.sun_path - 1);
- /* Create and bind the socket. */
- commfd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (commfd != -1) {
- if (connect(commfd, (const struct sockaddr *)&addr, sizeof (addr)) == -1) {
- /* Failed. Close the socket. */
- do {
- result = close(commfd);
- } while (result == -1 && errno == EINTR);
- commfd = -1;
- }
- }
- /* Move commfd to a high descriptor, to avoid complications. */
- if (commfd != -1 && commfd < MINIMUM_COMMFD) {
- const int newfd = MINIMUM_COMMFD;
- do {
- result = dup2(commfd, newfd);
- } while (result == -1 && errno == EINTR);
- if (!result) {
- do {
- result = close(commfd);
- } while (result == -1 && errno == EINTR);
- commfd = newfd;
- }
- }
- }
- }
- /* Send an init message, listing the executable path. */
- if (commfd != -1) {
- size_t len = 128;
- struct message *msg = NULL;
- while (1) {
- ssize_t n;
- free(msg);
- msg = malloc(sizeof (struct message) + len);
- if (!msg) {
- len = 0;
- break;
- }
- n = readlink("/proc/self/exe", msg->data, len);
- if (n > (ssize_t)0 && (size_t)n < len) {
- msg->data[n] = '