Skip to content
API Documentation
BastionGuard™
BastionGuard::RootGuard Namespace Reference

Namespaces

namespace  anonymous_namespace{RootGuardClient.cpp}
namespace  anonymous_namespace{RootGuardEvent.cpp}

Classes

struct  ApplicationRules
class  Client
struct  Event
struct  ServiceStatus
struct  Snapshot

Enumerations

enum class  EventSeverity { Telemetry , Observation , Incident }

Functions

std::optional< Event > parse_event_json (const std::string &line)
std::string format_event (const Event &event)
std::string event_fingerprint (const Event &event)
EventSeverity classify_event (const Event &event) noexcept
bool is_security_observation (const Event &event) noexcept
bool is_actionable_incident (const Event &event) noexcept
bool is_system_service_path (const std::string &path) noexcept

Enumeration Type Documentation

◆ EventSeverity

Function Documentation

◆ classify_event()

EventSeverity BastionGuard::RootGuard::classify_event ( const Event & event)
noexcept

Definition at line 217 of file RootGuardEvent.cpp.

218{
219 if (event.filename.empty() || event.filename == "--")
221 if (event.verdict != "blocked" && event.verdict != "alert" &&
222 event.verdict != "audit")
224
225 if (event.event == "service-blocked")
227
228 const bool metadataEvent =
229 event.event == "permission-change" ||
230 event.event == "owner-change" ||
231 event.event == "xattr-change" ||
232 event.event == "acl-change";
233 if (metadataEvent) {
234 /*
235 * Explicitly protected identities retain their existing incident
236 * semantics because they have a baseline and may have been blocked.
237 */
238 if (event.rule_id != 0)
240
241 /*
242 * Desktop policy: unprotected global privilege metadata is diagnostic
243 * telemetry only. Keep it visible as an observation when explicitly
244 * enabled, but never let backup/package metadata replay interrupt the
245 * user with a popup. Historical broad-surveillance records remain
246 * telemetry-only.
247 */
248 if ((event.reason_flags & RG_REASON_GLOBAL_METADATA) != 0)
249 return (event.reason_flags & RG_REASON_METADATA_BURST) != 0
252
254 }
255
256 if (event.event == "protected-unlink" ||
257 event.event == "protected-rename" ||
258 event.event == "protected-hardlink" ||
259 event.event == "integrity-drift")
260 return event.rule_id != 0
263
265}
@ RG_REASON_METADATA_BURST
@ RG_REASON_GLOBAL_METADATA

References classify_event(), Incident, Observation, RG_REASON_GLOBAL_METADATA, RG_REASON_METADATA_BURST, and Telemetry.

Referenced by classify_event(), is_actionable_incident(), is_security_observation(), main(), and RootGuardPage::render_incidents().

◆ event_fingerprint()

std::string BastionGuard::RootGuard::event_fingerprint ( const Event & event)

Definition at line 209 of file RootGuardEvent.cpp.

210{
211 const auto hash = std::hash<std::string>{}(event.raw_json);
212 std::ostringstream output;
213 output << std::hex << hash;
214 return output.str();
215}

References event_fingerprint().

Referenced by RootGuardPage::dismiss_alert(), RootGuardPage::dismiss_event(), event_fingerprint(), main(), RootGuardPage::queue_new_alerts(), and RootGuardPage::render_incidents().

◆ format_event()

std::string BastionGuard::RootGuard::format_event ( const Event & event)

Definition at line 167 of file RootGuardEvent.cpp.

168{
169 std::ostringstream output;
170 output << '[' << (event.received_at.empty() ? "unknown time" : event.received_at)
171 << "] [" << event.verdict << "] " << event.event
172 << " process=" << event.comm
173 << " pid=" << event.pid
174 << " tgid=" << event.tgid
175 << " ppid=" << event.ppid;
176
177 if (event.old_euid != event.new_euid)
178 output << " euid=" << event.old_euid << "->" << event.new_euid;
179 if (event.old_mode != event.new_mode)
180 output << " mode=" << octal_mode(event.old_mode)
181 << "->" << octal_mode(event.new_mode);
182 if (event.old_uid != event.new_uid || event.old_gid != event.new_gid)
183 output << " owner=" << event.old_uid << ':' << event.old_gid
184 << "->" << event.new_uid << ':' << event.new_gid;
185 if (event.rule_id != 0)
186 output << " rule=" << event.rule_id;
187 if (!event.parent_comm.empty())
188 output << " parent=" << event.parent_comm;
189 if (!event.parent_executable.empty())
190 output << " parent-exe=" << event.parent_executable;
191 if (event.parent_device != 0 || event.parent_inode != 0)
192 output << " parent-identity=" << event.parent_device
193 << ':' << event.parent_inode;
194 if (!event.actor_executable.empty())
195 output << " actor=" << event.actor_executable;
196 if (event.actor_device != 0 || event.actor_inode != 0)
197 output << " actor-identity=" << event.actor_device
198 << ':' << event.actor_inode;
199 if (!event.filename.empty())
200 output << " file=" << event.filename
201 << " path-resolution=" << event.path_resolution;
202 if (event.device != 0 || event.inode != 0)
203 output << " identity=" << event.device << ':' << event.inode;
204
205 output << " reason=0x" << std::hex << event.reason_flags << std::dec;
206 return output.str();
207}

References BastionGuard::RootGuard::Event::actor_device, BastionGuard::RootGuard::Event::actor_executable, BastionGuard::RootGuard::Event::actor_inode, BastionGuard::RootGuard::Event::device, BastionGuard::RootGuard::Event::filename, format_event(), BastionGuard::RootGuard::Event::inode, BastionGuard::RootGuard::Event::new_euid, BastionGuard::RootGuard::Event::new_gid, BastionGuard::RootGuard::Event::new_mode, BastionGuard::RootGuard::Event::new_uid, BastionGuard::RootGuard::Event::old_euid, BastionGuard::RootGuard::Event::old_gid, BastionGuard::RootGuard::Event::old_mode, BastionGuard::RootGuard::Event::old_uid, BastionGuard::RootGuard::Event::parent_comm, BastionGuard::RootGuard::Event::parent_device, BastionGuard::RootGuard::Event::parent_executable, BastionGuard::RootGuard::Event::parent_inode, BastionGuard::RootGuard::Event::received_at, and BastionGuard::RootGuard::Event::rule_id.

Referenced by format_event(), main(), and RootGuardPage::render_events().

◆ is_actionable_incident()

bool BastionGuard::RootGuard::is_actionable_incident ( const Event & event)
noexcept

Definition at line 272 of file RootGuardEvent.cpp.

273{
275}
EventSeverity classify_event(const Event &event) noexcept

References classify_event(), Incident, and is_actionable_incident().

Referenced by is_actionable_incident(), main(), and RootGuardPage::queue_new_alerts().

◆ is_security_observation()

bool BastionGuard::RootGuard::is_security_observation ( const Event & event)
noexcept

◆ is_system_service_path()

bool BastionGuard::RootGuard::is_system_service_path ( const std::string & path)
noexcept

Definition at line 277 of file RootGuardEvent.cpp.

278{
279 if (path.empty())
280 return false;
281 const bool systemd = has_prefix(path, "/etc/systemd/system") ||
282 has_prefix(path, "/usr/lib/systemd/system") ||
283 has_prefix(path, "/lib/systemd/system");
284 const bool initScript = has_prefix(path, "/etc/init.d") ||
285 has_prefix(path, "/etc/conf.d");
286 const bool dinit = has_prefix(path, "/etc/dinit.d") ||
287 has_prefix(path, "/usr/lib/dinit.d");
288 return systemd || initScript || dinit;
289}

References is_system_service_path().

Referenced by anonymous_namespace{RootGuardPage.cpp}::incident_detail(), is_system_service_path(), main(), BastionGuard::RootGuard::Client::run_request(), and RootGuardPage::show_next_alert().

◆ parse_event_json()

std::optional< Event > BastionGuard::RootGuard::parse_event_json ( const std::string & line)

Definition at line 122 of file RootGuardEvent.cpp.

123{
124 Event event;
125 event.raw_json = line;
126
127 const auto event_name = json_string(line, "event");
128 const auto verdict = json_string(line, "verdict");
129 if (!event_name || !verdict)
130 return std::nullopt;
131
132 event.received_at = json_string(line, "received_at").value_or("");
133 event.event = *event_name;
134 event.verdict = *verdict;
135 event.pid = as_u32(json_u64(line, "pid"));
136 event.tgid = as_u32(json_u64(line, "tgid"));
137 event.ppid = as_u32(json_u64(line, "ppid"));
138 event.old_euid = as_u32(json_u64(line, "old_euid"));
139 event.new_euid = as_u32(json_u64(line, "new_euid"));
140 event.rule_id = as_u32(json_u64(line, "rule_id"));
141 event.reason_flags = as_u32(json_u64(line, "reason_flags"));
142 event.lsm_flags = as_i32(json_i64(line, "lsm_flags"));
143 event.auxiliary = as_u32(json_u64(line, "auxiliary"));
144 event.device = json_u64(line, "device").value_or(0);
145 event.inode = json_u64(line, "inode").value_or(0);
146 event.actor_device = json_u64(line, "actor_device").value_or(0);
147 event.actor_inode = json_u64(line, "actor_inode").value_or(0);
148 event.parent_device = json_u64(line, "parent_device").value_or(0);
149 event.parent_inode = json_u64(line, "parent_inode").value_or(0);
150 event.actor_start_boottime_ns =
151 json_u64(line, "actor_start_boottime_ns").value_or(0);
152 event.old_mode = as_u32(json_u64(line, "old_mode"));
153 event.new_mode = as_u32(json_u64(line, "new_mode"));
154 event.old_uid = as_u32(json_u64(line, "old_uid"));
155 event.new_uid = as_u32(json_u64(line, "new_uid"));
156 event.old_gid = as_u32(json_u64(line, "old_gid"));
157 event.new_gid = as_u32(json_u64(line, "new_gid"));
158 event.comm = json_string(line, "comm").value_or("unknown");
159 event.parent_comm = json_string(line, "parent_comm").value_or("");
160 event.actor_executable = json_string(line, "actor_executable").value_or("");
161 event.parent_executable = json_string(line, "parent_executable").value_or("");
162 event.filename = json_string(line, "filename").value_or("");
163 event.path_resolution = json_string(line, "path_resolution").value_or("basename-only");
164 return event;
165}

References parse_event_json(), and BastionGuard::RootGuard::Event::raw_json.

Referenced by main(), parse_event_json(), and BastionGuard::RootGuard::anonymous_namespace{RootGuardClient.cpp}::read_recent_events().