Skip to content
API Documentation
BastionGuard™
bsc::proc::ProcMon Class Reference

#include <ProcMon.hpp>

Classes

struct  CacheEntry

Public Member Functions

std::optional< bsc::model::ProcessInfo > inspect (std::uint32_t pid, bool checksums=false) const
std::optional< bsc::model::ProcessInfo > cached (std::uint32_t pid, bool allow_recent_exit=true) const
std::vector< bsc::model::ProcessInfo > recent_candidates (std::uint32_t uid, std::chrono::milliseconds max_age=std::chrono::milliseconds(5000), std::size_t limit=8) const
std::vector< bsc::model::ProcessInfo > recent_candidates_any (std::chrono::milliseconds max_age=std::chrono::milliseconds(1500), std::size_t limit=8) const
void cache_process (const bsc::model::ProcessInfo &info) const
void invalidate (std::uint32_t pid) const
void note_fork (std::uint32_t child_pid, std::uint32_t parent_pid) const
void note_exec (std::uint32_t pid, bool checksums=false) const
void note_exit (std::uint32_t pid) const

Static Private Member Functions

static std::optional< bsc::model::ProcessInfo > inspect_procfs (std::uint32_t pid, bool checksums)

Private Attributes

std::mutex cache_mutex_
std::unordered_map< std::uint32_t, CacheEntry > cache_
std::unordered_map< std::uint32_t, CacheEntry > exited_

Detailed Description

Definition at line 13 of file ProcMon.hpp.

Member Function Documentation

◆ cache_process()

void bsc::proc::ProcMon::cache_process ( const bsc::model::ProcessInfo & info) const

Definition at line 227 of file ProcMon.cpp.

227 {
228 std::lock_guard lock(cache_mutex_);
229 auto& entry = cache_[static_cast<std::uint32_t>(info.pid)];
230 entry.info = info;
231 entry.has_checksums = !info.checksums.empty();
232 entry.updated_at = std::chrono::steady_clock::now();
233 exited_.erase(static_cast<std::uint32_t>(info.pid));
234}
std::unordered_map< std::uint32_t, CacheEntry > exited_
Definition ProcMon.hpp:39
std::mutex cache_mutex_
Definition ProcMon.hpp:37
std::unordered_map< std::uint32_t, CacheEntry > cache_
Definition ProcMon.hpp:38
std::map< std::string, std::string > checksums

References cache_, cache_mutex_, bsc::model::ProcessInfo::checksums, exited_, and bsc::model::ProcessInfo::pid.

Referenced by note_exec().

◆ cached()

std::optional< bsc::model::ProcessInfo > bsc::proc::ProcMon::cached ( std::uint32_t pid,
bool allow_recent_exit = true ) const

Definition at line 122 of file ProcMon.cpp.

122 {
123 const auto now = std::chrono::steady_clock::now();
124 std::lock_guard lock(cache_mutex_);
125 if (const auto it = cache_.find(pid); it != cache_.end()) return it->second.info;
126 if (allow_recent_exit) {
127 if (const auto it = exited_.find(pid); it != exited_.end()) {
128 if (now - it->second.updated_at <= kRecentExitTtl) return it->second.info;
129 exited_.erase(it);
130 }
131 }
132 return std::nullopt;
133}

References cache_, cache_mutex_, and exited_.

Referenced by inspect().

◆ inspect()

std::optional< bsc::model::ProcessInfo > bsc::proc::ProcMon::inspect ( std::uint32_t pid,
bool checksums = false ) const

Definition at line 192 of file ProcMon.cpp.

