From: Sungbae Yoo Date: Fri, 9 Jun 2017 11:31:50 +0000 (+0900) Subject: Add audit class to use linux audit subsystem X-Git-Tag: submit/tizen/20170720.071940~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F58%2F133758%2F5;p=platform%2Fcore%2Fsecurity%2Fklay.git Add audit class to use linux audit subsystem Signed-off-by: Sungbae Yoo Change-Id: I9a88371ebe822c93efd5a849de311d6a8ed4761f --- diff --git a/include/klay/netlink/audit.h b/include/klay/netlink/audit.h new file mode 100644 index 0000000..61a2ef6 --- /dev/null +++ b/include/klay/netlink/audit.h @@ -0,0 +1,63 @@ +/* + * 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 + */ + +#ifndef __RUNTIME_NETLINK_AUDIT_H__ +#define __RUNTIME_NETLINK_AUDIT_H__ + +#include +#include + +#include + +#include +#include + +namespace netlink { + +class Audit final { +public: + typedef std::pair> Message; + typedef std::function 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(); + + 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__ diff --git a/include/klay/netlink/netlink.h b/include/klay/netlink/netlink.h new file mode 100644 index 0000000..10e5a80 --- /dev/null +++ b/include/klay/netlink/netlink.h @@ -0,0 +1,50 @@ +/* + * 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 + */ + +#ifndef __RUNTIME_NETLINK_NETLINK_H__ +#define __RUNTIME_NETLINK_NETLINK_H__ + +#include + +#ifndef NETLINK_AUDIT +#define NETLINK_AUDIT 9 +#endif + +namespace netlink { + +class Netlink final { +public: + Netlink(int); + Netlink(Netlink&&); + Netlink(const Netlink&) = delete; + ~Netlink(); + + Netlink& operator=(const Netlink&) = delete; + + void send(const void *data, unsigned int size); + void recv(void *data, unsigned int size, int options = 0); + + int getFd() const { + return fd; + } + +private: + int fd; +}; + +} // namespace runtime + +#endif //!__RUNTIME_NETLINK_NETLINK_H__ diff --git a/include/klay/rmi/service.h b/include/klay/rmi/service.h index 883b63b..77d33d3 100644 --- a/include/klay/rmi/service.h +++ b/include/klay/rmi/service.h @@ -187,6 +187,8 @@ public: return processingContext.credentials.gid; } + runtime::Mainloop mainloop; + private: struct ProcessingContext { ProcessingContext() = default; @@ -229,7 +231,6 @@ private: NotificationRegistry notificationRegistry; ConnectionRegistry connectionRegistry; - runtime::Mainloop mainloop; std::string address; runtime::ThreadPool workqueue; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1fb0bc..c135d23 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,6 +48,8 @@ SET (KLAY_SOURCES ${KLAY_SRC}/error.cpp ${KLAY_SRC}/audit/console-sink.cpp ${KLAY_SRC}/audit/dlog-sink.cpp ${KLAY_SRC}/audit/audit-trail.cpp + ${KLAY_SRC}/netlink/audit.cpp + ${KLAY_SRC}/netlink/netlink.cpp ) SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,noexecstack") diff --git a/src/netlink/audit.cpp b/src/netlink/audit.cpp new file mode 100644 index 0000000..680656e --- /dev/null +++ b/src/netlink/audit.cpp @@ -0,0 +1,189 @@ +/* + * 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 + */ +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +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; +} + +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 err = (struct nlmsgerr*)recv().second.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(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(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/src/netlink/netlink.cpp b/src/netlink/netlink.cpp new file mode 100644 index 0000000..c0bf91a --- /dev/null +++ b/src/netlink/netlink.cpp @@ -0,0 +1,99 @@ +/* + * 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 + */ +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace netlink { + +Netlink::Netlink(int protocol) +{ + fd = ::socket(PF_NETLINK, SOCK_RAW, protocol); + if (fd < 0) { + throw runtime::Exception(runtime::GetSystemErrorMessage()); + } + + if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { + ::close(fd); + throw runtime::Exception(runtime::GetSystemErrorMessage()); + } +} + +Netlink::Netlink(Netlink&& netlink) : + fd(netlink.fd) +{ + netlink.fd = -1; +} + +Netlink::~Netlink() +{ + if (fd > 0) { + ::close(fd); + } +} + +void Netlink::send(const void *buf, unsigned int size) +{ + struct sockaddr_nl addr; + int ret; + + ::memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pid = 0; + addr.nl_groups = 0; + + do { + ret = ::sendto(fd, buf, size, 0, + (struct sockaddr*)&addr, size); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + throw runtime::Exception("Failed to send audit packet"); + } +} + +void Netlink::recv(void *buf, unsigned int size, int options) +{ + struct sockaddr_nl nladdr; + socklen_t nladdrlen = sizeof(nladdr); + int ret; + + do { + ret = ::recvfrom(fd, buf, size, options, + (struct sockaddr*)&nladdr, &nladdrlen); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + throw runtime::Exception("Failed to receive audit packet"); + } + + if (nladdrlen != sizeof(nladdr)) { + throw runtime::Exception("Bad address size reading audit netlink socket"); + } + + if (nladdr.nl_pid) { + throw runtime::Exception("Spoofed packet received on audit netlink socket"); + } +} + +} // namespace runtime