11#include <linux/cn_proc.h>
12#include <linux/connector.h>
13#include <linux/netlink.h>
14#include <sys/socket.h>
34#ifdef PROC_EVENT_PTRACE
37#ifdef PROC_EVENT_COREDUMP
53 bool subscribe(
bool enable) {
54 std::array<char, NLMSG_SPACE(
sizeof(cn_msg) +
sizeof(
enum proc_cn_mcast_op))> buf{};
55 auto* nlh =
reinterpret_cast<nlmsghdr*
>(buf.data());
56 auto* cn =
reinterpret_cast<cn_msg*
>(NLMSG_DATA(nlh));
57 auto* op =
reinterpret_cast<enum proc_cn_mcast_op*
>(cn->data);
59 nlh->nlmsg_len = NLMSG_LENGTH(
sizeof(cn_msg) +
sizeof(
enum proc_cn_mcast_op));
60 nlh->nlmsg_type = NLMSG_DONE;
63 nlh->nlmsg_pid =
static_cast<std::uint32_t
>(::getpid());
65 cn->id.idx = CN_IDX_PROC;
66 cn->id.val = CN_VAL_PROC;
69 cn->len =
sizeof(
enum proc_cn_mcast_op);
72 *op = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE;
73 return ::send(fd, nlh, nlh->nlmsg_len, 0) ==
static_cast<ssize_t
>(nlh->nlmsg_len);
78ProcEventMonitor::~ProcEventMonitor() { stop(); }
80bool ProcEventMonitor::start(Handler handler) {
82 impl_ = std::make_unique<Impl>();
83 impl_->handler = std::move(handler);
85 impl_->fd = ::socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
92 addr.nl_family = AF_NETLINK;
93 addr.nl_groups = CN_IDX_PROC;
94 addr.nl_pid =
static_cast<std::uint32_t
>(::getpid());
96 if (::bind(impl_->fd,
reinterpret_cast<sockaddr*
>(&addr),
sizeof(addr)) < 0) {
103 if (!impl_->subscribe(
true)) {
111 impl_->thread = std::thread([
this]() {
112 std::array<char, 4096> buf{};
114 const auto recv_len = ::recv(impl_->fd, buf.data(), buf.size(), 0);
116 if (errno == EINTR)
continue;
121 int remaining =
static_cast<int>(recv_len);
122 for (nlmsghdr* nlh =
reinterpret_cast<nlmsghdr*
>(buf.data()); NLMSG_OK(nlh, remaining); nlh = NLMSG_NEXT(nlh, remaining)) {
123 if (nlh->nlmsg_type == NLMSG_ERROR || nlh->nlmsg_type == NLMSG_NOOP)
continue;
124 auto* cn =
reinterpret_cast<cn_msg*
>(NLMSG_DATA(nlh));
125 if (!cn || cn->id.idx != CN_IDX_PROC || cn->id.val != CN_VAL_PROC)
continue;
126 auto* ev =
reinterpret_cast<proc_event*
>(cn->data);
130 out.type = from_what(ev->what);
132 case PROC_EVENT_FORK:
133 out.pid = ev->event_data.fork.child_pid;
134 out.tgid = ev->event_data.fork.child_tgid;
135 out.parent_pid = ev->event_data.fork.parent_pid;
136 out.parent_tgid = ev->event_data.fork.parent_tgid;
138 case PROC_EVENT_EXEC:
139 out.pid = ev->event_data.exec.process_pid;
140 out.tgid = ev->event_data.exec.process_tgid;
142 case PROC_EVENT_EXIT:
143 out.pid = ev->event_data.exit.process_pid;
144 out.tgid = ev->event_data.exit.process_tgid;
145 out.exit_code =
static_cast<std::int32_t
>(ev->event_data.exit.exit_code);
146 out.exit_signal = ev->event_data.exit.exit_signal;
149 out.pid = ev->event_data.id.process_pid;
150 out.tgid = ev->event_data.id.process_tgid;
151 out.uid = ev->event_data.id.r.ruid;
154 out.pid = ev->event_data.id.process_pid;
155 out.tgid = ev->event_data.id.process_tgid;
156 out.gid = ev->event_data.id.r.rgid;
158#ifdef PROC_EVENT_COMM
159 case PROC_EVENT_COMM:
160 out.pid = ev->event_data.comm.process_pid;
161 out.tgid = ev->event_data.comm.process_tgid;
162 out.comm = ev->event_data.comm.comm;
168 if (impl_->handler) impl_->handler(out);
175void ProcEventMonitor::stop() {
178 if (impl_->fd >= 0) {
179 impl_->subscribe(
false);
180 ::shutdown(impl_->fd, SHUT_RDWR);
184 if (impl_->thread.joinable()) impl_->thread.join();
187bool ProcEventMonitor::available() {
return true; }
void warning(const std::string &msg)
static Logger & instance()
std::function< void(const ProcEvent &)> Handler
std::unique_ptr< Impl > impl_
bool start(Handler handler)