--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Rafal Krypa <r.krypa@samsung.com>
+ *
+ * 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 mount-monitor.h
+ * @author Rafal Krypa <r.krypa@samsung.com>
+ * @version 1.0
+ * @brief Monitor mount/umount events
+ */
+
+#pragma once
+
+#include <libmount.h>
+
+#include <atomic>
+#include <functional>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace SecurityManager {
+
+class MntFS {
+public:
+ MntFS(const libmnt_fs *fs);
+ ~MntFS();
+
+ MntFS(const MntFS &) = delete;
+ MntFS(MntFS &&other);
+ MntFS & operator=(const MntFS &) = delete;
+ MntFS && operator=(MntFS &&other);
+
+ std::string getSource() const;
+ std::string getTarget() const;
+
+private:
+ struct libmnt_fs *m_fs = nullptr;
+};
+
+class MntDiffEntry
+{
+public:
+
+ enum class Type {
+ MOUNT = MNT_TABDIFF_MOUNT,
+ UMOUNT = MNT_TABDIFF_UMOUNT,
+ MOVE = MNT_TABDIFF_MOVE,
+ REMOUNT = MNT_TABDIFF_REMOUNT
+ };
+
+ Type m_type;
+ MntFS m_oldFS, m_newFS;
+
+ MntDiffEntry(int type, const libmnt_fs *oldFS, const libmnt_fs *newFS) :
+ m_type(static_cast<Type>(type)), m_oldFS(oldFS), m_newFS(newFS)
+ {}
+};
+
+class MntTable {
+public:
+ MntTable(const std::string &file = "/proc/self/mountinfo");
+ ~MntTable();
+
+ MntTable(const MntTable &) = delete;
+ MntTable(MntTable &&other);
+ MntTable & operator=(const MntTable &) = delete;
+ MntTable & operator=(MntTable &&other);
+
+ std::vector<MntDiffEntry> diff(const MntTable &other);
+
+private:
+ libmnt_table *m_table = nullptr;
+};
+
+class MntMonitor
+{
+public:
+ MntMonitor(const std::function<void(MntDiffEntry &)> &callback);
+ ~MntMonitor();
+
+private:
+ void threadNotifyPut();
+ void threadNotifyGet();
+ void run();
+
+ MntTable m_table;
+ struct libmnt_monitor *m_monitor;
+ int m_monitorFd;
+
+ std::function<void(MntDiffEntry &)> m_callback;
+
+ std::mutex m_monitorMut;
+ std::thread m_thread;
+ std::atomic<bool> m_terminate;
+ const int m_eventFd;
+};
+
+} // namespace SecurityManager
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Rafal Krypa <r.krypa@samsung.com>
+ *
+ * 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 mount-monitor.cpp
+ * @author Rafal Krypa <r.krypa@samsung.com>
+ * @version 1.0
+ * @brief Monitor mount/umount events
+ */
+
+#include <mount-monitor.h>
+
+#include <dpl/errno_string.h>
+#include <dpl/log/log.h>
+#include <utils.h>
+
+#include <poll.h>
+#include <sys/eventfd.h>
+
+namespace SecurityManager {
+
+MntFS::MntFS(const libmnt_fs *fs)
+{
+ if (fs != nullptr) {
+ m_fs = mnt_copy_fs(nullptr, fs);
+ if (m_fs == nullptr)
+ throw std::bad_alloc();
+ } else {
+ m_fs = nullptr;
+ }
+}
+
+MntFS::MntFS(MntFS &&other)
+{
+ if (m_fs != nullptr)
+ mnt_unref_fs(m_fs);
+ m_fs = other.m_fs;
+ other.m_fs = nullptr;
+}
+
+MntFS::~MntFS()
+{
+ if (m_fs != nullptr)
+ mnt_unref_fs(m_fs);
+}
+
+std::string MntFS::getSource() const
+{
+ return mnt_fs_get_source(m_fs);
+}
+
+std::string MntFS::getTarget() const
+{
+ return mnt_fs_get_target(m_fs);
+}
+
+MntTable::MntTable(const std::string &file)
+{
+ m_table = mnt_new_table_from_file(file.c_str());
+ if (m_table == nullptr)
+ throw std::bad_alloc();
+}
+
+MntTable::~MntTable()
+{
+ if (m_table != nullptr)
+ mnt_free_table(m_table);
+}
+
+MntTable& MntTable::operator=(MntTable &&other)
+{
+ if (m_table != nullptr)
+ mnt_free_table(m_table);
+ m_table = other.m_table;
+ other.m_table = nullptr;
+
+ return *this;
+}
+
+std::vector<MntDiffEntry> MntTable::diff(const MntTable &other)
+{
+ std::vector<MntDiffEntry> entries;
+
+ struct libmnt_tabdiff *diff = mnt_new_tabdiff();
+ if (diff == nullptr)
+ throw std::bad_alloc();
+ auto diffPtr = makeUnique(diff, mnt_free_tabdiff);
+
+ if (mnt_diff_tables(diff, m_table, other.m_table) < 0)
+ throw std::bad_alloc();
+
+ struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
+ if (itr == nullptr)
+ throw std::bad_alloc();
+ auto itrPtr = makeUnique(itr, mnt_free_iter);
+
+ int type;
+ struct libmnt_fs *fs_old, *fs_new;
+ while (mnt_tabdiff_next_change(diff, itr, &fs_old, &fs_new, &type) == 0)
+ entries.emplace_back(type, fs_old, fs_new);
+
+ return entries;
+}
+
+MntMonitor::MntMonitor(const std::function<void(MntDiffEntry &)> &callback) :
+ m_callback(callback), m_terminate(false), m_eventFd(eventfd(0, 0))
+{
+ m_monitor = mnt_new_monitor();
+ if (m_monitor == nullptr)
+ throw std::bad_alloc();
+ mnt_monitor_enable_kernel(m_monitor, true);
+ m_monitorFd = mnt_monitor_get_fd(m_monitor);
+
+ m_thread = std::thread(&MntMonitor::run, this);
+}
+
+MntMonitor::~MntMonitor()
+{
+ m_terminate = true;
+ threadNotifyPut();
+ m_thread.join();
+
+ // Critical section
+ std::lock_guard<std::mutex> guard(m_monitorMut);
+ mnt_unref_monitor(m_monitor);
+}
+
+void MntMonitor::threadNotifyPut()
+{
+ int ret = eventfd_write(m_eventFd, 1);
+ if (ret == -1)
+ LogError("Unexpected error while writing to eventfd: " << GetErrnoString(errno));
+}
+
+void MntMonitor::threadNotifyGet()
+{
+ eventfd_t value;
+ int ret = eventfd_read(m_eventFd, &value);
+ if (ret == -1)
+ LogError("Unexpected error while reading from eventfd: " << GetErrnoString(errno));
+}
+
+void MntMonitor::run()
+{
+ while (true) {
+ struct pollfd pollFds[2] = {{m_eventFd, POLLIN, 0}, {m_monitorFd, POLLIN, 0}};
+ int ret = poll(pollFds, 2, -1);
+
+ if (ret == -1) {
+ if (errno != EINTR)
+ //LogError("Unexpected error returned by poll: " << GetErrnoString(errno));
+ continue;
+ }
+
+ // Check eventfd for termination signal
+ if (pollFds[0].revents) {
+ threadNotifyGet();
+ if (m_terminate) {
+ //LogInfo("MntMonitor thread terminated");
+ return;
+ }
+ }
+
+ pollFds[1].revents = 0;
+ // Critical section
+ std::lock_guard<std::mutex> guard(m_monitorMut);
+
+ while (mnt_monitor_next_change(m_monitor, nullptr, nullptr) == 0) {
+ MntTable tableNew;
+ std::vector<MntDiffEntry> diff = m_table.diff(tableNew);
+ m_table = std::move(tableNew);
+
+ for (auto &e : diff)
+ m_callback(e);
+ }
+ }
+}
+
+} /* namespace SecurityManager */