Skip to content
API Documentation
BastionGuard™
ProcEventMonitor.cpp
Go to the documentation of this file.
3
4#include <array>
5#include <cerrno>
6#include <cstring>
7#include <memory>
8#include <thread>
9
10#if defined(__linux__)
11#include <linux/cn_proc.h>
12#include <linux/connector.h>
13#include <linux/netlink.h>
14#include <sys/socket.h>
15#include <unistd.h>
16#endif
17
18namespace bsc::netlink {
19
20#if defined(__linux__)
21namespace {
22
23ProcEvent::Type from_what(std::uint32_t what) {
24 switch (what) {
25 case PROC_EVENT_FORK: return ProcEvent::Type::Fork;
26 case PROC_EVENT_EXEC: return ProcEvent::Type::Exec;
27 case PROC_EVENT_EXIT: return ProcEvent::Type::Exit;
28 case PROC_EVENT_UID: return ProcEvent::Type::Uid;
29 case PROC_EVENT_GID: return ProcEvent::Type::Gid;
30 case PROC_EVENT_SID: return ProcEvent::Type::Sid;
31#ifdef PROC_EVENT_COMM
32 case PROC_EVENT_COMM: return ProcEvent::Type::Comm;
33#endif
34#ifdef PROC_EVENT_PTRACE
35 case PROC_EVENT_PTRACE: return ProcEvent::Type::Ptrace;
36#endif
37#ifdef PROC_EVENT_COREDUMP
38 case PROC_EVENT_COREDUMP: return ProcEvent::Type::CoreDump;
39#endif
40 default: return ProcEvent::Type::Unknown;
41 }
42}
43
44} // namespace
45
46
48 public:
49 int fd{-1};
50 std::thread thread;
51 Handler handler;
52
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);
58
59 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(cn_msg) + sizeof(enum proc_cn_mcast_op));
60 nlh->nlmsg_type = NLMSG_DONE;
61 nlh->nlmsg_flags = 0;
62 nlh->nlmsg_seq = 0;
63 nlh->nlmsg_pid = static_cast<std::uint32_t>(::getpid());
64
65 cn->id.idx = CN_IDX_PROC;
66 cn->id.val = CN_VAL_PROC;
67 cn->seq = 0;
68 cn->ack = 0;
69 cn->len = sizeof(enum proc_cn_mcast_op);
70 cn->flags = 0;
71
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);
74 }
75};
76
77ProcEventMonitor::ProcEventMonitor() : impl_(std::make_unique<Impl>()) {}
78ProcEventMonitor::~ProcEventMonitor() { stop(); }
79
80bool ProcEventMonitor::start(Handler handler) {
81 stop();
82 impl_ = std::make_unique<Impl>();
83 impl_->handler = std::move(handler);
84
85 impl_->fd = ::socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
86 if (impl_->fd < 0) {
87 bsc::logging::Logger::instance().warning(std::string("proc netlink socket failed: ") + std::strerror(errno));
88 return false;
89 }
90
91 sockaddr_nl addr{};
92 addr.nl_family = AF_NETLINK;
93 addr.nl_groups = CN_IDX_PROC;
94 addr.nl_pid = static_cast<std::uint32_t>(::getpid());
95
96 if (::bind(impl_->fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
97 bsc::logging::Logger::instance().warning(std::string("proc netlink bind failed: ") + std::strerror(errno));
98 ::close(impl_->fd);
99 impl_->fd = -1;
100 return false;
101 }
102
103 if (!impl_->subscribe(true)) {
104 bsc::logging::Logger::instance().warning(std::string("proc netlink subscribe failed: ") + std::strerror(errno));
105 ::close(impl_->fd);
106 impl_->fd = -1;
107 return false;
108 }
109
110 running_ = true;
111 impl_->thread = std::thread([this]() {
112 std::array<char, 4096> buf{};
113 while (running_) {
114 const auto recv_len = ::recv(impl_->fd, buf.data(), buf.size(), 0);
115 if (recv_len <= 0) {
116 if (errno == EINTR) continue;
117 if (running_) bsc::logging::Logger::instance().warning(std::string("proc netlink recv failed: ") + std::strerror(errno));
118 break;
119 }
120
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);
127 if (!ev) continue;
128
129 ProcEvent out;
130 out.type = from_what(ev->what);
131 switch (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;
137 break;
138 case PROC_EVENT_EXEC:
139 out.pid = ev->event_data.exec.process_pid;
140 out.tgid = ev->event_data.exec.process_tgid;
141 break;
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;
147 break;
148 case PROC_EVENT_UID:
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;
152 break;
153 case PROC_EVENT_GID:
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;
157 break;
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;
163 break;
164#endif
165 default:
166 break;
167 }
168 if (impl_->handler) impl_->handler(out);
169 }
170 }
171 });
172 return true;
173}
174
175void ProcEventMonitor::stop() {
176 running_ = false;
177 if (!impl_) return;
178 if (impl_->fd >= 0) {
179 impl_->subscribe(false);
180 ::shutdown(impl_->fd, SHUT_RDWR);
181 ::close(impl_->fd);
182 impl_->fd = -1;
183 }
184 if (impl_->thread.joinable()) impl_->thread.join();
185}
186
187bool ProcEventMonitor::available() { return true; }
188
189#else
190
194bool ProcEventMonitor::start(Handler) { return false; }
196bool ProcEventMonitor::available() { return false; }
197
198#endif
199
200} // namespace bsc::netlink
void warning(const std::string &msg)
Definition Logger.cpp:22
static Logger & instance()
Definition Logger.cpp:11