inline void updateAuditRow(const AuditEventContextRef& ec, Row& r) { const auto& fields = ec->fields; if (ec->type == AUDIT_SYSCALL) { r["pid"] = (fields.count("pid")) ? fields.at("pid") : "0"; r["parent"] = fields.count("ppid") ? fields.at("ppid") : "0"; r["uid"] = fields.count("uid") ? fields.at("uid") : "0"; r["euid"] = fields.count("euid") ? fields.at("euid") : "0"; r["gid"] = fields.count("gid") ? fields.at("gid") : "0"; r["egid"] = fields.count("egid") ? fields.at("euid") : "0"; r["path"] = (fields.count("exe")) ? decodeAuditValue(fields.at("exe")) : ""; // This should get overwritten during the EXECVE state. r["cmdline"] = (fields.count("comm")) ? fields.at("comm") : ""; // Do not record a cmdline size. If the final state is reached and no 'argc' // has been filled in then the EXECVE state was not used. r["cmdline_size"] = ""; r["overflows"] = ""; r["env_size"] = "0"; r["env_count"] = "0"; r["env"] = ""; } if (ec->type == AUDIT_EXECVE) { // Reset the temporary storage from the SYSCALL state. r["cmdline"] = ""; for (const auto& arg : fields) { if (arg.first == "argc") { continue; } // Amalgamate all the "arg*" fields. if (r.at("cmdline").size() > 0) { r["cmdline"] += " "; } r["cmdline"] += decodeAuditValue(arg.second); } // There may be a better way to calculate actual size from audit. // Then an overflow could be calculated/determined based on actual/expected. r["cmdline_size"] = std::to_string(r.at("cmdline").size()); } if (ec->type == AUDIT_PATH) { r["mode"] = (fields.count("mode")) ? fields.at("mode") : ""; r["owner_uid"] = fields.count("ouid") ? fields.at("ouid") : "0"; r["owner_gid"] = fields.count("ogid") ? fields.at("ogid") : "0"; auto qd = SQL::selectAllFrom("file", "path", EQUALS, r.at("path")); if (qd.size() == 1) { r["ctime"] = qd.front().at("ctime"); r["atime"] = qd.front().at("atime"); r["mtime"] = qd.front().at("mtime"); r["btime"] = "0"; } // Uptime is helpful for execution-based events. r["uptime"] = std::to_string(tables::getUptime()); } }
TEST_F(AuditTests, test_audit_value_decode) { // In the normal case the decoding only removes '"' characters from the ends. auto decoded_normal = decodeAuditValue("\"/bin/ls\""); EXPECT_EQ(decoded_normal, "/bin/ls"); // If the first char is not '"', the value is expected to be hex-encoded. auto decoded_hex = decodeAuditValue("736C6565702031"); EXPECT_EQ(decoded_hex, "sleep 1"); // When the hex fails to decode the input value is returned as the result. auto decoded_fail = decodeAuditValue("7"); EXPECT_EQ(decoded_fail, "7"); }
Status ProcessEventSubscriber::Callback(const ECRef& ec, const SCRef& sc) { // Check and set the valid state change. // If this is an unacceptable change reset the state and clear row data. if (ec->fields.count("success") && ec->fields.at("success") == "no") { return Status(0, "OK"); } if (!validAuditState(ec->type, state_).ok()) { state_ = STATE_SYSCALL; Row().swap(row_); return Status(0, "OK"); } // Fill in row fields based on the event state. updateAuditRow(ec, row_); // Only add the event if finished (aka a PATH event was emitted). if (state_ == STATE_SYSCALL) { // If the EXECVE state was not used, decode the cmdline value. if (row_.at("cmdline_size").size() == 0) { // This allows at most 1 decode call per potentially-encoded item. row_["cmdline"] = decodeAuditValue(row_.at("cmdline")); row_["cmdline_size"] = "1"; } add(row_, getUnixTime()); Row().swap(row_); } return Status(0, "OK"); }
bool SocketUpdate(size_t type, const AuditFields& fields, AuditFields& r) { if (type == AUDIT_TYPE_SOCKADDR) { const auto& saddr = fields.at("saddr"); if (saddr.size() < 4 || saddr[0] == '1') { return false; } r["protocol"] = '0'; r["local_port"] = '0'; r["remote_port"] = '0'; // Parse the struct and emit the row. if (!parseSockAddr(saddr, r)) { return false; } return true; } r["auid"] = fields.at("auid"); r["pid"] = fields.at("pid"); r["path"] = decodeAuditValue(fields.at("exe")); // TODO: This is a hex value. r["fd"] = fields.at("a0"); // The open/bind success status. r["success"] = (fields.at("success") == "yes") ? "1" : "0"; r["uptime"] = std::to_string(tables::getUptime()); return true; }