192 {
193 const auto now = std::chrono::steady_clock::now();
194 {
195 std::lock_guard lock(cache_mutex_);
196 if (const auto it = cache_.find(pid); it != cache_.end()) {
197 const auto age = now - it->second.updated_at;
198 const auto fresh = age <= kFreshCacheTtl;
199 const auto checksum_ok = !checksums || it->second.has_checksums;
200 if (fresh && checksum_ok) return it->second.info;
201 }
202 if (const auto it = exited_.find(pid); it != exited_.end()) {
203 const auto age = now - it->second.updated_at;
204 const auto checksum_ok = !checksums || it->second.has_checksums;
205 if (age <= kRecentExitTtl && checksum_ok) return it->second.info;
206 if (age > kRecentExitTtl) exited_.erase(it);
207 }
208 }
209
210 auto info = inspect_procfs(pid, checksums);
211 if (!info) {
212 if (auto stale = cached(pid, true)) return stale;
213 invalidate(pid);
214 return std::nullopt;
215 }
216
217 CacheEntry entry;
218 entry.info = *info;
219 entry.has_checksums = !info->checksums.empty();
220 entry.updated_at = now;
221 std::lock_guard lock(cache_mutex_);
222 exited_.erase(pid);
223 cache_[pid] = std::move(entry);
224 return info;
225}
static std::optional< bsc::model::ProcessInfo > inspect_procfs(std::uint32_t pid, bool checksums)
Definition ProcMon.cpp:66
std::optional< bsc::model::ProcessInfo > cached(std::uint32_t pid, bool allow_recent_exit=true) const
Definition ProcMon.cpp:122
void invalidate(std::uint32_t pid) const
Definition ProcMon.cpp:236
bsc::model::ProcessInfo info
Definition ProcMon.hpp:30

References cache_, cache_mutex_, cached(), exited_, bsc::proc::ProcMon::CacheEntry::has_checksums, bsc::proc::ProcMon::CacheEntry::info, inspect_procfs(), invalidate(), and bsc::proc::ProcMon::CacheEntry::updated_at.

◆ inspect_procfs()

std::optional< bsc::model::ProcessInfo > bsc::proc::ProcMon::inspect_procfs ( std::uint32_t pid,
bool checksums )
staticprivate

Definition at line 66 of file ProcMon.cpp.

66 {
67 fs::path base = fs::path("/proc") / std::to_string(pid);
68 if (!fs::exists(base)) return std::nullopt;
69 bsc::model::ProcessInfo p; p.pid = pid;
70 std::error_code ec;
71 p.path = fs::read_symlink(base / "exe", ec).string();
72 ec.clear(); p.cwd = fs::read_symlink(base / "cwd", ec).string();
73 p.args = split_nulls(slurp(base / "cmdline", true));
74 auto env = split_nulls(slurp(base / "environ", true));
75 for (const auto& e : env) { auto pos=e.find('='); if (pos!=std::string::npos) p.env[e.substr(0,pos)] = e.substr(pos+1); }
76
77 // /proc/<pid>/comm contiene il nome del processo terminato da \n.
78 // Piu' affidabile del parsing di /proc/<pid>/status (separatore variabile).
79 {
80 std::ifstream comm_file(base / "comm");
81 if (comm_file) {
82 std::string comm_line;
83 if (std::getline(comm_file, comm_line)) {
84 while (!comm_line.empty() &&
85 (comm_line.back() == '\n' || comm_line.back() == '\r' ||
86 std::isspace(static_cast<unsigned char>(comm_line.back()))))
87 comm_line.pop_back();
88 p.comm = std::move(comm_line);
89 }
90 }
91 }
92
93 std::ifstream status(base / "status");
94 std::string line;
95 while (std::getline(status, line)) {
96 // Fallback per p.comm se /proc/<pid>/comm non era leggibile
97 if (p.comm.empty() && line.rfind("Name:", 0) == 0) {
98 p.comm = line.substr(5);
99 while (!p.comm.empty() && std::isspace(static_cast<unsigned char>(p.comm.front()))) p.comm.erase(p.comm.begin());
100 while (!p.comm.empty() && std::isspace(static_cast<unsigned char>(p.comm.back()))) p.comm.pop_back();
101 }
102 else if (line.rfind("PPid:", 0) == 0) p.ppid = std::stoull(line.substr(6));
103 else if (line.rfind("Uid:", 0) == 0) { std::istringstream iss(line.substr(5)); iss >> p.uid; }
104 }
105 for (auto current = p.pid; current > 0;) {
106 fs::path status_path = fs::path("/proc") / std::to_string(current) / "status";
107 std::ifstream st(status_path);
108 if (!st) break;
109 std::string name; std::uint64_t ppid=0;
110 while (std::getline(st, line)) {
111 if (line.rfind("Name:",0)==0) { name = line.substr(6); while (!name.empty() && std::isspace(static_cast<unsigned char>(name.front()))) name.erase(name.begin()); }
112 else if (line.rfind("PPid:",0)==0) ppid = std::stoull(line.substr(6));
113 }
114 p.process_tree.emplace_back(name, static_cast<std::uint32_t>(current));
115 if (ppid == current) break;
116 current = ppid;
117 }
118 if (checksums && !p.path.empty()) { p.checksums["md5"] = md5_file(p.path); p.checksums["sha1"] = sha1_file(p.path); p.checksums["sha256"] = sha256_file(p.path); }
119 return p;
120}
std::string sha256_file(const std::string &path)
std::string md5_file(const fs::path &p)
Definition ProcMon.cpp:31
std::string slurp(const fs::path &p, bool binary=false)
Definition ProcMon.cpp:17
std::string sha1_file(const fs::path &p)
Definition ProcMon.cpp:42
std::vector< std::string > split_nulls(const std::string &s)
Definition ProcMon.cpp:22
std::map< std::string, std::string > env
std::vector< std::pair< std::string, std::uint32_t > > process_tree
std::vector< std::string > args

