Move clasees for audit subsystem from klay git 02/163902/1
authorSungbae Yoo <sungbae.yoo@samsung.com>
Thu, 14 Dec 2017 03:12:08 +0000 (12:12 +0900)
committerSungbae Yoo <sungbae.yoo@samsung.com>
Thu, 14 Dec 2017 03:13:00 +0000 (12:13 +0900)
Change-Id: Ibfffdd27a1a9d6dc629466f4a49bc346843dfdc7
Signed-off-by: Sungbae Yoo <sungbae.yoo@samsung.com>
server/CMakeLists.txt
server/audit/audit-rule.cpp [new file with mode: 0644]
server/audit/audit-rule.h [new file with mode: 0644]
server/audit/audit.cpp [new file with mode: 0644]
server/audit/audit.h [new file with mode: 0644]
server/discretionary-access-control.cpp
server/server.h
server/system-call.cpp

index d87a4951bf64f282aaf47a3be05a1f0151d4cb22..c42100aa3cfadb59c0fb25bdce649497f43fafb6 100644 (file)
@@ -19,6 +19,8 @@ SET(SERVER_SRCS       main.cpp
                                system-call.cpp
                                mandatory-access-control.cpp
                                discretionary-access-control.cpp
+                               audit/audit.cpp
+                               audit/audit-rule.cpp
 )
 
 SET(DEPENDENCY klay
diff --git a/server/audit/audit-rule.cpp b/server/audit/audit-rule.cpp
new file mode 100644 (file)
index 0000000..356a758
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ *  Copyright (c) 2017 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
+ */
+#include <klay/error.h>
+#include <klay/exception.h>
+
+#include "audit-rule.h"
+
+namespace netlink {
+
+namespace {
+
+bool isStringValueRequired(unsigned int field) {
+       switch (field) {
+       case AUDIT_OBJ_USER:
+       case AUDIT_OBJ_ROLE:
+       case AUDIT_OBJ_TYPE:
+       case AUDIT_OBJ_LEV_LOW:
+       case AUDIT_OBJ_LEV_HIGH:
+       case AUDIT_WATCH:
+       case AUDIT_DIR:
+       case AUDIT_SUBJ_USER:
+       case AUDIT_SUBJ_ROLE:
+       case AUDIT_SUBJ_TYPE:
+       case AUDIT_SUBJ_SEN:
+       case AUDIT_SUBJ_CLR:
+       case AUDIT_FILTERKEY:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+
+} // namespace
+
+AuditRule::AuditRule() :
+       buf(sizeof(struct audit_rule_data))
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       r->flags = AUDIT_FILTER_EXIT;
+       r->action = AUDIT_ALWAYS;
+}
+
+AuditRule::AuditRule(std::vector<char> &buf) :
+       buf(buf)
+{
+}
+
+AuditRule::~AuditRule()
+{
+}
+
+void AuditRule::setSystemCall(unsigned int syscall)
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       r->mask[syscall / 32] |= 1 << (syscall % 32);
+}
+
+void AuditRule::unsetSystemCall(unsigned int syscall)
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       r->mask[syscall / 32] &= ~(1 << (syscall % 32));
+}
+
+void AuditRule::setAllSystemCalls()
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       for (auto &m : r->mask) {
+               m = 0xffffffff;
+       }
+}
+
+void AuditRule::clearAllSystemCalls()
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       for (auto &m : r->mask) {
+               m = 0;
+       }
+}
+
+std::vector<unsigned int> AuditRule::getSystemCalls() const
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       std::vector<unsigned int> ret;
+
+       for (int i = 0; i < AUDIT_BITMASK_SIZE; i++) {
+               for (int j = 0, k = 1; j < 32; j++, k <<= 1) {
+                       if (r->mask[i] & k) {
+                               ret.push_back(i << 5 | j);
+                       }
+               }
+       }
+       return ret;
+}
+
+void AuditRule::addCondition(const Condition<int> &cond)
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       unsigned int i = r->field_count;
+
+       if (isStringValueRequired(cond.field))
+               throw runtime::Exception("This field requires string value");
+
+       if (i >= AUDIT_MAX_FIELDS)
+               throw runtime::Exception("This rule condition is full");
+
+       r->fields[i] = cond.field;
+       r->fieldflags[i] = cond.op;
+       r->values[i] = (unsigned int)cond.value;
+
+       r->field_count++;
+}
+
+void AuditRule::removeCondition(const Condition<int> &cond)
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       unsigned int i;
+
+       if (isStringValueRequired(cond.field))
+               throw runtime::Exception("This field requires string value");
+
+       for (i = 0; i < r->field_count; i++) {
+               if (r->fields[i] == cond.field &&
+                       r->fieldflags[i] == cond.op &&
+                       r->values[i] == (unsigned int)cond.value) {
+                       break;
+               }
+       }
+
+       if (i == r->field_count)
+               throw runtime::Exception("This condition doesn't exist");
+
+       std::move(&r->values[i + 1], &r->values[r->field_count], &r->values[i]);
+       std::move(&r->fields[i + 1], &r->fields[r->field_count], &r->fields[i]);
+       std::move(&r->fieldflags[i + 1], &r->fieldflags[r->field_count], &r->fieldflags[i]);
+
+       r->field_count--;
+
+       r->values[r->field_count] = 0;
+       r->fields[r->field_count] = 0;
+       r->fieldflags[r->field_count] = 0;
+}
+
+void AuditRule::addCondition(const Condition<std::string> &cond)
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       unsigned int i = r->field_count;
+
+       if (!isStringValueRequired(cond.field))
+               throw runtime::Exception("This field requires integer value");
+
+       if (i >= AUDIT_MAX_FIELDS)
+               throw runtime::Exception("Audit rule condition is full");
+
+       r->fields[i] = cond.field;
+       r->fieldflags[i] = cond.op;
+       r->values[i] = cond.value.size();
+
+       buf.resize(sizeof(struct audit_rule_data) + r->buflen + r->values[i]);
+       r = (struct audit_rule_data *)buf.data();
+       std::copy(cond.value.begin(), cond.value.end(), r->buf + r->buflen);
+       r->buflen += r->values[i];
+
+       r->field_count++;
+}
+
+void AuditRule::removeCondition(const Condition<std::string> &cond)
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       unsigned int i;
+       char * bufdata = r->buf;
+
+       if (!isStringValueRequired(cond.field))
+               throw runtime::Exception("This field requires integer value");
+
+       for (i = 0; i < r->field_count; i++) {
+               if (r->fields[i] == cond.field &&
+                       r->fieldflags[i] == cond.op &&
+                       std::string(bufdata, bufdata + r->values[i] + 1) == cond.value) {
+                       break;
+               }
+               if (isStringValueRequired(r->fields[i]))
+                       bufdata += r->values[i];
+       }
+
+       if (i == r->field_count)
+               throw runtime::Exception("This condition doesn't exist");
+
+       std::copy(bufdata + r->values[i] + 1, &r->buf[r->buflen], bufdata);
+       r->buflen -= r->values[i];
+
+       std::move(&r->values[i + 1], &r->values[r->field_count], &r->values[i]);
+       std::move(&r->fields[i + 1], &r->fields[r->field_count], &r->fields[i]);
+       std::move(&r->fieldflags[i + 1], &r->fieldflags[r->field_count], &r->fieldflags[i]);
+
+       r->field_count--;
+
+       r->values[r->field_count] = 0;
+       r->fields[r->field_count] = 0;
+       r->fieldflags[r->field_count] = 0;
+
+       buf.resize(sizeof(struct audit_rule_data) + r->buflen);
+}
+
+template <>
+std::vector<AuditRule::Condition<int>> AuditRule::getConditions() const
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       std::vector<Condition<int>> ret;
+
+       for (unsigned int i = 0; i < r->field_count; i++)
+               if (!isStringValueRequired(r->fields[i]))
+                       ret.push_back(AuditRule::Condition<int>(r->fields[i],
+                                                                                       r->fieldflags[i], r->values[i]));
+
+       return ret;
+}
+
+template <>
+std::vector<AuditRule::Condition<std::string>> AuditRule::getConditions() const
+{
+       auto r = (struct audit_rule_data *)buf.data();
+       std::vector<Condition<std::string>> ret;
+       char * buf = r->buf;
+
+       for (unsigned int i = 0; i < r->field_count; i++) {
+               if (isStringValueRequired(r->fields[i])) {
+                       ret.push_back(AuditRule::Condition<std::string>(r->fields[i],
+                               r->fieldflags[i], std::string(buf, buf + r->values[i] + 1)));
+                       buf += r->values[i];
+               }
+       }
+       return ret;
+}
+
+
+} // namespace runtime
diff --git a/server/audit/audit-rule.h b/server/audit/audit-rule.h
new file mode 100644 (file)
index 0000000..c08d5b3
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2017 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
+ */
+
+#ifndef __RUNTIME_NETLINK_AUDIT_RULE_H__
+#define __RUNTIME_NETLINK_AUDIT_RULE_H__
+
+#include <vector>
+#include <string>
+
+#include <linux/audit.h>
+
+#include <klay/klay.h>
+
+namespace netlink {
+
+class KLAY_EXPORT AuditRule final {
+public:
+       template <typename T>
+       struct Condition {
+               unsigned int field, op;
+               T value;
+
+               Condition(unsigned int field, unsigned int op, T value)
+               : field(field), op(op), value(value)
+               {
+               }
+       };
+
+       AuditRule();
+       AuditRule(std::vector<char>& buf);
+       ~AuditRule();
+
+       void setSystemCall(unsigned int syscall);
+       void unsetSystemCall(unsigned int syscall);
+       void setAllSystemCalls();
+       void clearAllSystemCalls();
+       std::vector<unsigned int> getSystemCalls() const;
+
+       void addCondition(const Condition<int> &cond);
+       void removeCondition(const Condition<int> &cond);
+
+       void addCondition(const Condition<std::string> &cond);
+       void removeCondition(const Condition<std::string> &cond);
+
+       template <typename T>
+       std::vector<Condition<T>> getConditions() const;
+
+       const char *data() const
+       {
+               return buf.data();
+       }
+
+       unsigned int size() const
+       {
+               return buf.size();
+       }
+
+private:
+       std::vector<char> buf;
+};
+
+template <>
+std::vector<AuditRule::Condition<int>> AuditRule::getConditions() const;
+
+template <>
+std::vector<AuditRule::Condition<std::string>> AuditRule::getConditions() const;
+
+} // namespace runtime
+
+#endif //!__RUNTIME_NETLINK_AUDIT_RULE_H__
diff --git a/server/audit/audit.cpp b/server/audit/audit.cpp
new file mode 100644 (file)
index 0000000..9558557
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ *  Copyright (c) 2017 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
+ */
+#include <poll.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include <cstring>
+
+#include <klay/error.h>
+#include <klay/exception.h>
+
+#include "audit.h"
+
+using namespace std::placeholders;
+
+namespace netlink {
+
+Audit::Audit() :
+       nl(NETLINK_AUDIT), sequence(0), mainloop(nullptr)
+{
+}
+
+Audit::Audit(Audit&& audit) :
+       nl(std::move(audit.nl)), sequence(audit.sequence), mainloop(audit.mainloop)
+{
+}
+
+Audit::~Audit()
+{
+}
+
+void Audit::setPID(pid_t pid)
+{
+       struct audit_status s;
+
+       ::memset(&s, 0, sizeof(s));
+       s.mask  = AUDIT_STATUS_PID;
+       s.pid   = pid;
+
+       send(AUDIT_SET, &s, sizeof(s));
+}
+
+void Audit::setEnabled(int enabled)
+{
+       struct audit_status s;
+
+       ::memset(&s, 0, sizeof(s));
+       s.mask          = AUDIT_STATUS_ENABLED;
+       s.enabled       = enabled;
+
+       send(AUDIT_SET, &s, sizeof(s));
+}
+
+int Audit::isEnabled()
+{
+       int ret = 0;
+       send(AUDIT_GET, NULL, 0);
+
+       while (1) {
+               auto msg = recv();
+
+               switch (msg.first) {
+               case NLMSG_DONE:
+               case NLMSG_ERROR:
+                       throw runtime::Exception("Failed to get audit state");
+               case AUDIT_GET:
+                       ret = ((struct audit_status*)msg.second.data())->enabled;
+                       break;
+               default:
+                       continue;
+               }
+
+               break;
+       }
+
+       return ret;
+}
+
+std::vector<AuditRule> Audit::getRules()
+{
+       std::vector<AuditRule> ret;
+
+       send(AUDIT_LIST_RULES, NULL, 0);
+
+       while (1) {
+               auto msg = recv();
+
+               switch (msg.first) {
+               case NLMSG_DONE:
+                       break;
+               case NLMSG_ERROR:
+                       throw runtime::Exception("Failed to get a list of audit rules");
+               case AUDIT_LIST_RULES:
+                       ret.push_back(msg.second);
+               default:
+                       continue;
+               }
+
+               break;
+       }
+       return ret;
+}
+
+void Audit::addRule(const AuditRule& rule)
+{
+       send(AUDIT_ADD_RULE, rule.data(), rule.size());
+}
+
+void Audit::removeRule(const AuditRule& rule)
+{
+       send(AUDIT_DEL_RULE, rule.data(), rule.size());
+}
+
+void Audit::setMainloop(runtime::Mainloop *ml)
+{
+       int fd = nl.getFd();
+
+       if (mainloop != nullptr) {
+               mainloop->removeEventSource(fd);
+       }
+       mainloop = ml;
+       mainloop->addEventSource(fd, POLLIN, std::bind(&Audit::processMessage,
+                                                                                                       this, _1, _2));
+}
+
+void Audit::setMessageHandler(MessageHandler&& handler)
+{
+       messageHandler = handler;
+}
+
+void Audit::send(int type, const void *data, unsigned int size)
+{
+       char buf[NLMSG_SPACE(size)];
+       auto *nlh = (struct nlmsghdr *)buf;
+
+       ::memset(buf, 0, sizeof(buf));
+
+       nlh->nlmsg_len = sizeof(buf);
+       nlh->nlmsg_type = type;
+       nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       nlh->nlmsg_seq = ++sequence;
+
+       if (sequence == 0) {
+               sequence++;
+       }
+
+       if (size && data) {
+               ::memcpy(NLMSG_DATA(buf), data, size);
+       }
+
+       nl.send(buf, sizeof(buf));
+
+       if (recv(MSG_PEEK).first == NLMSG_ERROR) {
+               auto reply = recv().second;
+               auto err = (struct nlmsgerr*)reply.data();
+               if (err->error) {
+                       throw runtime::Exception("Audit netlink error: " +
+                                                                               std::to_string(err->error));
+               }
+       }
+}
+
+Audit::Message Audit::recv(int options)
+{
+       struct nlmsghdr nlh;
+
+       processMessage(nl.getFd(), POLLIN);
+
+       //To get message size
+       nl.recv(&nlh, sizeof(nlh), options | MSG_PEEK);
+
+       char buf[nlh.nlmsg_len + NLMSG_HDRLEN];
+       nl.recv(buf, sizeof(buf), options);
+
+       Message msg = {nlh.nlmsg_type, std::vector<char>(nlh.nlmsg_len)};
+
+       ::memcpy(msg.second.data(), NLMSG_DATA(buf), msg.second.size());
+       return msg;
+}
+
+void Audit::processMessage(int fd, runtime::Mainloop::Event event)
+{
+       struct nlmsghdr nlh;
+
+       nl.recv(&nlh, sizeof(nlh), MSG_PEEK);
+
+       while (nlh.nlmsg_seq == 0) {
+               char buf[nlh.nlmsg_len + NLMSG_HDRLEN];
+               nl.recv(buf, sizeof(buf));
+
+               Message msg = {nlh.nlmsg_type, std::vector<char>(nlh.nlmsg_len)};
+
+               ::memcpy(msg.second.data(), NLMSG_DATA(buf), msg.second.size());
+               if (messageHandler) {
+                       messageHandler(msg);
+               }
+
+               try {
+                       nl.recv(&nlh, sizeof(nlh), MSG_PEEK | MSG_DONTWAIT);
+               } catch (runtime::Exception &e) {
+                       break;
+               }
+       }
+}
+
+} // namespace runtime
diff --git a/server/audit/audit.h b/server/audit/audit.h
new file mode 100644 (file)
index 0000000..cbd6aa0
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2017 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
+ */
+
+#ifndef __RUNTIME_NETLINK_AUDIT_H__
+#define __RUNTIME_NETLINK_AUDIT_H__
+
+#include <list>
+#include <vector>
+
+#include <linux/audit.h>
+
+#include <klay/klay.h>
+#include <klay/mainloop.h>
+#include <klay/netlink/netlink.h>
+
+#include "audit/audit-rule.h"
+
+namespace netlink {
+
+class KLAY_EXPORT Audit final {
+public:
+       typedef std::pair<int, std::vector<char>> Message;
+       typedef std::function<void(Message&)> MessageHandler;
+
+       Audit();
+       Audit(Audit&&);
+       Audit(const Audit&) = delete;
+       ~Audit();
+
+       Audit& operator=(const Audit&) = delete;
+
+       void setPID(pid_t pid);
+       void setEnabled(int enabled);
+       int isEnabled();
+
+       std::vector<AuditRule> getRules();
+       void addRule(const AuditRule& rule);
+       void removeRule(const AuditRule& rule);
+
+       void setMainloop(runtime::Mainloop *ml);
+       void setMessageHandler(MessageHandler&& handler);
+
+private:
+       void send(int type, const void *data, unsigned int size);
+       Message recv(int options = 0);
+
+       void processMessage(int fd, runtime::Mainloop::Event event);
+
+       Netlink nl;
+       unsigned int sequence = 0;
+       runtime::Mainloop *mainloop;
+       MessageHandler messageHandler;
+};
+
+} // namespace runtime
+
+#endif //!__RUNTIME_NETLINK_AUDIT_H__
index 00549cd261ef1774abb1372f928af64b07243f9e..cb70cbc89a3d6c8cfbb20816a8fb5892822ae910 100644 (file)
@@ -101,7 +101,7 @@ DiscretionaryAccessControl::DiscretionaryAccessControl(AuditTrailControlContext
 
        context.createNotification("DiscretionaryAccessControl");
 
-       ruleDacAccess.setKey(AUDIT_RULE_KEY);
+       ruleDacAccess.addCondition({AUDIT_FILTERKEY, AUDIT_EQUAL, AUDIT_RULE_KEY});
 
        //Both EACCESS and EPERM
        ruleDacAccess.setSystemCall(__NR_execve);
@@ -213,11 +213,11 @@ DiscretionaryAccessControl::DiscretionaryAccessControl(AuditTrailControlContext
        ruleDacAccess.setSystemCall(__NR_readlinkat);
        ruleDacAccess.setSystemCall(__NR_faccessat);
 
-       ruleDacAccess.setReturn(-EACCES);
+       ruleDacAccess.addCondition({AUDIT_EXIT, AUDIT_EQUAL, -EACCES});
 
        //EPERM only
 
-       ruleDacPerm.setReturn(-EPERM);
+       ruleDacPerm.addCondition({AUDIT_EXIT, AUDIT_EQUAL, -EPERM});
 
        try {
                context.removeAuditRule(ruleDacAccess);
index a04a96dc94a5b1853083d37c2d8e8d62c5868989..f2e713287c9a4a703089b954a293e3c07a8198bc 100644 (file)
 #include <memory>
 
 #include <klay/filesystem.h>
-#include <klay/netlink/audit.h>
 #include <klay/file-descriptor.h>
 #include <klay/rmi/service.h>
 
+#include "audit/audit.h"
+
 class Server final {
 public:
        typedef std::function<void(int, std::vector<char>&)> AuditHandler;
index 3b5a615eb4129a1af31833e93c31f75ef7076298..e14e915e21cb0fc7d331768dc2b378eafba9a314 100644 (file)
@@ -86,7 +86,7 @@ SystemCall::SystemCall(AuditTrailControlContext &ctx) :
 
        context.createNotification("SystemCall");
 
-       ruleAllSyscall.setKey(AUDIT_RULE_KEY);
+       ruleAllSyscall.addCondition({AUDIT_FILTERKEY, AUDIT_EQUAL, AUDIT_RULE_KEY});
        ruleAllSyscall.setAllSystemCalls();
 
        try {