Add AuditEventHandler 30/43730/1
authorAleksander Zdyb <a.zdyb@samsung.com>
Mon, 29 Jun 2015 17:40:33 +0000 (19:40 +0200)
committerAleksander Zdyb <a.zdyb@samsung.com>
Fri, 10 Jul 2015 12:50:28 +0000 (14:50 +0200)
The class dispatches different types of audit event and collects
required properties according to type of event.

Change-Id: I492f93143489acc1bf72d6122b93a5e099c7c631

src/Lad/AuditEventHandler.cpp [new file with mode: 0644]
src/Lad/AuditEventHandler.h [new file with mode: 0644]

diff --git a/src/Lad/AuditEventHandler.cpp b/src/Lad/AuditEventHandler.cpp
new file mode 100644 (file)
index 0000000..537d564
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/**
+ * @file        src/Lad/AuditEventHandler.cpp
+ * @author      Aleksander Zdyb <a.zdyb@samsung.com>
+ * @version     1.0
+ */
+
+#include <functional>
+#include <set>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+
+#include <Log/log.h>
+
+#include "AuditEventHandler.h"
+
+namespace Lad {
+
+const std::string EVTYPE_SYSCALL = "SYSCALL";
+const std::string EVTYPE_AVC = "AVC";
+const std::string EVTYPE_CYNARA = "TRUSTED_APP";
+const std::string EVTYPE_NETFILTER = "NETFILTER_PKT";
+
+const std::string UNKNOWN_PROPERTY = "[unknown]";
+
+typedef void(AuditEventHandler::* EventDispatcherFn)(const Audit::Parser::Event &);
+
+std::unordered_map<std::string, EventDispatcherFn> eventDispatcher = {
+    { EVTYPE_SYSCALL,   &AuditEventHandler::handleSyscall },
+    { EVTYPE_AVC,       &AuditEventHandler::handleAVC },
+    { EVTYPE_CYNARA,    &AuditEventHandler::handleCynara },
+    { EVTYPE_NETFILTER, &AuditEventHandler::handleNetfilter }
+};
+
+class PropertyGetter {
+public:
+    PropertyGetter(const Audit::Parser::Record &rec) : m_rec(rec) {}
+
+    std::string operator()(const std::string &prop) const {
+        const auto &propIter = m_rec.find(prop);
+        if (propIter != m_rec.end())
+            return propIter->second;
+        else
+            return UNKNOWN_PROPERTY;
+    }
+
+private:
+    const Audit::Parser::Record &m_rec;
+};
+
+void AuditEventHandler::handleEvent(const Audit::Parser::Event &event) {
+
+    std::string eventType;
+    for (const auto &rec : event) {
+        const auto typeIter = rec.find("type");
+        if (typeIter == rec.end())
+            continue;
+        const auto &recType = typeIter->second;
+        const auto disp = eventDispatcher.find(recType);
+        if (disp != eventDispatcher.end()) {
+            auto fun = disp->second;
+            (this->*fun)(event);
+        }
+        break;
+    }
+}
+
+void AuditEventHandler::handleSyscall(const Audit::Parser::Event &event) {
+    auto syscall = UNKNOWN_PROPERTY;
+    auto exit = UNKNOWN_PROPERTY;
+    auto filename = UNKNOWN_PROPERTY;
+    auto objGid = UNKNOWN_PROPERTY;
+    auto objLabel = UNKNOWN_PROPERTY;
+    auto subjLabel = UNKNOWN_PROPERTY;
+
+    for (const auto &rec : event) {
+        const auto typeIter = rec.find("type");
+        if (typeIter == rec.end()) {
+            LOGW("Malformed record in SYSCALL event");
+            continue;
+        }
+
+        PropertyGetter props(rec);
+        const auto &recType = typeIter->second;
+        if (recType == "SYSCALL") {
+            syscall = props("syscall");
+            subjLabel = props("subj");
+            exit = props("exit");
+        } else if (recType == "PATH") {
+            auto nameType = props("nametype");
+            if (nameType == "NORMAL") {
+                filename = props("name");
+                objGid = props("ogid");
+                objLabel = props("obj");
+            }
+        }
+    }
+
+    std::stringstream ss;
+    ss << "ACCESS DENIED ON SYSCALL syscall=" << syscall << " filename=" << filename
+       << " exit=" << exit << " gid=" << objGid << " object=" << objLabel
+       << " subject=" << subjLabel;
+
+    onLogDenial(ss.str());
+}
+
+// TODO: Sometimes Smack event comes with AVC and PATH records
+//       -- have to investigate need to check on PATH
+void AuditEventHandler::handleAVC(const Audit::Parser::Event &event) {
+    auto objLabel = UNKNOWN_PROPERTY;
+    auto subjLabel = UNKNOWN_PROPERTY;
+    auto accessReq = UNKNOWN_PROPERTY;
+
+    for (const auto &rec : event) {
+        const auto typeIter = rec.find("type");
+        if (typeIter == rec.end()) {
+            LOGW("Malformed record in AVC event");
+            continue;
+        }
+
+        PropertyGetter props(rec);
+        const auto &recType = typeIter->second;
+        if (recType == "AVC") {
+            if (props("lsm") == "SMACK" && props("action") == "denied") {
+                subjLabel = props("subject");
+                objLabel = props("object");
+                accessReq = props("requested");
+            } else {
+                return;
+            }
+        }
+    }
+
+    std::stringstream ss;
+    ss << "ACCESS DENIED ON SMACK object=" << objLabel << " subject=" << subjLabel
+       << " access=" << accessReq;
+    onLogDenial(ss.str());
+}
+
+void AuditEventHandler::handleCynara(const Audit::Parser::Event &event) {
+    auto client = UNKNOWN_PROPERTY;
+    auto user = UNKNOWN_PROPERTY;
+    auto privilege = UNKNOWN_PROPERTY;
+
+    for (const auto &rec : event) {
+        const auto typeIter = rec.find("type");
+        if (typeIter == rec.end()) {
+            LOGW("Malformed record in TRUSTED_APP event");
+            continue;
+        }
+
+        PropertyGetter props(rec);
+        const auto &recType = typeIter->second;
+        if (recType == "TRUSTED_APP") {
+            // Interested only in denials
+            if (props("app") != "Cynara" || props("policy_type") != "0") {
+                continue;
+            }
+
+            client = props("client");
+            user = props("user");
+            privilege = props("privilege");
+        }
+    }
+
+    std::stringstream ss;
+    ss << "ACCESS DENIED ON CYNARA client=" << client << " user=" << user
+       << " privilege=" << privilege;
+    onLogDenial(ss.str());
+}
+
+void AuditEventHandler::handleNetfilter(const Audit::Parser::Event &event) {
+    auto obj = UNKNOWN_PROPERTY;
+    auto outif = UNKNOWN_PROPERTY;
+    auto proto = UNKNOWN_PROPERTY;
+    auto saddr = UNKNOWN_PROPERTY;
+    auto sport = UNKNOWN_PROPERTY;
+    auto daddr = UNKNOWN_PROPERTY;
+    auto dport = UNKNOWN_PROPERTY;
+
+    for (const auto &rec : event) {
+        const auto typeIter = rec.find("type");
+        if (typeIter == rec.end()) {
+            LOGW("Malformed record in NETFILTER_PKT event");
+            continue;
+        }
+
+        PropertyGetter props(rec);
+        const auto &recType = typeIter->second;
+        if (recType == "NETFILTER_PKT") {
+            if (props("action") != "2") { // Interested only in denials
+                continue;
+            }
+
+            obj = props("obj");
+            outif = props("outif");
+            proto = props("proto");
+            saddr = props("saddr");
+            sport = props("sport");
+            daddr = props("daddr");
+            dport = props("dport");
+        }
+    }
+
+    std::stringstream ss;
+    ss << "ACCESS DENIED ON NETFILTER"
+       << " obj=" << obj << " outif=" << outif << " proto=" << proto
+       << " saddr=" << saddr << " sport=" << sport
+       << " daddr=" << daddr << " dport=" << dport;
+    onLogDenial(ss.str());
+}
+
+} /* namespace Lad */
diff --git a/src/Lad/AuditEventHandler.h b/src/Lad/AuditEventHandler.h
new file mode 100644 (file)
index 0000000..d0f9dd6
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/**
+ * @file        src/Lad/AuditEventHandler.h
+ * @author      Aleksander Zdyb <a.zdyb@samsung.com>
+ * @version     1.0
+ */
+
+#ifndef SRC_AUDITEVENTHANDLER_H
+#define SRC_AUDITEVENTHANDLER_H
+
+#include <string>
+
+#include <boost/signals2.hpp>
+
+#include <Audit/Parser.h>
+
+namespace Lad {
+
+class AuditEventHandler {
+public:
+       AuditEventHandler() = default;
+       virtual ~AuditEventHandler() = default;
+
+       // TODO: Consider using std::function as member, if the application stays single-threaded
+       boost::signals2::signal<void(const std::string &)> onLogDenial;
+
+       void handleEvent(const Audit::Parser::Event &event);
+
+       void handleSyscall(const Audit::Parser::Event &event);
+       void handleAVC(const Audit::Parser::Event &event);
+       void handleCynara(const Audit::Parser::Event &event);
+       void handleNetfilter(const Audit::Parser::Event &event);
+};
+
+} /* namespace Lad */
+
+#endif /* SRC_AUDITEVENTHANDLER_H */