References bsc::model::ProcessInfo::args, bsc::model::ProcessInfo::checksums, bsc::model::ProcessInfo::comm, bsc::model::ProcessInfo::cwd, bsc::model::ProcessInfo::env, bsc::model::ProcessInfo::path, bsc::model::ProcessInfo::pid, bsc::model::ProcessInfo::ppid, bsc::model::ProcessInfo::process_tree, sha256_file(), and bsc::model::ProcessInfo::uid.

Referenced by inspect(), and note_exec().

◆ invalidate()

void bsc::proc::ProcMon::invalidate ( std::uint32_t pid) const

Definition at line 236 of file ProcMon.cpp.

236 {
237 std::lock_guard lock(cache_mutex_);
238 cache_.erase(pid);
239 exited_.erase(pid);
240}

References cache_, cache_mutex_, and exited_.

Referenced by inspect().

◆ note_exec()

void bsc::proc::ProcMon::note_exec ( std::uint32_t pid,
bool checksums = false ) const

Definition at line 257 of file ProcMon.cpp.

257 {
258 if (auto info = inspect_procfs(pid, checksums)) {
259 cache_process(*info);
260 }
261}
void cache_process(const bsc::model::ProcessInfo &info) const
Definition ProcMon.cpp:227

References cache_process(), and inspect_procfs().

◆ note_exit()

void bsc::proc::ProcMon::note_exit ( std::uint32_t pid) const

Definition at line 263 of file ProcMon.cpp.

263 {
264 std::lock_guard lock(cache_mutex_);
265 if (const auto it = cache_.find(pid); it != cache_.end()) {
266 auto entry = it->second;
267 entry.updated_at = std::chrono::steady_clock::now();
268 exited_[pid] = std::move(entry);
269 cache_.erase(it);
270 }
271}

References cache_, cache_mutex_, and exited_.

◆ note_fork()

void bsc::proc::ProcMon::note_fork ( std::uint32_t child_pid,
std::uint32_t parent_pid ) const

Definition at line 242 of file ProcMon.cpp.

242 {
243 std::lock_guard lock(cache_mutex_);
244 if (const auto it = cache_.find(parent_pid); it != cache_.end()) {
245 auto child = it->second;
246 child.info.pid = child_pid;
247 child.info.ppid = parent_pid;
248 child.info.checksums.clear();
249 child.has_checksums = false;
250 child.updated_at = std::chrono::steady_clock::now();
251 child.info.process_tree.clear();
252 cache_[child_pid] = std::move(child);
253 exited_.erase(child_pid);
254 }
255}

References cache_, cache_mutex_, and exited_.

◆ recent_candidates()

std::vector< bsc::model::ProcessInfo > bsc::proc::ProcMon::recent_candidates ( std::uint32_t uid,
std::chrono::milliseconds max_age = std::chrono::milliseconds(5000),
std::size_t limit = 8 ) const

Definition at line 135 of file ProcMon.cpp.

137 {
138 const auto now = std::chrono::steady_clock::now();
139 std::vector<std::pair<std::chrono::steady_clock::time_point, bsc::model::ProcessInfo>> tmp;
140
141 std::lock_guard lock(cache_mutex_);
142 auto consider = [&](const CacheEntry& entry) {
143 if (entry.info.uid != uid) return;
144 if (entry.info.comm.empty() && entry.info.path.empty()) return;
145 if (max_age.count() > 0 && now - entry.updated_at > max_age) return;
146 tmp.emplace_back(entry.updated_at, entry.info);
147 };
148 for (const auto& [pid, entry] : cache_) consider(entry);
149 for (const auto& [pid, entry] : exited_) consider(entry);
150
151 std::sort(tmp.begin(), tmp.end(), [](const auto& a, const auto& b) {
152 return a.first > b.first;
153 });
154
155 std::vector<bsc::model::ProcessInfo> out;
156 out.reserve(std::min(limit, tmp.size()));
157 for (const auto& [ts, info] : tmp) {
158 out.push_back(info);
159 if (out.size() >= limit) break;
160 }
161 return out;
162}

References cache_, cache_mutex_, and exited_.

◆ recent_candidates_any()

std::vector< bsc::model::ProcessInfo > bsc::proc::ProcMon::recent_candidates_any ( std::chrono::milliseconds max_age = std::chrono::milliseconds(1500),
std::size_t limit = 8 ) const

Definition at line 165 of file ProcMon.cpp.

166 {
167 const auto now = std::chrono::steady_clock::now();
168 std::vector<std::pair<std::chrono::steady_clock::time_point, bsc::model::ProcessInfo>> tmp;
169
170 std::lock_guard lock(cache_mutex_);
171 auto consider = [&](const CacheEntry& entry) {
172 if (entry.info.comm.empty() && entry.info.path.empty()) return;
173 if (max_age.count() > 0 && now - entry.updated_at > max_age) return;
174 tmp.emplace_back(entry.updated_at, entry.info);
175 };
176 for (const auto& [pid, entry] : cache_) consider(entry);
177 for (const auto& [pid, entry] : exited_) consider(entry);
178
179 std::sort(tmp.begin(), tmp.end(), [](const auto& a, const auto& b) {
180 return a.first > b.first;
181 });
182
183 std::vector<bsc::model::ProcessInfo> out;
184 out.reserve(std::min(limit, tmp.size()));
185 for (const auto& [ts, info] : tmp) {
186 out.push_back(info);
187 if (out.size() >= limit) break;
188 }
189 return out;
190}

References cache_, cache_mutex_, and exited_.

Member Data Documentation

◆ cache_

std::unordered_map<std::uint32_t, CacheEntry> bsc::proc::ProcMon::cache_
mutableprivate

◆ cache_mutex_

std::mutex bsc::proc::ProcMon::cache_mutex_
mutableprivate

◆ exited_

std::unordered_map<std::uint32_t, CacheEntry> bsc::proc::ProcMon::exited_
mutableprivate

The documentation for this class was generated from the following files:
  • BastionGuard/thirdparty/bastionguard-secure-connection/daemon/include/bsc/proc/ProcMon.hpp
  • BastionGuard/thirdparty/bastionguard-secure-connection/daemon/src/proc/ProcMon.cpp