system-call.cpp
mandatory-access-control.cpp
discretionary-access-control.cpp
+ audit/audit.cpp
+ audit/audit-rule.cpp
)
SET(DEPENDENCY klay
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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__
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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__
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);
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);
#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;
context.createNotification("SystemCall");
- ruleAllSyscall.setKey(AUDIT_RULE_KEY);
+ ruleAllSyscall.addCondition({AUDIT_FILTERKEY, AUDIT_EQUAL, AUDIT_RULE_KEY});
ruleAllSyscall.setAllSystemCalls();
try {