-
-
Save banister/63bf69ae3717bff0f01f8fbebc1f6c33 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* This file is licensed under the GPL v2 (http://www.gnu.org/licenses/gpl2.txt) (some parts was originally borrowed from proc events example) | |
pmon.c | |
code highlighted with GNU source-highlight 3.1 | |
*/ | |
#define _XOPEN_SOURCE 700 | |
#include <sys/socket.h> | |
#include <linux/netlink.h> | |
#include <linux/connector.h> | |
#include <linux/cn_proc.h> | |
#include <signal.h> | |
#include <errno.h> | |
#include <stdbool.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <fcntl.h> | |
int get_exe_for_pid(pid_t pid, char *buf, size_t bufsize) { | |
char path[32]; | |
sprintf(path, "/proc/%d/exe", pid); | |
return readlink(path, buf, bufsize); | |
} | |
/* | |
* connect to netlink | |
* returns netlink socket, or -1 on error | |
*/ | |
static int nl_connect() | |
{ | |
int rc; | |
int nl_sock; | |
struct sockaddr_nl sa_nl; | |
nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | |
if (nl_sock == -1) | |
{ | |
perror("socket"); | |
return -1; | |
} | |
sa_nl.nl_family = AF_NETLINK; | |
sa_nl.nl_groups = CN_IDX_PROC; | |
sa_nl.nl_pid = getpid(); | |
rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl)); | |
if (rc == -1) | |
{ | |
perror("bind"); | |
close(nl_sock); | |
return -1; | |
} | |
return nl_sock; | |
} | |
/* | |
* subscribe on proc events (process notifications) | |
*/ | |
static int set_proc_ev_listen(int nl_sock, bool enable) | |
{ | |
int rc; | |
struct __attribute__((aligned(NLMSG_ALIGNTO))) | |
{ | |
struct nlmsghdr nl_hdr; | |
struct __attribute__((__packed__)) | |
{ | |
struct cn_msg cn_msg; | |
enum proc_cn_mcast_op cn_mcast; | |
}; | |
} nlcn_msg; | |
memset(&nlcn_msg, 0, sizeof(nlcn_msg)); | |
nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg); | |
nlcn_msg.nl_hdr.nlmsg_pid = getpid(); | |
nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE; | |
nlcn_msg.cn_msg.id.idx = CN_IDX_PROC; | |
nlcn_msg.cn_msg.id.val = CN_VAL_PROC; | |
nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op); | |
nlcn_msg.cn_mcast = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE; | |
rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0); | |
if (rc == -1) | |
{ | |
perror("netlink send"); | |
return -1; | |
} | |
return 0; | |
} | |
/* | |
* handle a single process event | |
*/ | |
static volatile bool need_exit = false; | |
static int handle_proc_ev(int nl_sock) | |
{ | |
int rc; | |
struct __attribute__((aligned(NLMSG_ALIGNTO))) | |
{ | |
struct nlmsghdr nl_hdr; | |
struct __attribute__((__packed__)) | |
{ | |
struct cn_msg cn_msg; | |
struct proc_event proc_ev; | |
}; | |
} nlcn_msg; | |
while (!need_exit) | |
{ | |
rc = recv(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0); | |
if (rc == 0) | |
{ | |
/* shutdown? */ | |
return 0; | |
} | |
else if (rc == -1) | |
{ | |
if (errno == EINTR) | |
continue; | |
perror("netlink recv"); | |
return -1; | |
} | |
int pid; | |
switch (nlcn_msg.proc_ev.what) | |
{ | |
case PROC_EVENT_NONE: | |
printf("set mcast listen ok\n"); | |
break; | |
case PROC_EVENT_FORK: | |
printf("fork: parent tid=%d pid=%d -> child tid=%d pid=%d\n", | |
nlcn_msg.proc_ev.event_data.fork.parent_pid, | |
nlcn_msg.proc_ev.event_data.fork.parent_tgid, | |
nlcn_msg.proc_ev.event_data.fork.child_pid, | |
nlcn_msg.proc_ev.event_data.fork.child_tgid); | |
break; | |
case PROC_EVENT_EXEC: | |
pid = nlcn_msg.proc_ev.event_data.exec.process_pid; | |
printf("exec: tid=%d pid=%d\n", | |
nlcn_msg.proc_ev.event_data.exec.process_pid, | |
nlcn_msg.proc_ev.event_data.exec.process_tgid); | |
char buf[256]; | |
get_exe_for_pid(pid, buf, sizeof(buf)); | |
printf("exec: process path=%s\n", buf); | |
sprintf(buf, "/proc/%d/cmdline", pid); | |
int fd = open(buf, O_RDONLY); | |
read(fd, buf, sizeof(buf)); | |
printf("exec: cmdline = %s\n", buf); | |
close(fd); | |
break; | |
case PROC_EVENT_UID: | |
printf("uid change: tid=%d pid=%d from %d to %d\n", | |
nlcn_msg.proc_ev.event_data.id.process_pid, | |
nlcn_msg.proc_ev.event_data.id.process_tgid, | |
nlcn_msg.proc_ev.event_data.id.r.ruid, | |
nlcn_msg.proc_ev.event_data.id.e.euid); | |
break; | |
case PROC_EVENT_GID: | |
printf("gid change: tid=%d pid=%d from %d to %d\n", | |
nlcn_msg.proc_ev.event_data.id.process_pid, | |
nlcn_msg.proc_ev.event_data.id.process_tgid, | |
nlcn_msg.proc_ev.event_data.id.r.rgid, | |
nlcn_msg.proc_ev.event_data.id.e.egid); | |
break; | |
case PROC_EVENT_EXIT: | |
printf("exit: tid=%d pid=%d exit_code=%d\n", | |
nlcn_msg.proc_ev.event_data.exit.process_pid, | |
nlcn_msg.proc_ev.event_data.exit.process_tgid, | |
nlcn_msg.proc_ev.event_data.exit.exit_code); | |
break; | |
default: | |
printf("unhandled proc event\n"); | |
break; | |
} | |
} | |
return 0; | |
} | |
static void on_sigint(int unused) | |
{ | |
need_exit = true; | |
} | |
int main(int argc, const char *argv[]) | |
{ | |
int nl_sock; | |
int rc = EXIT_SUCCESS; | |
signal(SIGINT, &on_sigint); | |
siginterrupt(SIGINT, true); | |
nl_sock = nl_connect(); | |
if (nl_sock == -1) | |
exit(EXIT_FAILURE); | |
rc = set_proc_ev_listen(nl_sock, true); | |
if (rc == -1) | |
{ | |
rc = EXIT_FAILURE; | |
goto out; | |
} | |
rc = handle_proc_ev(nl_sock); | |
if (rc == -1) | |
{ | |
rc = EXIT_FAILURE; | |
goto out; | |
} | |
set_proc_ev_listen(nl_sock, false); | |
out: | |
close(nl_sock); | |
exit(rc); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment