Skip to content
API Documentation
BastionGuard™
JsonEventSink.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <chrono>
5#include <iomanip>
6#include <sstream>
7#include <stdexcept>
8
10namespace {
11
12const char* eventName(const __u32 type) noexcept
13{
14 switch (type) {
15 case RG_EVENT_SETUID: return "setuid";
16 case RG_EVENT_EXEC_PRIV: return "exec-priv";
17 case RG_EVENT_CREDENTIAL_ANOMALY: return "credential-anomaly";
18 case RG_EVENT_PERMISSION_CHANGE: return "permission-change";
19 case RG_EVENT_OWNER_CHANGE: return "owner-change";
20 case RG_EVENT_XATTR_CHANGE: return "xattr-change";
21 case RG_EVENT_ACL_CHANGE: return "acl-change";
22 case RG_EVENT_PROTECTED_UNLINK: return "protected-unlink";
23 case RG_EVENT_PROTECTED_RENAME: return "protected-rename";
24 case RG_EVENT_PROTECTED_HARDLINK: return "protected-hardlink";
25 case RG_EVENT_INTEGRITY_DRIFT: return "integrity-drift";
26 case RG_EVENT_INTEGRITY_RESTORED: return "integrity-restored";
27 case RG_EVENT_SERVICE_BLOCKED: return "service-blocked";
28 case RG_EVENT_FILE_RESTORED: return "file-restored";
29 case RG_EVENT_FILE_QUARANTINED: return "file-quarantined";
30 case RG_EVENT_PROTECTION_MODE_CHANGED: return "protection-mode-changed";
31 default: return "unknown";
32 }
33}
34
35const char* verdictName(const __u32 verdict) noexcept
36{
37 switch (verdict) {
38 case RG_VERDICT_AUDIT: return "audit";
39 case RG_VERDICT_AUTHORIZED: return "authorized";
40 case RG_VERDICT_BLOCKED: return "blocked";
41 case RG_VERDICT_TRUSTED: return "trusted";
42 case RG_VERDICT_ALERT: return "alert";
43 case RG_VERDICT_RESTORED: return "restored";
44 default: return "unknown";
45 }
46}
47
48const char* pathResolutionName(const __u32 value) noexcept
49{
50 switch (value) {
51 case RG_PATH_PROTECTED_BASELINE: return "protected-baseline";
52 case RG_PATH_PROC_FD: return "proc-fd";
53 case RG_PATH_PROCESS_CWD: return "process-cwd";
54 case RG_PATH_KERNEL_EXACT: return "kernel-exact";
55 case RG_PATH_LSM_EXACT: return "lsm-exact";
56 default: return "basename-only";
57 }
58}
59
60std::string receivedAtUtc()
61{
62 const auto now = std::chrono::system_clock::now();
63 const auto time = std::chrono::system_clock::to_time_t(now);
64 std::tm tm {};
65 gmtime_r(&time, &tm);
66 std::ostringstream output;
67 output << std::put_time(&tm, "%Y-%m-%dT%H:%M:%SZ");
68 return output.str();
69}
70
71} // namespace
72
73JsonEventSink::JsonEventSink(const std::filesystem::path& path)
74 : stream_(path, std::ios::app)
75{
76 if (!stream_)
77 throw std::runtime_error("impossibile aprire il log JSON: " + path.string());
78}
79
80std::string JsonEventSink::escape(const char* value)
81{
82 std::ostringstream output;
83 for (const unsigned char character : std::string(value ? value : "")) {
84 switch (character) {
85 case '"': output << "\\\""; break;
86 case '\\': output << "\\\\"; break;
87 case '\b': output << "\\b"; break;
88 case '\f': output << "\\f"; break;
89 case '\n': output << "\\n"; break;
90 case '\r': output << "\\r"; break;
91 case '\t': output << "\\t"; break;
92 default:
93 if (character < 0x20)
94 output << "\\u" << std::hex << std::setw(4) << std::setfill('0')
95 << static_cast<unsigned int>(character) << std::dec;
96 else
97 output << static_cast<char>(character);
98 }
99 }
100 return output.str();
101}
102
103void JsonEventSink::onEvent(const rg_event& event) noexcept
104{
105 try {
106 std::lock_guard lock(mutex_);
107 stream_ << '{'
108 << "\"received_at\":\"" << receivedAtUtc() << "\","
109 << "\"kernel_monotonic_ns\":" << event.timestamp_ns << ','
110 << "\"event\":\"" << eventName(event.event_type) << "\","
111 << "\"verdict\":\"" << verdictName(event.verdict) << "\","
112 << "\"pid\":" << event.pid << ','
113 << "\"tgid\":" << event.tgid << ','
114 << "\"ppid\":" << event.ppid << ','
115 << "\"old_euid\":" << event.old_euid << ','
116 << "\"new_euid\":" << event.new_euid << ','
117 << "\"rule_id\":" << event.rule_id << ','
118 << "\"reason_flags\":" << event.reason_flags << ','
119 << "\"lsm_flags\":" << event.lsm_flags << ','
120 << "\"auxiliary\":" << event.auxiliary << ','
121 << "\"path_resolution\":\"" << pathResolutionName(event.path_resolution) << "\","
122 << "\"device\":" << event.file.device << ','
123 << "\"inode\":" << event.file.inode << ','
124 << "\"actor_device\":" << event.actor_file.device << ','
125 << "\"actor_inode\":" << event.actor_file.inode << ','
126 << "\"parent_device\":" << event.parent_file.device << ','
127 << "\"parent_inode\":" << event.parent_file.inode << ','
128 << "\"actor_start_boottime_ns\":" << event.actor_start_boottime_ns << ','
129 << "\"old_mode\":" << event.old_mode << ','
130 << "\"new_mode\":" << event.new_mode << ','
131 << "\"old_uid\":" << event.old_uid << ','
132 << "\"new_uid\":" << event.new_uid << ','
133 << "\"old_gid\":" << event.old_gid << ','
134 << "\"new_gid\":" << event.new_gid << ','
135 << "\"comm\":\"" << escape(event.comm) << "\","
136 << "\"parent_comm\":\"" << escape(event.parent_comm) << "\","
137 << "\"actor_executable\":\"" << escape(event.actor_executable) << "\","
138 << "\"parent_executable\":\"" << escape(event.parent_executable) << "\","
139 << "\"filename\":\"" << escape(event.filename) << "\","
140 << "\"xattr_name\":\"" << escape(event.xattr_name) << "\""
141 << "}\n";
142 stream_.flush();
143 } catch (...) {
144 // Logging must never crash the security engine.
145 }
146}
147
148} // namespace bastionguard::rootguard
JsonEventSink(const std::filesystem::path &path)
void onEvent(const rg_event &event) noexcept override
static std::string escape(const char *value)
const char * verdictName(const __u32 verdict) noexcept
const char * pathResolutionName(const __u32 value) noexcept
@ RG_EVENT_PROTECTED_RENAME
@ RG_EVENT_FILE_QUARANTINED
@ RG_EVENT_EXEC_PRIV
@ RG_EVENT_OWNER_CHANGE
@ RG_EVENT_ACL_CHANGE
@ RG_EVENT_PROTECTED_UNLINK
@ RG_EVENT_SETUID
@ RG_EVENT_SERVICE_BLOCKED
@ RG_EVENT_INTEGRITY_RESTORED
@ RG_EVENT_INTEGRITY_DRIFT
@ RG_EVENT_PROTECTED_HARDLINK
@ RG_EVENT_CREDENTIAL_ANOMALY
@ RG_EVENT_PROTECTION_MODE_CHANGED
@ RG_EVENT_XATTR_CHANGE
@ RG_EVENT_PERMISSION_CHANGE
@ RG_EVENT_FILE_RESTORED
@ RG_PATH_LSM_EXACT
@ RG_PATH_PROCESS_CWD
@ RG_PATH_PROC_FD
@ RG_PATH_PROTECTED_BASELINE
@ RG_PATH_KERNEL_EXACT
@ RG_VERDICT_TRUSTED
@ RG_VERDICT_ALERT
@ RG_VERDICT_AUDIT
@ RG_VERDICT_RESTORED
@ RG_VERDICT_AUTHORIZED
@ RG_VERDICT_BLOCKED