From d1034a9876a445b6b66b0665387166e335ea7f70 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Thu, 12 Jun 2014 15:31:19 +0200 Subject: [PATCH 01/16] Dbus API for "Display Off" signal [Feature] - API in Dbus to handle "Display Off" signal. - Switching to default container when "Display Off" signal occurs. [Cause] SC must properly react when device is inactive for some time. [Solution] Create a Dbus API for Display Off signal. Use this event to switch to default container. [Verification] Build, install, run ContainersManagerSuite and ContainerConnectionSuite tests. Both suites should pass. Change-Id: I34e0178cd9d8efbbdad92e1f2d69f4c32b41f779 Signed-off-by: Lukasz Kostyra --- server/configs/daemon.conf | 1 + server/container-connection.cpp | 34 ++++++ server/container-connection.hpp | 12 +++ server/container.cpp | 15 +++ server/container.hpp | 7 ++ server/containers-manager-config.hpp | 6 ++ server/containers-manager.cpp | 18 ++++ server/containers-manager.hpp | 1 + server/fake-power-manager-dbus-definitions.hpp | 56 ++++++++++ .../ut-containers-manager/buggy-daemon.conf | 1 + .../buggy-default-daemon.conf | 10 ++ .../buggy-foreground-daemon.conf | 1 + .../configs/ut-containers-manager/test-daemon.conf | 1 + .../ut-containers-manager/test-dbus-daemon.conf | 1 + .../server/configs/ut-server/buggy-daemon.conf | 1 + .../server/configs/ut-server/test-daemon.conf | 1 + .../unit_tests/server/ut-container-connection.cpp | 90 ++++++++++++++++ tests/unit_tests/server/ut-containers-manager.cpp | 114 +++++++++++++++++++-- 18 files changed, 361 insertions(+), 9 deletions(-) create mode 100644 server/fake-power-manager-dbus-definitions.hpp create mode 100644 tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf diff --git a/server/configs/daemon.conf b/server/configs/daemon.conf index 2610f5e..591e0b7 100644 --- a/server/configs/daemon.conf +++ b/server/configs/daemon.conf @@ -1,6 +1,7 @@ { "containerConfigs" : ["containers/private.conf", "containers/business.conf" ], "foregroundId" : "private", + "defaultId" : "private", "inputConfig" : {"enabled" : true, "device" : "gpio-keys", "code" : 139, diff --git a/server/container-connection.cpp b/server/container-connection.cpp index 9f8a417..cf541f7 100644 --- a/server/container-connection.cpp +++ b/server/container-connection.cpp @@ -27,6 +27,8 @@ #include "container-connection.hpp" #include "container-dbus-definitions.hpp" #include "exception.hpp" +// TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager +#include "fake-power-manager-dbus-definitions.hpp" #include "log/logger.hpp" @@ -77,6 +79,16 @@ ContainerConnection::ContainerConnection(const std::string& address, const OnNam _3, _4, _5)); + + mDbusConnection->signalSubscribe(std::bind(&ContainerConnection::onSignalReceived, + this, + _1, + _2, + _3, + _4, + _5), + std::string(fake_power_manager_api::BUS_NAME)); + LOGD("Connected"); } @@ -123,6 +135,11 @@ void ContainerConnection::setNotifyActiveContainerCallback( mNotifyActiveContainerCallback = callback; } +void ContainerConnection::setDisplayOffCallback(const DisplayOffCallback& callback) +{ + mDisplayOffCallback = callback; +} + void ContainerConnection::onMessageCall(const std::string& objectPath, const std::string& interface, const std::string& methodName, @@ -144,6 +161,23 @@ void ContainerConnection::onMessageCall(const std::string& objectPath, } } +void ContainerConnection::onSignalReceived(const std::string& senderBusName, + const std::string& objectPath, + const std::string& interface, + const std::string& signalName, + GVariant* /*parameters*/) +{ + LOGD("Received signal: " << senderBusName << "; " << objectPath << "; " << interface << "; " + << signalName); + if (objectPath == fake_power_manager_api::OBJECT_PATH && + interface == fake_power_manager_api::INTERFACE) { + //power-manager sent us a signal, check it + if (signalName == fake_power_manager_api::SIGNAL_DISPLAY_OFF && mDisplayOffCallback) { + mDisplayOffCallback(); + } + } +} + void ContainerConnection::sendNotification(const std::string& container, const std::string& application, const std::string& message) diff --git a/server/container-connection.hpp b/server/container-connection.hpp index 4ddac0e..e0b2467 100644 --- a/server/container-connection.hpp +++ b/server/container-connection.hpp @@ -39,6 +39,7 @@ class ContainerConnection { public: typedef std::function OnNameLostCallback; + typedef std::function DisplayOffCallback; ContainerConnection(const std::string& address, const OnNameLostCallback& callback); ~ContainerConnection(); @@ -55,6 +56,11 @@ public: void setNotifyActiveContainerCallback(const NotifyActiveContainerCallback& callback); /** + * Register callback to handle turning off the display + */ + void setDisplayOffCallback(const DisplayOffCallback& callback); + + /** * Send notification signal to this container */ void sendNotification(const std::string& container, @@ -69,6 +75,7 @@ private: bool mNameLost; OnNameLostCallback mOnNameLostCallback; NotifyActiveContainerCallback mNotifyActiveContainerCallback; + DisplayOffCallback mDisplayOffCallback; void onNameAcquired(); void onNameLost(); @@ -79,6 +86,11 @@ private: const std::string& methodName, GVariant* parameters, dbus::MethodResultBuilder& result); + void onSignalReceived(const std::string& senderBusName, + const std::string& objectPath, + const std::string& interface, + const std::string& signalName, + GVariant* parameters); }; diff --git a/server/container.cpp b/server/container.cpp index cebdb55..2d7114f 100644 --- a/server/container.cpp +++ b/server/container.cpp @@ -101,6 +101,10 @@ void Container::start() if (mNotifyCallback) { mConnection->setNotifyActiveContainerCallback(mNotifyCallback); } + if (mDisplayOffCallback) { + mConnection->setDisplayOffCallback(mDisplayOffCallback); + } + // Send to the background only after we're connected, // otherwise it'd take ages. LOGD(getId() << ": DBUS connected, sending to the background"); @@ -218,4 +222,15 @@ void Container::sendNotification(const std::string& container, } } +void Container::setDisplayOffCallback(const DisplayOffCallback& callback) +{ + Lock lock(mReconnectMutex); + + mDisplayOffCallback = callback; + if (mConnection) { + mConnection->setDisplayOffCallback(callback); + } +} + + } // namespace security_containers diff --git a/server/container.hpp b/server/container.hpp index a30708f..5dbccad 100644 --- a/server/container.hpp +++ b/server/container.hpp @@ -48,6 +48,7 @@ public: virtual ~Container(); typedef ContainerConnection::NotifyActiveContainerCallback NotifyActiveContainerCallback; + typedef ContainerConnection::DisplayOffCallback DisplayOffCallback; /** * Get the container id @@ -114,6 +115,11 @@ public: void setNotifyActiveContainerCallback(const NotifyActiveContainerCallback& callback); /** + * Register callback used when switching to default container. + */ + void setDisplayOffCallback(const DisplayOffCallback& callback); + + /** * Send notification signal to this container * * @param container name of container in which the notification occurred @@ -133,6 +139,7 @@ private: std::thread mReconnectThread; mutable std::recursive_mutex mReconnectMutex; NotifyActiveContainerCallback mNotifyCallback; + DisplayOffCallback mDisplayOffCallback; void onNameLostCallback(); void reconnectHandler(); diff --git a/server/containers-manager-config.hpp b/server/containers-manager-config.hpp index f523479..9f881c1 100644 --- a/server/containers-manager-config.hpp +++ b/server/containers-manager-config.hpp @@ -56,10 +56,16 @@ struct ContainersManagerConfig { */ std::string foregroundId; + /** + * An ID of default container. + */ + std::string defaultId; + CONFIG_REGISTER ( containerConfigs, foregroundId, + defaultId, inputConfig ) }; diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp index d26ac06..13ee3d4 100644 --- a/server/containers-manager.cpp +++ b/server/containers-manager.cpp @@ -64,9 +64,21 @@ ContainersManager::ContainersManager(const std::string& managerConfigPath): mDet id, _1, _2)); + + c->setDisplayOffCallback(bind(&ContainersManager::displayOffHandler, + this, + id)); + mContainers.insert(ContainerMap::value_type(id, std::move(c))); } + // check if default container exists, throw ContainerOperationException if not found + if (mContainers.find(mConfig.defaultId) == mContainers.end()) { + LOGE("Provided default container ID " << mConfig.defaultId << " is invalid."); + throw ContainerOperationException("Provided default container ID " + mConfig.defaultId + + " is invalid."); + } + LOGD("ContainersManager object instantiated"); if (mConfig.inputConfig.enabled) { @@ -192,4 +204,10 @@ void ContainersManager::notifyActiveContainerHandler(const std::string& caller, } } +void ContainersManager::displayOffHandler(const std::string& /*caller*/) +{ + LOGI("Switching to default container " << mConfig.defaultId); + focus(mConfig.defaultId); +} + } // namespace security_containers diff --git a/server/containers-manager.hpp b/server/containers-manager.hpp index 7fa3382..316e7bb 100644 --- a/server/containers-manager.hpp +++ b/server/containers-manager.hpp @@ -85,6 +85,7 @@ private: void notifyActiveContainerHandler(const std::string& caller, const std::string& appliaction, const std::string& message); + void displayOffHandler(const std::string& caller); }; diff --git a/server/fake-power-manager-dbus-definitions.hpp b/server/fake-power-manager-dbus-definitions.hpp new file mode 100644 index 0000000..f24bc81 --- /dev/null +++ b/server/fake-power-manager-dbus-definitions.hpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * 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 fake-power-manager-dbus-definitions.h + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Declaration of fake dbus definitions from power-manager. Made only to test API in + * ContainerConnection. + */ + +#ifndef FAKE_POWER_MANAGER_DBUS_DEFINITIONS_H +#define FAKE_POWER_MANAGER_DBUS_DEFINITIONS_H + +/** + * !!WARNING!! + * + * This header file is created only to test if API in ContainerConnection works correctly. It should + * be removed when power-managers API will be created. + */ + +namespace fake_power_manager_api +{ + +const std::string BUS_NAME = "com.tizen.fakepowermanager"; +const std::string OBJECT_PATH = "/com/tizen/fakepowermanager"; +const std::string INTERFACE = "com.tizen.fakepowermanager.manager"; + +const std::string SIGNAL_DISPLAY_OFF = "DisplayOff"; + +const std::string DEFINITION = + "" + " " + " " + " " + " " + ""; + + +} // namespace fake_power_manager_api + +#endif // FAKE_POWER_MANAGER_DBUS_DEFINITIONS_H diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf index ec42fdc..a403aa8 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf @@ -1,6 +1,7 @@ { "containerConfigs" : ["containers/console1.conf", "missing/file/path/missing.conf", "containers/console3.conf"], "foregroundId" : "ut-containers-manager-console1", + "defaultId" : "ut-containers-manager-console1", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf new file mode 100644 index 0000000..39d56df --- /dev/null +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf @@ -0,0 +1,10 @@ +{ + "containerConfigs" : ["containers/console1-dbus.conf", "containers/console2-dbus.conf", "containers/console3-dbus.conf"], + "foregroundId" : "ut-containers-manager-console1", + "defaultId" : "in_no_way_there_is_a_valid_id_here", + "inputConfig" : {"enabled" : false, + "device" : "/dev/doesnotexist", + "code" : 139, + "numberOfEvents" : 2, + "timeWindowMs" : 500} +} diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf index 0bb38b7..e12964a 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf @@ -1,6 +1,7 @@ { "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"], "foregroundId" : "this_id_does_not_exist", + "defaultId" : "ut-containers-manager-console1", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf index 29ac710..4ffe017 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf @@ -1,6 +1,7 @@ { "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"], "foregroundId" : "ut-containers-manager-console1", + "defaultId" : "ut-containers-manager-console1", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf index c403e04..ae59483 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf @@ -3,6 +3,7 @@ "containers/console2-dbus.conf", "containers/console3-dbus.conf"], "foregroundId" : "ut-containers-manager-console1", + "defaultId" : "ut-containers-manager-console1", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf index 0d27a85..47b4450 100644 --- a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf +++ b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf @@ -1,6 +1,7 @@ { "containerConfigs" : ["containers/container1.conf", "missing/file/path/missing.conf", "containers/container3.conf"], "foregroundId" : "ut-server-container1", + "defaultId" : "ut-server-container1", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-server/test-daemon.conf b/tests/unit_tests/server/configs/ut-server/test-daemon.conf index fc55c54..360bab7 100644 --- a/tests/unit_tests/server/configs/ut-server/test-daemon.conf +++ b/tests/unit_tests/server/configs/ut-server/test-daemon.conf @@ -1,6 +1,7 @@ { "containerConfigs" : ["containers/container1.conf", "containers/container2.conf", "containers/container3.conf"], "foregroundId" : "ut-server-container1", + "defaultId" : "ut-server-container1", "inputConfig" : {"enabled" : false, "device" : "gpio-keys.4", "code" : 139, diff --git a/tests/unit_tests/server/ut-container-connection.cpp b/tests/unit_tests/server/ut-container-connection.cpp index 4b757a3..92f98ac 100644 --- a/tests/unit_tests/server/ut-container-connection.cpp +++ b/tests/unit_tests/server/ut-container-connection.cpp @@ -29,8 +29,11 @@ #include "container-connection.hpp" #include "container-connection-transport.hpp" #include "container-dbus-definitions.hpp" +// TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager +#include "fake-power-manager-dbus-definitions.hpp" #include "dbus/connection.hpp" +#include "dbus/exception.hpp" #include "utils/scoped-daemon.hpp" #include "utils/glib-loop.hpp" #include "utils/latch.hpp" @@ -73,6 +76,53 @@ private: ScopedDaemon mDaemon; }; +class DbusNameSetter { +public: + DbusNameSetter() + : mNameAcquired(false), + mPendingDisconnect(false) + { + } + + void setName(const std::unique_ptr& conn, const std::string& name) + { + conn->setName(name, + std::bind(&DbusNameSetter::onNameAcquired, this), + std::bind(&DbusNameSetter::onDisconnect, this)); + + if(!waitForName()) { + throw dbus::DbusOperationException("Could not acquire name."); + } + } + + bool waitForName() + { + std::unique_lock lock(mMutex); + mNameCondition.wait(lock, [this] {return mNameAcquired || mPendingDisconnect;}); + return mNameAcquired; + } + + void onNameAcquired() + { + std::unique_lock lock(mMutex); + mNameAcquired = true; + mNameCondition.notify_one(); + } + + void onDisconnect() + { + std::unique_lock lock(mMutex); + mPendingDisconnect = true; + mNameCondition.notify_one(); + } + +private: + bool mNameAcquired; + bool mPendingDisconnect; + std::mutex mMutex; + std::condition_variable mNameCondition; +}; + } // namespace @@ -151,5 +201,45 @@ BOOST_AUTO_TEST_CASE(SignalNotificationApiTest) BOOST_CHECK(signalEmitted.wait(EVENT_TIMEOUT)); } +BOOST_AUTO_TEST_CASE(SignalDisplayOffApiTest) +{ + ScopedGlibLoop loop; + ScopedDbusDaemon dbus; + + Latch displayOffCalled; + std::unique_ptr connection; + + BOOST_REQUIRE_NO_THROW(connection.reset(new ContainerConnection(dbus.acquireAddress(), + nullptr))); + + DbusConnection::Pointer client = DbusConnection::create(dbus.acquireAddress()); + + auto callback = [&]() { + displayOffCalled.set(); + }; + + connection->setDisplayOffCallback(callback); + + client->emitSignal(fake_power_manager_api::OBJECT_PATH, + fake_power_manager_api::INTERFACE, + fake_power_manager_api::SIGNAL_DISPLAY_OFF, + nullptr); + + // timeout should occur, since no name is set to client + BOOST_CHECK(!displayOffCalled.wait(EVENT_TIMEOUT)); + + DbusNameSetter setter; + + setter.setName(client, fake_power_manager_api::BUS_NAME); + + client->emitSignal(fake_power_manager_api::OBJECT_PATH, + fake_power_manager_api::INTERFACE, + fake_power_manager_api::SIGNAL_DISPLAY_OFF, + nullptr); + + // now signal should be delivered correctly + BOOST_CHECK(displayOffCalled.wait(EVENT_TIMEOUT)); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit_tests/server/ut-containers-manager.cpp b/tests/unit_tests/server/ut-containers-manager.cpp index f12c9d6..61eea40 100644 --- a/tests/unit_tests/server/ut-containers-manager.cpp +++ b/tests/unit_tests/server/ut-containers-manager.cpp @@ -28,9 +28,12 @@ #include "containers-manager.hpp" #include "container-dbus-definitions.hpp" +// TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager +#include "fake-power-manager-dbus-definitions.hpp" #include "exception.hpp" #include "dbus/connection.hpp" +#include "dbus/exception.hpp" #include "utils/glib-loop.hpp" #include "config/exception.hpp" #include "utils/latch.hpp" @@ -39,6 +42,8 @@ #include #include #include +#include +#include using namespace security_containers; @@ -52,6 +57,7 @@ const std::string TEST_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-cont const std::string TEST_DBUS_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/test-dbus-daemon.conf"; const std::string BUGGY_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-daemon.conf"; const std::string BUGGY_FOREGROUND_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-foreground-daemon.conf"; +const std::string BUGGY_DEFAULTID_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-default-daemon.conf"; const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/missing-daemon.conf"; const int EVENT_TIMEOUT = 5000; const int TEST_DBUS_CONNECTION_CONTAINERS_COUNT = 3; @@ -63,20 +69,63 @@ class DbusAccessory { public: std::vector mReceivedSignalsSource; - DbusAccessory(int id, Latch& signalEmittedLatch) + DbusAccessory(int id) : mId(id), mClient(DbusConnection::create(acquireAddress())), - mSignalEmittedLatch(signalEmittedLatch) + mNameAcquired(false), + mPendingDisconnect(false) { } - void signalSubscribe() + void setName(const std::string& name) + { + mClient->setName(name, + std::bind(&DbusAccessory::onNameAcquired, this), + std::bind(&DbusAccessory::onDisconnect, this)); + + if(!waitForName()) { + mClient.reset(); + throw dbus::DbusOperationException("Could not acquire name."); + } + } + + bool waitForName() + { + std::unique_lock lock(mMutex); + mNameCondition.wait(lock, [this] {return mNameAcquired || mPendingDisconnect;}); + return mNameAcquired; + } + + void onNameAcquired() + { + std::unique_lock lock(mMutex); + mNameAcquired = true; + mNameCondition.notify_one(); + } + + void onDisconnect() + { + std::unique_lock lock(mMutex); + mPendingDisconnect = true; + mNameCondition.notify_one(); + } + + void signalSubscribe(Latch& referenceLatch) { using namespace std::placeholders; - mClient->signalSubscribe(std::bind(&DbusAccessory::handler, this, _1, _2, _3, _4, _5), + mClient->signalSubscribe(std::bind(&DbusAccessory::handler, + this, std::ref(referenceLatch), _1, _2, _3, _4, _5), api::BUS_NAME); } + void emitSignal(const std::string& objectPath, + const std::string& interface, + const std::string& name, + GVariant* parameters) + { + mClient->emitSignal(objectPath, interface, name, parameters); + } + void callMethod() { GVariant* parameters = g_variant_new("(ss)", TEST_APP_NAME.c_str(), TEST_MESSGAE.c_str()); @@ -96,7 +145,10 @@ public: private: const int mId; DbusConnection::Pointer mClient; - Latch& mSignalEmittedLatch; + bool mNameAcquired; + bool mPendingDisconnect; + std::mutex mMutex; + std::condition_variable mNameCondition; std::string acquireAddress() const { @@ -104,7 +156,8 @@ private: "-dbus/dbus/system_bus_socket"; } - void handler(const std::string& /*senderBusName*/, + void handler(Latch& referenceLatch, + const std::string& /*senderBusName*/, const std::string& objectPath, const std::string& interface, const std::string& signalName, @@ -121,7 +174,7 @@ private: g_variant_get(parameters, "(&s&s&s)", &container, &application, &message); mReceivedSignalsSource.push_back(container); if (application == TEST_APP_NAME && message == TEST_MESSGAE) { - mSignalEmittedLatch.set(); + referenceLatch.set(); } } } @@ -168,6 +221,12 @@ BOOST_AUTO_TEST_CASE(BuggyForegroundTest) BOOST_CHECK(cm.getRunningForegroundContainerId() == "ut-containers-manager-console2"); } +BOOST_AUTO_TEST_CASE(BuggyDefaultTest) +{ + BOOST_REQUIRE_THROW(ContainersManager cm(BUGGY_DEFAULTID_CONFIG_PATH), + ContainerOperationException); +} + BOOST_AUTO_TEST_CASE(StopAllTest) { ContainersManager cm(TEST_CONFIG_PATH); @@ -210,10 +269,10 @@ BOOST_AUTO_TEST_CASE(NotifyActiveContainerTest) std::vector< std::unique_ptr > dbuses; for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) { - dbuses.push_back(std::unique_ptr(new DbusAccessory(i, signalReceivedLatch))); + dbuses.push_back(std::unique_ptr(new DbusAccessory(i))); } for (auto& dbus : dbuses) { - dbus->signalSubscribe(); + dbus->signalSubscribe(signalReceivedLatch); } for (auto& dbus : dbuses) { dbus->callMethod(); @@ -238,4 +297,41 @@ BOOST_AUTO_TEST_CASE(NotifyActiveContainerTest) dbuses.clear(); } +BOOST_AUTO_TEST_CASE(DisplayOffTest) +{ + ContainersManager cm(TEST_DBUS_CONFIG_PATH); + BOOST_REQUIRE_NO_THROW(cm.startAll()); + + std::vector> clients; + for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) { + clients.push_back(std::unique_ptr(new DbusAccessory(i))); + } + + for (auto& client : clients) { + client->setName(fake_power_manager_api::BUS_NAME); + } + + std::mutex Mutex; + std::unique_lock Lock(Mutex); + std::condition_variable Condition; + auto cond = [&cm]() -> bool { + return cm.getRunningForegroundContainerId() == "ut-containers-manager-console1"; + }; + + for (auto& client : clients) { + // TEST SWITCHING TO DEFAULT CONTAINER + // focus non-default container + BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console3")); + + // emit signal from dbus connection + BOOST_REQUIRE_NO_THROW(client->emitSignal(fake_power_manager_api::OBJECT_PATH, + fake_power_manager_api::INTERFACE, + fake_power_manager_api::SIGNAL_DISPLAY_OFF, + nullptr)); + + // check if default container has focus + BOOST_CHECK(Condition.wait_for(Lock, std::chrono::milliseconds(EVENT_TIMEOUT), cond)); + } +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 7834a74cd7b7f7b0f45f60c6274f58e5d57188b0 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Mon, 30 Jun 2014 16:30:39 +0200 Subject: [PATCH 02/16] Fix RPM build error [Bug/Feature] RPM build error. [Cause] Installed but unpackaged files found. [Solution] N/A [Verification] Build, install, run tests Change-Id: Icd4f2703d0d507ecafd795c623439393151f3675 Signed-off-by: Dariusz Michaluk --- packaging/security-containers.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec index 49c2d84..dc6e8ac 100644 --- a/packaging/security-containers.spec +++ b/packaging/security-containers.spec @@ -158,5 +158,5 @@ Unit tests for both: server and client and integration tests. %attr(755,root,root) %{script_dir}/sc_launch_test.py %{script_dir}/sc_test_parser.py %{_datadir}/security-containers -%{python_sitelib}/sc_integration_tests/ +%{python_sitelib}/sc_integration_tests -- 2.7.4 From 333a8be979fb2a98a0f11139d485d6d99efa97fb Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Tue, 1 Jul 2014 13:09:08 +0200 Subject: [PATCH 03/16] Rename dbus interface name [Bug/Feature] Rename interface name from 'com.samsung' to 'org.tizen' [Cause] This is not a proprietary code [Solution] N/A [Verification] Build, install, run tests Change-Id: I39cf5b5fc74b0f01e8678fab3a2ba02bc87c7ade --- container-daemon/CMakeLists.txt | 2 +- container-daemon/configs/com.samsung.container.daemon.conf | 14 -------------- container-daemon/configs/org.tizen.container.daemon.conf | 14 ++++++++++++++ container-daemon/daemon-dbus-definitions.hpp | 6 +++--- packaging/security-containers.spec | 2 +- server/configs/CMakeLists.txt | 2 +- .../etc/dbus-1/system.d/com.samsung.containers.conf | 14 -------------- .../etc/dbus-1/system.d/org.tizen.containers.conf | 14 ++++++++++++++ server/container-dbus-definitions.hpp | 6 +++--- tests/unit_tests/dbus/test-common.hpp | 4 ++-- tests/unit_tests/dbus/test-server.cpp | 2 +- 11 files changed, 40 insertions(+), 40 deletions(-) delete mode 100644 container-daemon/configs/com.samsung.container.daemon.conf create mode 100644 container-daemon/configs/org.tizen.container.daemon.conf delete mode 100644 server/configs/image-skel/etc/dbus-1/system.d/com.samsung.containers.conf create mode 100644 server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.conf diff --git a/container-daemon/CMakeLists.txt b/container-daemon/CMakeLists.txt index c623798..d997ab7 100644 --- a/container-daemon/CMakeLists.txt +++ b/container-daemon/CMakeLists.txt @@ -40,5 +40,5 @@ TARGET_LINK_LIBRARIES(${CONTAINER_DAEMON_CODENAME} ${CONTAINER_DAEMON_DEPS_LIBRA ## Install ##################################################################### INSTALL(TARGETS ${CONTAINER_DAEMON_CODENAME} DESTINATION bin) -INSTALL(FILES configs/com.samsung.container.daemon.conf +INSTALL(FILES configs/org.tizen.container.daemon.conf DESTINATION /etc/dbus-1/system.d/) diff --git a/container-daemon/configs/com.samsung.container.daemon.conf b/container-daemon/configs/com.samsung.container.daemon.conf deleted file mode 100644 index 26dbddd..0000000 --- a/container-daemon/configs/com.samsung.container.daemon.conf +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - diff --git a/container-daemon/configs/org.tizen.container.daemon.conf b/container-daemon/configs/org.tizen.container.daemon.conf new file mode 100644 index 0000000..d962c15 --- /dev/null +++ b/container-daemon/configs/org.tizen.container.daemon.conf @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/container-daemon/daemon-dbus-definitions.hpp b/container-daemon/daemon-dbus-definitions.hpp index 785a9cb..2cc283e 100644 --- a/container-daemon/daemon-dbus-definitions.hpp +++ b/container-daemon/daemon-dbus-definitions.hpp @@ -32,9 +32,9 @@ namespace security_containers { namespace container_daemon { namespace api { -const std::string BUS_NAME = "com.samsung.container.daemon"; -const std::string OBJECT_PATH = "/com/samsung/container/daemon"; -const std::string INTERFACE = "com.samsung.container.daemon"; +const std::string BUS_NAME = "org.tizen.container.daemon"; +const std::string OBJECT_PATH = "/org/tizen/container/daemon"; +const std::string INTERFACE = "org.tizen.container.daemon"; const std::string METHOD_GAIN_FOCUS = "GainFocus"; const std::string METHOD_LOSE_FOCUS = "LoseFocus"; diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec index dc6e8ac..d6bcc2c 100644 --- a/packaging/security-containers.spec +++ b/packaging/security-containers.spec @@ -133,7 +133,7 @@ Daemon running inside every container. %manifest packaging/security-containers-container-daemon.manifest %defattr(644,root,root,755) %attr(755,root,root) %{_bindir}/security-containers-container-daemon -/etc/dbus-1/system.d/com.samsung.container.daemon.conf +/etc/dbus-1/system.d/org.tizen.container.daemon.conf ## Test Package ################################################################ diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index 935cc2f..2e46a66 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -28,7 +28,7 @@ INSTALL(FILES daemon.conf DESTINATION ${SC_CONFIG_INSTALL_DIR}) # TODO This file should be installed to /etc/dbus-1/system.d/ on an every container -INSTALL(FILES image-skel/etc/dbus-1/system.d/com.samsung.containers.conf +INSTALL(FILES image-skel/etc/dbus-1/system.d/org.tizen.containers.conf DESTINATION ${SC_CONFIG_INSTALL_DIR}/image-skel/etc/dbus-1/system.d) INSTALL(FILES ${container_CONF} diff --git a/server/configs/image-skel/etc/dbus-1/system.d/com.samsung.containers.conf b/server/configs/image-skel/etc/dbus-1/system.d/com.samsung.containers.conf deleted file mode 100644 index 81be3a1..0000000 --- a/server/configs/image-skel/etc/dbus-1/system.d/com.samsung.containers.conf +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - diff --git a/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.conf b/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.conf new file mode 100644 index 0000000..f672c76 --- /dev/null +++ b/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.conf @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/server/container-dbus-definitions.hpp b/server/container-dbus-definitions.hpp index de806e7..7fec0db 100644 --- a/server/container-dbus-definitions.hpp +++ b/server/container-dbus-definitions.hpp @@ -32,9 +32,9 @@ namespace security_containers { namespace api { -const std::string BUS_NAME = "com.samsung.containers"; -const std::string OBJECT_PATH = "/com/samsung/containers"; -const std::string INTERFACE = "com.samsung.containers.manager"; +const std::string BUS_NAME = "org.tizen.containers"; +const std::string OBJECT_PATH = "/org/tizen/containers"; +const std::string INTERFACE = "org.tizen.containers.manager"; const std::string METHOD_NOTIFY_ACTIVE_CONTAINER = "NotifyActiveContainer"; const std::string SIGNAL_NOTIFICATION = "Notification"; diff --git a/tests/unit_tests/dbus/test-common.hpp b/tests/unit_tests/dbus/test-common.hpp index 5ac9881..85dad51 100644 --- a/tests/unit_tests/dbus/test-common.hpp +++ b/tests/unit_tests/dbus/test-common.hpp @@ -34,8 +34,8 @@ namespace security_containers { const std::string DBUS_SOCKET_FILE = "/tmp/container_socket"; const std::string DBUS_ADDRESS = "unix:path=" + DBUS_SOCKET_FILE; -const std::string TESTAPI_BUS_NAME = "com.samsung.tests"; -const std::string TESTAPI_OBJECT_PATH = "/com/samsung/tests"; +const std::string TESTAPI_BUS_NAME = "org.tizen.tests"; +const std::string TESTAPI_OBJECT_PATH = "/org/tizen/tests"; const std::string TESTAPI_INTERFACE = "tests.api"; const std::string TESTAPI_METHOD_NOOP = "Noop"; const std::string TESTAPI_METHOD_PROCESS = "Process"; diff --git a/tests/unit_tests/dbus/test-server.cpp b/tests/unit_tests/dbus/test-server.cpp index e245d4d..6fcbbda 100644 --- a/tests/unit_tests/dbus/test-server.cpp +++ b/tests/unit_tests/dbus/test-server.cpp @@ -142,7 +142,7 @@ void DbusTestServer::onMessageCall(const std::string& objectPath, LOGE("unknown method; should never happen"); } } catch (const std::exception& e) { - result.setError("com.samsung.Exception", e.what()); + result.setError("org.tizen.Exception", e.what()); } } -- 2.7.4 From 8fb601f688e7a955cd14d08b496e581d88dd2c4e Mon Sep 17 00:00:00 2001 From: Mateusz Malicki Date: Wed, 2 Jul 2014 09:08:06 +0200 Subject: [PATCH 04/16] Fixed path in test configuration file removed [Bug/Feature] Tests don't work on some installations [Cause] There is a fixed path in test configuration file [Solution] Remove fixed path in test configuration file [Verification] Build, install, run test ContainersManagerSuite Change-Id: Icd7bff311d2d1e9e982bbee8d577247fb66da1a4 --- tests/unit_tests/server/configs/CMakeLists.txt | 10 ++++++++++ .../libvirt-config/{console1-dbus.xml => console1-dbus.xml.in} | 2 +- .../libvirt-config/{console2-dbus.xml => console2-dbus.xml.in} | 2 +- .../libvirt-config/{console3-dbus.xml => console3-dbus.xml.in} | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) rename tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/{console1-dbus.xml => console1-dbus.xml.in} (78%) rename tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/{console2-dbus.xml => console2-dbus.xml.in} (78%) rename tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/{console3-dbus.xml => console3-dbus.xml.in} (78%) diff --git a/tests/unit_tests/server/configs/CMakeLists.txt b/tests/unit_tests/server/configs/CMakeLists.txt index 42b76d8..fac2f9c 100644 --- a/tests/unit_tests/server/configs/CMakeLists.txt +++ b/tests/unit_tests/server/configs/CMakeLists.txt @@ -55,6 +55,14 @@ CONFIGURE_FILE(ut-network-admin/containers/buggy.conf.in ${CMAKE_BINARY_DIR}/ut-network-admin/containers/buggy.conf @ONLY) FILE(GLOB network_container_CONF_GEN ${CMAKE_BINARY_DIR}/ut-network-admin/containers/*.conf) +CONFIGURE_FILE(ut-containers-manager/libvirt-config/console1-dbus.xml.in + ${CMAKE_BINARY_DIR}/ut-containers-manager/libvirt-config/console1-dbus.xml @ONLY) +CONFIGURE_FILE(ut-containers-manager/libvirt-config/console2-dbus.xml.in + ${CMAKE_BINARY_DIR}/ut-containers-manager/libvirt-config/console2-dbus.xml @ONLY) +CONFIGURE_FILE(ut-containers-manager/libvirt-config/console3-dbus.xml.in + ${CMAKE_BINARY_DIR}/ut-containers-manager/libvirt-config/console3-dbus.xml @ONLY) +FILE(GLOB manager_admin_CONF_GEN ${CMAKE_BINARY_DIR}/ut-containers-manager/libvirt-config/*.xml) + CONFIGURE_FILE(ut-container/libvirt-config/test-dbus.xml.in ${CMAKE_BINARY_DIR}/ut-container/libvirt-config/test-dbus.xml @ONLY) FILE(GLOB container_admin_CONF_GEN ${CMAKE_BINARY_DIR}/ut-container/libvirt-config/*.xml) @@ -74,6 +82,8 @@ INSTALL(FILES ${manager_container_CONF} DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/containers) INSTALL(FILES ${manager_admin_CONF} DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/libvirt-config) +INSTALL(FILES ${manager_admin_CONF_GEN} + DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-containers-manager/libvirt-config) INSTALL(FILES ${container_CONF} DESTINATION ${SC_TEST_CONFIG_INSTALL_DIR}/server/ut-container) diff --git a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in similarity index 78% rename from tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml rename to tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in index 3df8595..7aea75f 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml +++ b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in @@ -6,7 +6,7 @@ exe /bin/dbus-daemon --nofork - --config-file=/usr/share/security-containers/tests/server/ut-containers-manager/ut-dbus.conf + --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --address=unix:path=/tmp/ut-containers-manager/console1-dbus/dbus/system_bus_socket diff --git a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in similarity index 78% rename from tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml rename to tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in index 0fc7e83..0336d3d 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml +++ b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in @@ -6,7 +6,7 @@ exe /bin/dbus-daemon --nofork - --config-file=/usr/share/security-containers/tests/server/ut-containers-manager/ut-dbus.conf + --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --address=unix:path=/tmp/ut-containers-manager/console2-dbus/dbus/system_bus_socket diff --git a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in similarity index 78% rename from tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml rename to tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in index a341cb3..0b65ad4 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml +++ b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in @@ -6,7 +6,7 @@ exe /bin/dbus-daemon --nofork - --config-file=/usr/share/security-containers/tests/server/ut-containers-manager/ut-dbus.conf + --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --address=unix:path=/tmp/ut-containers-manager/console3-dbus/dbus/system_bus_socket -- 2.7.4 From 1292f6ebd110df620e45c94d923d33fc7a27fca3 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Thu, 12 Jun 2014 10:12:41 +0200 Subject: [PATCH 05/16] A DBUS API to move the files between containers [Bug/Feature] Add an ability for a container to request a file move to another container. Some minor fixes here and there. Added missing tests for utils/fs. A little revamp of DbusAccessory in ut-cm tests. [Cause] N/A [Solution] Implement a DBUS API and a simple move implementation. [Verification] Build, install, run tests, run server. Change-Id: I881f7b6079e38e3dd43d6fe34360457172047c2c Signed-off-by: Lukasz Pawelczyk --- common/config.hpp | 7 + common/utils/fs.cpp | 59 +++++- common/utils/fs.hpp | 12 ++ container-daemon/CMakeLists.txt | 2 +- packaging/security-containers.spec | 4 +- server/CMakeLists.txt | 1 + server/configs/containers/business.conf | 4 +- server/configs/containers/private.conf | 4 +- server/configs/daemon.conf | 1 + server/configs/libvirt-config/business.xml | 2 + server/configs/libvirt-config/private.xml | 2 + server/container-config.hpp | 17 +- server/container-connection.cpp | 15 ++ server/container-connection.hpp | 11 ++ server/container-dbus-definitions.hpp | 14 ++ server/container.cpp | 31 ++- server/container.hpp | 26 +++ server/containers-manager-config.hpp | 16 +- server/containers-manager.cpp | 109 +++++++++- server/containers-manager.hpp | 4 + .../ut-container-admin/containers/buggy.conf.in | 4 +- .../ut-container-admin/containers/missing.conf | 4 +- .../containers/test-no-shutdown.conf.in | 4 +- .../ut-container-admin/containers/test.conf.in | 4 +- .../configs/ut-container/containers/buggy.conf | 4 +- .../configs/ut-container/containers/test-dbus.conf | 4 +- .../configs/ut-container/containers/test.conf | 4 +- .../ut-containers-manager/buggy-daemon.conf | 1 + .../buggy-default-daemon.conf | 3 +- .../buggy-foreground-daemon.conf | 1 + .../containers/console1-dbus.conf | 4 +- .../ut-containers-manager/containers/console1.conf | 4 +- .../containers/console2-dbus.conf | 4 +- .../ut-containers-manager/containers/console2.conf | 4 +- .../containers/console3-dbus.conf | 4 +- .../ut-containers-manager/containers/console3.conf | 4 +- .../libvirt-config/console1-dbus.xml.in | 2 +- .../libvirt-config/console2-dbus.xml.in | 2 +- .../libvirt-config/console3-dbus.xml.in | 2 +- .../configs/ut-containers-manager/test-daemon.conf | 1 + .../ut-containers-manager/test-dbus-daemon.conf | 5 +- .../ut-network-admin/containers/buggy.conf.in | 4 +- .../ut-network-admin/containers/missing.conf | 4 +- .../ut-network-admin/containers/test.conf.in | 4 +- .../server/configs/ut-server/buggy-daemon.conf | 1 + .../configs/ut-server/containers/container1.conf | 4 +- .../configs/ut-server/containers/container2.conf | 4 +- .../configs/ut-server/containers/container3.conf | 4 +- .../server/configs/ut-server/test-daemon.conf | 1 + tests/unit_tests/server/ut-containers-manager.cpp | 219 ++++++++++++++++----- tests/unit_tests/utils/ut-fs.cpp | 83 ++++++++ 51 files changed, 636 insertions(+), 102 deletions(-) diff --git a/common/config.hpp b/common/config.hpp index 2ed11a6..0721de4 100644 --- a/common/config.hpp +++ b/common/config.hpp @@ -67,4 +67,11 @@ #define BOOST_PP_VARIADICS 1 #endif +// This has to be defined always when the boost has not been compiled +// using C++11. Headers detect that you are compiling using C++11 and +// blindly and wrongly assume that boost has been as well. +#ifndef BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_CXX11_SCOPED_ENUMS 1 +#endif + #endif // COMMON_CONFIG_HPP diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index 2bae7d6..421ff54 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -28,6 +28,7 @@ #include "utils/paths.hpp" #include "utils/exception.hpp" +#include #include #include #include @@ -135,20 +136,66 @@ bool umount(const std::string& path) bool isMountPoint(const std::string& path, bool& result) { - struct stat stat, parentStat; std::string parentPath = dirName(path); + bool newResult; + bool ret = hasSameMountPoint(path, parentPath, newResult); - if (::stat(path.c_str(), &stat)) { - LOGD("Failed to get stat of " << path << ": " << strerror(errno)); + result = !newResult; + return ret; +} + +bool hasSameMountPoint(const std::string& path1, const std::string& path2, bool& result) +{ + struct stat s1, s2; + + if (::stat(path1.c_str(), &s1)) { + LOGD("Failed to get stat of " << path1 << ": " << strerror(errno)); return false; } - if (::stat(parentPath.c_str(), &parentStat)) { - LOGD("Failed to get stat of " << parentPath << ": " << strerror(errno)); + if (::stat(path2.c_str(), &s2)) { + LOGD("Failed to get stat of " << path2 << ": " << strerror(errno)); return false; } - result = (stat.st_dev != parentStat.st_dev); + result = (s1.st_dev == s2.st_dev); + return true; +} + +bool moveFile(const std::string& src, const std::string& dst) +{ + bool bResult; + + namespace fs = boost::filesystem; + boost::system::error_code error; + + // The destination has to be a full path (including a file name) + // so it doesn't exist yet, we need to check upper level dir instead. + if (!hasSameMountPoint(src, dirName(dst), bResult)) { + LOGE("Failed to check the files' mount points"); + return false; + } + + if (bResult) { + fs::rename(src, dst, error); + if (error) { + LOGE("Failed to rename the file: " << error); + return false; + } + } else { + fs::copy_file(src, dst, error); + if (error) { + LOGE("Failed to copy the file: " << error); + return false; + } + fs::remove(src, error); + if (error) { + LOGE("Failed to remove the file: " << error); + fs::remove(dst, error); + return false; + } + } + return true; } diff --git a/common/utils/fs.hpp b/common/utils/fs.hpp index 8312393..9e69cbd 100644 --- a/common/utils/fs.hpp +++ b/common/utils/fs.hpp @@ -73,6 +73,18 @@ bool umount(const std::string& path); */ bool isMountPoint(const std::string& path, bool& result); +/** + * Checks whether the given paths are under the same mount point + */ +bool hasSameMountPoint(const std::string& path1, const std::string& path2, bool& result); + +/** + * Moves the file either by rename if under the same mount point + * or by copy&delete if under a different one. + * The destination has to be a full path including file name. + */ +bool moveFile(const std::string& src, const std::string& dst); + } // namespace utils } // namespace security_containers diff --git a/container-daemon/CMakeLists.txt b/container-daemon/CMakeLists.txt index d997ab7..3408f43 100644 --- a/container-daemon/CMakeLists.txt +++ b/container-daemon/CMakeLists.txt @@ -29,7 +29,7 @@ ADD_EXECUTABLE(${CONTAINER_DAEMON_CODENAME} ${project_SRCS} ${common_SRCS}) ## Link libraries ############################################################## -FIND_PACKAGE (Boost COMPONENTS program_options) +FIND_PACKAGE (Boost COMPONENTS program_options system filesystem) PKG_CHECK_MODULES(CONTAINER_DAEMON_DEPS REQUIRED gio-2.0 libsystemd-journal) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec index d6bcc2c..3afbdd1 100644 --- a/packaging/security-containers.spec +++ b/packaging/security-containers.spec @@ -8,6 +8,7 @@ License: Apache-2.0 Group: Security/Other Summary: Daemon for managing containers BuildRequires: cmake +BuildRequires: boost-devel BuildRequires: libvirt-devel BuildRequires: libjson-devel BuildRequires: pkgconfig(glib-2.0) @@ -123,8 +124,6 @@ Development package including the header files for the client library Summary: Security Containers Containers Daemon Group: Security/Other Requires: security-containers = %{version}-%{release} -BuildRequires: pkgconfig(glib-2.0) -BuildRequires: pkgconfig(libsystemd-journal) %description container-daemon Daemon running inside every container. @@ -144,7 +143,6 @@ Requires: security-containers = %{version}-%{release} Requires: security-containers-client = %{version}-%{release} Requires: python Requires: boost-test -BuildRequires: boost-devel %description tests Unit tests for both: server and client and integration tests. diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index b93b010..595ec72 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -29,6 +29,7 @@ ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS} ${common_SRCS}) ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS program_options system filesystem regex) + PKG_CHECK_MODULES(SERVER_DEPS REQUIRED libvirt libvirt-glib-1.0 json gio-2.0 libsystemd-journal) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${SERVER_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) diff --git a/server/configs/containers/business.conf b/server/configs/containers/business.conf index 8468e2c..fbd1bbb 100644 --- a/server/configs/containers/business.conf +++ b/server/configs/containers/business.conf @@ -4,5 +4,7 @@ "privilege" : 1, "config" : "../libvirt-config/business.xml", "networkConfig" : "../libvirt-config/business-network.xml", - "runMountPoint" : "/var/run/containers/business/run" + "runMountPoint" : "/var/run/containers/business/run", + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*" ] } diff --git a/server/configs/containers/private.conf b/server/configs/containers/private.conf index 444638f..a12a847 100644 --- a/server/configs/containers/private.conf +++ b/server/configs/containers/private.conf @@ -4,5 +4,7 @@ "privilege" : 10, "config" : "../libvirt-config/private.xml", "networkConfig" : "../libvirt-config/private-network.xml", - "runMountPoint" : "/var/run/containers/private/run" + "runMountPoint" : "/var/run/containers/private/run", + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*" ] } diff --git a/server/configs/daemon.conf b/server/configs/daemon.conf index 591e0b7..94af879 100644 --- a/server/configs/daemon.conf +++ b/server/configs/daemon.conf @@ -1,5 +1,6 @@ { "containerConfigs" : ["containers/private.conf", "containers/business.conf" ], + "containersPath" : "/opt/usr/containers", "foregroundId" : "private", "defaultId" : "private", "inputConfig" : {"enabled" : true, diff --git a/server/configs/libvirt-config/business.xml b/server/configs/libvirt-config/business.xml index 85e9a77..deaf000 100644 --- a/server/configs/libvirt-config/business.xml +++ b/server/configs/libvirt-config/business.xml @@ -101,11 +101,13 @@ + + diff --git a/server/configs/libvirt-config/private.xml b/server/configs/libvirt-config/private.xml index 7561bab..532cd76 100644 --- a/server/configs/libvirt-config/private.xml +++ b/server/configs/libvirt-config/private.xml @@ -101,11 +101,13 @@ + + diff --git a/server/container-config.hpp b/server/container-config.hpp index 2c12363..d5a3038 100644 --- a/server/container-config.hpp +++ b/server/container-config.hpp @@ -29,6 +29,7 @@ #include "config/fields.hpp" #include +#include namespace security_containers { @@ -67,6 +68,18 @@ struct ContainerConfig { */ std::string runMountPoint; + /** + * When you move a file out of the container (by move request) + * its path must match at least one of the regexps in this vector. + */ + std::vector permittedToSend; + + /** + * When you move a file to the container (by move request) + * its path must match at least one of the regexps in this vector. + */ + std::vector permittedToRecv; + CONFIG_REGISTER ( privilege, @@ -74,7 +87,9 @@ struct ContainerConfig { networkConfig, cpuQuotaForeground, cpuQuotaBackground, - runMountPoint + runMountPoint, + permittedToSend, + permittedToRecv ) }; diff --git a/server/container-connection.cpp b/server/container-connection.cpp index cf541f7..3ef2dd7 100644 --- a/server/container-connection.cpp +++ b/server/container-connection.cpp @@ -140,6 +140,12 @@ void ContainerConnection::setDisplayOffCallback(const DisplayOffCallback& callba mDisplayOffCallback = callback; } +void ContainerConnection::setFileMoveRequestCallback( + const FileMoveRequestCallback& callback) +{ + mFileMoveRequestCallback = callback; +} + void ContainerConnection::onMessageCall(const std::string& objectPath, const std::string& interface, const std::string& methodName, @@ -159,6 +165,15 @@ void ContainerConnection::onMessageCall(const std::string& objectPath, result.setVoid(); } } + + if (methodName == api::METHOD_FILE_MOVE_REQUEST) { + const gchar* destination = NULL; + const gchar* path = NULL; + g_variant_get(parameters, "(&s&s)", &destination, &path); + if (mFileMoveRequestCallback) { + mFileMoveRequestCallback(destination, path, result); + } + } } void ContainerConnection::onSignalReceived(const std::string& senderBusName, diff --git a/server/container-connection.hpp b/server/container-connection.hpp index e0b2467..2f429ce 100644 --- a/server/container-connection.hpp +++ b/server/container-connection.hpp @@ -50,6 +50,11 @@ public: const std::string& message )> NotifyActiveContainerCallback; + typedef std::function FileMoveRequestCallback; + /** * Register notification request callback */ @@ -60,6 +65,11 @@ public: */ void setDisplayOffCallback(const DisplayOffCallback& callback); + /* + * Register file move request callback + */ + void setFileMoveRequestCallback(const FileMoveRequestCallback& callback); + /** * Send notification signal to this container */ @@ -76,6 +86,7 @@ private: OnNameLostCallback mOnNameLostCallback; NotifyActiveContainerCallback mNotifyActiveContainerCallback; DisplayOffCallback mDisplayOffCallback; + FileMoveRequestCallback mFileMoveRequestCallback; void onNameAcquired(); void onNameLost(); diff --git a/server/container-dbus-definitions.hpp b/server/container-dbus-definitions.hpp index 7fec0db..118a348 100644 --- a/server/container-dbus-definitions.hpp +++ b/server/container-dbus-definitions.hpp @@ -37,8 +37,17 @@ const std::string OBJECT_PATH = "/org/tizen/containers"; const std::string INTERFACE = "org.tizen.containers.manager"; const std::string METHOD_NOTIFY_ACTIVE_CONTAINER = "NotifyActiveContainer"; +const std::string METHOD_FILE_MOVE_REQUEST = "FileMoveRequest"; const std::string SIGNAL_NOTIFICATION = "Notification"; +const std::string FILE_MOVE_DESTINATION_NOT_FOUND = "FILE_MOVE_DESTINATION_NOT_FOUND"; +const std::string FILE_MOVE_WRONG_DESTINATION = "FILE_MOVE_WRONG_DESTINATION"; +const std::string FILE_MOVE_NO_PERMISSIONS_SEND = "FILE_MOVE_NO_PERMISSIONS_SEND"; +const std::string FILE_MOVE_NO_PERMISSIONS_RECEIVE = "FILE_MOVE_NO_PERMISSIONS_RECEIVE"; +const std::string FILE_MOVE_FAILED = "FILE_MOVE_FAILED"; +const std::string FILE_MOVE_SUCCEEDED = "FILE_MOVE_SUCCEEDED"; + + const std::string DEFINITION = "" " " @@ -46,6 +55,11 @@ const std::string DEFINITION = " " " " " " + " " + " " + " " + " " + " " " " " " " " diff --git a/server/container.cpp b/server/container.cpp index 2d7114f..ea45b39 100644 --- a/server/container.cpp +++ b/server/container.cpp @@ -54,6 +54,13 @@ Container::Container(const std::string& containerConfigPath) { config::loadFromFile(containerConfigPath, mConfig); + for (std::string r: mConfig.permittedToSend) { + mPermittedToSend.push_back(boost::regex(r)); + } + for (std::string r: mConfig.permittedToRecv) { + mPermittedToRecv.push_back(boost::regex(r)); + } + const std::string baseConfigPath = utils::dirName(containerConfigPath); mConfig.config = fs::absolute(mConfig.config, baseConfigPath).string(); mConfig.networkConfig = fs::absolute(mConfig.networkConfig, baseConfigPath).string(); @@ -79,6 +86,16 @@ Container::~Container() } } +const std::vector& Container::getPermittedToSend() const +{ + return mPermittedToSend; +} + +const std::vector& Container::getPermittedToRecv() const +{ + return mPermittedToRecv; +} + const std::string& Container::getId() const { Lock lock(mReconnectMutex); @@ -104,6 +121,9 @@ void Container::start() if (mDisplayOffCallback) { mConnection->setDisplayOffCallback(mDisplayOffCallback); } + if (mFileMoveCallback) { + mConnection->setFileMoveRequestCallback(mFileMoveCallback); + } // Send to the background only after we're connected, // otherwise it'd take ages. @@ -207,7 +227,6 @@ void Container::setNotifyActiveContainerCallback(const NotifyActiveContainerCall if (mConnection) { mConnection->setNotifyActiveContainerCallback(mNotifyCallback); } - } void Container::sendNotification(const std::string& container, @@ -232,5 +251,15 @@ void Container::setDisplayOffCallback(const DisplayOffCallback& callback) } } +void Container::setFileMoveRequestCallback(const FileMoveRequestCallback& callback) +{ + Lock lock(mReconnectMutex); + + mFileMoveCallback = callback; + if (mConnection) { + mConnection->setFileMoveRequestCallback(callback); + } +} + } // namespace security_containers diff --git a/server/container.hpp b/server/container.hpp index 5dbccad..7cc0c5b 100644 --- a/server/container.hpp +++ b/server/container.hpp @@ -35,6 +35,7 @@ #include #include #include +#include namespace security_containers { @@ -49,6 +50,21 @@ public: typedef ContainerConnection::NotifyActiveContainerCallback NotifyActiveContainerCallback; typedef ContainerConnection::DisplayOffCallback DisplayOffCallback; + typedef ContainerConnection::FileMoveRequestCallback FileMoveRequestCallback; + + /** + * Returns a vector of regexps defining files permitted to be + * send to other containers using file move functionality + */ + const std::vector& getPermittedToSend() const; + + /** + * Returns a vector of regexps defining files permitted to be + * send to other containers using file move functionality + */ + const std::vector& getPermittedToRecv() const; + + // ContainerAdmin API /** * Get the container id @@ -109,6 +125,8 @@ public: */ bool isPaused(); + // ContainerConnection API + /** * Register notification request callback */ @@ -130,8 +148,15 @@ public: const std::string& application, const std::string& message); + /** + * Register file move request callback + */ + void setFileMoveRequestCallback(const FileMoveRequestCallback& callback); + private: ContainerConfig mConfig; + std::vector mPermittedToSend; + std::vector mPermittedToRecv; std::unique_ptr mConnectionTransport; std::unique_ptr mNetworkAdmin; std::unique_ptr mAdmin; @@ -140,6 +165,7 @@ private: mutable std::recursive_mutex mReconnectMutex; NotifyActiveContainerCallback mNotifyCallback; DisplayOffCallback mDisplayOffCallback; + FileMoveRequestCallback mFileMoveCallback; void onNameLostCallback(); void reconnectHandler(); diff --git a/server/containers-manager-config.hpp b/server/containers-manager-config.hpp index 9f881c1..c890880 100644 --- a/server/containers-manager-config.hpp +++ b/server/containers-manager-config.hpp @@ -41,11 +41,6 @@ const std::string CONTAINERS_MANAGER_CONFIG_PATH = "/etc/security-containers/con struct ContainersManagerConfig { /** - * Parameters describing input device used to switch between containers - */ - InputConfig inputConfig; - - /** * List of containers' configs that we manage. * File paths can be relative to the ContainerManager config file. */ @@ -61,11 +56,22 @@ struct ContainersManagerConfig { */ std::string defaultId; + /** + * A path where the containers mount points reside. + */ + std::string containersPath; + + /* + * Parameters describing input device used to switch between containers + */ + InputConfig inputConfig; + CONFIG_REGISTER ( containerConfigs, foregroundId, defaultId, + containersPath, inputConfig ) }; diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp index 13ee3d4..44539da 100644 --- a/server/containers-manager.cpp +++ b/server/containers-manager.cpp @@ -24,6 +24,7 @@ #include "config.hpp" +#include "container-dbus-definitions.hpp" #include "containers-manager.hpp" #include "container-admin.hpp" #include "exception.hpp" @@ -32,6 +33,8 @@ #include "log/logger.hpp" #include "config/manager.hpp" +#include +#include #include #include #include @@ -40,6 +43,21 @@ namespace security_containers { +namespace { + +bool regexMatchVector(const std::string& str, const std::vector& v) +{ + for (const boost::regex& toMatch: v) { + if (boost::regex_match(str, toMatch)) { + return true; + } + } + + return false; +} + +} // namespace + ContainersManager::ContainersManager(const std::string& managerConfigPath): mDetachOnExit(false) { LOGD("Instantiating ContainersManager object..."); @@ -60,14 +78,13 @@ ContainersManager::ContainersManager(const std::string& managerConfigPath): mDet std::string id = c->getId(); using namespace std::placeholders; c->setNotifyActiveContainerCallback(bind(&ContainersManager::notifyActiveContainerHandler, - this, - id, - _1, - _2)); + this, id, _1, _2)); c->setDisplayOffCallback(bind(&ContainersManager::displayOffHandler, - this, - id)); + this, id)); + + c->setFileMoveRequestCallback(std::bind(&ContainersManager::handleContainerMoveFileRequest, + this, id, _1, _2, _3)); mContainers.insert(ContainerMap::value_type(id, std::move(c))); } @@ -210,4 +227,84 @@ void ContainersManager::displayOffHandler(const std::string& /*caller*/) focus(mConfig.defaultId); } +void ContainersManager::handleContainerMoveFileRequest(const std::string& srcContainerId, + const std::string& dstContainerId, + const std::string& path, + dbus::MethodResultBuilder& result) +{ + // TODO: this implementation is only a placeholder. + // There are too many unanswered questions and security concerns: + // 1. What about mount namespace, host might not see the source/destination + // file. The file might be a different file from a host perspective. + // 2. Copy vs move (speed and security concerns over already opened FDs) + // 3. Access to source and destination files - DAC, uid/gig + // 4. Access to source and destintation files - MAC, smack + // 5. Destination file uid/gid assignment + // 6. Destination file smack label assignment + // 7. Verifiability of the source path + + // NOTE: other possible implementations include: + // 1. Sending file descriptors opened directly in each container through DBUS + // using something like g_dbus_message_set_unix_fd_list() + // 2. SCS forking and calling setns(MNT) in each container and opening files + // by itself, then passing FDs to the main process + // Now when the main process has obtained FDs (by either of those methods) + // it can do the copying by itself. + + LOGI("File move requested\n" + << "src: " << srcContainerId << "\n" + << "dst: " << dstContainerId << "\n" + << "path: " << path); + + ContainerMap::const_iterator srcIter = mContainers.find(srcContainerId); + if (srcIter == mContainers.end()) { + LOGE("Source container '" << srcContainerId << "' not found"); + return; + } + Container& srcContainer = *srcIter->second; + + ContainerMap::const_iterator dstIter = mContainers.find(dstContainerId); + if (dstIter == mContainers.end()) { + LOGE("Destination container '" << dstContainerId << "' not found"); + result.set(g_variant_new("(s)", api::FILE_MOVE_DESTINATION_NOT_FOUND.c_str())); + return; + } + Container& dstContanier = *dstIter->second; + + if (srcContainerId == dstContainerId) { + LOGE("Cannot send a file to yourself"); + result.set(g_variant_new("(s)", api::FILE_MOVE_WRONG_DESTINATION.c_str())); + return; + } + + if (!regexMatchVector(path, srcContainer.getPermittedToSend())) { + LOGE("Source container has no permissions to send the file: " << path); + result.set(g_variant_new("(s)", api::FILE_MOVE_NO_PERMISSIONS_SEND.c_str())); + return; + } + + if (!regexMatchVector(path, dstContanier.getPermittedToRecv())) { + LOGE("Destination container has no permissions to receive the file: " << path); + result.set(g_variant_new("(s)", api::FILE_MOVE_NO_PERMISSIONS_RECEIVE.c_str())); + return; + } + + namespace fs = boost::filesystem; + std::string srcPath = fs::absolute(srcContainerId, mConfig.containersPath).string() + path; + std::string dstPath = fs::absolute(dstContainerId, mConfig.containersPath).string() + path; + + if (!utils::moveFile(srcPath, dstPath)) { + LOGE("Failed to move the file: " << path); + result.set(g_variant_new("(s)", api::FILE_MOVE_FAILED.c_str())); + } else { + result.set(g_variant_new("(s)", api::FILE_MOVE_SUCCEEDED.c_str())); + try { + dstContanier.sendNotification(srcContainerId, path, api::FILE_MOVE_SUCCEEDED); + } catch (ServerException&) { + LOGE("Notification to '" << dstContainerId << "' has not been sent"); + } + } +} + + } // namespace security_containers diff --git a/server/containers-manager.hpp b/server/containers-manager.hpp index 316e7bb..1a1af88 100644 --- a/server/containers-manager.hpp +++ b/server/containers-manager.hpp @@ -86,6 +86,10 @@ private: const std::string& appliaction, const std::string& message); void displayOffHandler(const std::string& caller); + void handleContainerMoveFileRequest(const std::string& srcContainerId, + const std::string& dstContainerId, + const std::string& path, + dbus::MethodResultBuilder& result); }; diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in index 8617125..e06bf63 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in @@ -4,5 +4,7 @@ "networkConfig" : "", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf b/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf index 9add4c3..55d6852 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf @@ -4,5 +4,7 @@ "networkConfig" : "", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in index a7bccd0..6d01a50 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in @@ -4,5 +4,7 @@ "networkConfig" : "", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in index 0ad824e..518aa4c 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in @@ -4,5 +4,7 @@ "networkConfig" : "", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-container/containers/buggy.conf b/tests/unit_tests/server/configs/ut-container/containers/buggy.conf index fdb3ce8..d5ccd1e 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/buggy.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/buggy.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf index f4b38f9..fde05d8 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-container" + "runMountPoint" : "/tmp/ut-container", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-container/containers/test.conf b/tests/unit_tests/server/configs/ut-container/containers/test.conf index 458bca4..e1769c3 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/test.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/test.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf index a403aa8..8e89f50 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf @@ -2,6 +2,7 @@ "containerConfigs" : ["containers/console1.conf", "missing/file/path/missing.conf", "containers/console3.conf"], "foregroundId" : "ut-containers-manager-console1", "defaultId" : "ut-containers-manager-console1", + "containersPath" : "/tmp", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf index 39d56df..51b2bbd 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf @@ -1,7 +1,8 @@ { - "containerConfigs" : ["containers/console1-dbus.conf", "containers/console2-dbus.conf", "containers/console3-dbus.conf"], + "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"], "foregroundId" : "ut-containers-manager-console1", "defaultId" : "in_no_way_there_is_a_valid_id_here", + "containersPath" : "/tmp", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf index e12964a..c62daad 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf @@ -2,6 +2,7 @@ "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"], "foregroundId" : "this_id_does_not_exist", "defaultId" : "ut-containers-manager-console1", + "containersPath" : "/tmp", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf index fc12fec..55dfeb5 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network1.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-containers-manager/console1-dbus" + "runMountPoint" : "/tmp/ut-containers-manager/console1-dbus", + "permittedToSend" : [ "/tmp/.*", "/etc/secret2" ], + "permittedToRecv" : [ "/tmp/.*" ] } diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf index 47bbf5c..61668c8 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network1.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*" ] } diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf index 41988e6..713cb02 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network2.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-containers-manager/console2-dbus" + "runMountPoint" : "/tmp/ut-containers-manager/console2-dbus", + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*", "/etc/secret1" ] } diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf index 3bf1623..10e5cef 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network2.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*" ] } diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf index 8ebdfaa..70ff251 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network3.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "/tmp/ut-containers-manager/console3-dbus" + "runMountPoint" : "/tmp/ut-containers-manager/console3-dbus", + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*" ] } diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf index 0a90aff..8ccf55b 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network3.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [ "/tmp/.*" ], + "permittedToRecv" : [ "/tmp/.*" ] } diff --git a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in index 7aea75f..6d24978 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in +++ b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in @@ -1,5 +1,5 @@ - ut-containers-manager-console1 + ut-containers-manager-console1-dbus 58184009-b278-4d01-975d-708393690084 102400 diff --git a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in index 0336d3d..5fe2996 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in +++ b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in @@ -1,5 +1,5 @@ - ut-containers-manager-console2 + ut-containers-manager-console2-dbus 3d18323e-4ada-4a1b-a907-836701891306 102400 diff --git a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in index 0b65ad4..be4d618 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in +++ b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in @@ -1,5 +1,5 @@ - ut-containers-manager-console3 + ut-containers-manager-console3-dbus 71cb8511-7474-4e90-865a-3360b7f77254 102400 diff --git a/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf index 4ffe017..7908dea 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf @@ -2,6 +2,7 @@ "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"], "foregroundId" : "ut-containers-manager-console1", "defaultId" : "ut-containers-manager-console1", + "containersPath" : "/tmp", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf index ae59483..5466f3d 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf @@ -2,8 +2,9 @@ "containerConfigs" : ["containers/console1-dbus.conf", "containers/console2-dbus.conf", "containers/console3-dbus.conf"], - "foregroundId" : "ut-containers-manager-console1", - "defaultId" : "ut-containers-manager-console1", + "foregroundId" : "ut-containers-manager-console1-dbus", + "defaultId" : "ut-containers-manager-console1-dbus", + "containersPath" : "/tmp", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in b/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in index 1078859..be3f7c1 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in @@ -4,5 +4,7 @@ "networkConfig" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-network-admin/libvirt-config/buggy-network.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf b/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf index cc31322..f418503 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf @@ -4,5 +4,7 @@ "networkConfig" : "", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in b/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in index f680989..771a93b 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in @@ -4,5 +4,7 @@ "networkConfig" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-network-admin/libvirt-config/network.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf index 47b4450..41cfc2f 100644 --- a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf +++ b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf @@ -1,5 +1,6 @@ { "containerConfigs" : ["containers/container1.conf", "missing/file/path/missing.conf", "containers/container3.conf"], + "containersPath" : "/tmp", "foregroundId" : "ut-server-container1", "defaultId" : "ut-server-container1", "inputConfig" : {"enabled" : false, diff --git a/tests/unit_tests/server/configs/ut-server/containers/container1.conf b/tests/unit_tests/server/configs/ut-server/containers/container1.conf index 0b18659..952decf 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container1.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container1.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network1.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-server/containers/container2.conf b/tests/unit_tests/server/configs/ut-server/containers/container2.conf index b5bab4d..4e6de09 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container2.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container2.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network2.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-server/containers/container3.conf b/tests/unit_tests/server/configs/ut-server/containers/container3.conf index 3a1ae36..9170c54 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container3.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container3.conf @@ -4,5 +4,7 @@ "networkConfig" : "../libvirt-config/network3.xml", "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, - "runMountPoint" : "" + "runMountPoint" : "", + "permittedToSend" : [], + "permittedToRecv" : [] } diff --git a/tests/unit_tests/server/configs/ut-server/test-daemon.conf b/tests/unit_tests/server/configs/ut-server/test-daemon.conf index 360bab7..8935030 100644 --- a/tests/unit_tests/server/configs/ut-server/test-daemon.conf +++ b/tests/unit_tests/server/configs/ut-server/test-daemon.conf @@ -1,5 +1,6 @@ { "containerConfigs" : ["containers/container1.conf", "containers/container2.conf", "containers/container3.conf"], + "containersPath" : "/tmp", "foregroundId" : "ut-server-container1", "defaultId" : "ut-server-container1", "inputConfig" : {"enabled" : false, diff --git a/tests/unit_tests/server/ut-containers-manager.cpp b/tests/unit_tests/server/ut-containers-manager.cpp index 61eea40..0182cb8 100644 --- a/tests/unit_tests/server/ut-containers-manager.cpp +++ b/tests/unit_tests/server/ut-containers-manager.cpp @@ -37,14 +37,17 @@ #include "utils/glib-loop.hpp" #include "config/exception.hpp" #include "utils/latch.hpp" +#include "utils/fs.hpp" +#include +#include #include #include #include #include #include #include - +#include using namespace security_containers; using namespace security_containers::config; @@ -63,12 +66,13 @@ const int EVENT_TIMEOUT = 5000; const int TEST_DBUS_CONNECTION_CONTAINERS_COUNT = 3; const std::string PREFIX_CONSOLE_NAME = "ut-containers-manager-console"; const std::string TEST_APP_NAME = "testapp"; -const std::string TEST_MESSGAE = "testmessage"; +const std::string TEST_MESSAGE = "testmessage"; +const std::string FILE_CONTENT = "File content\n" + "Line 1\n" + "Line 2\n"; class DbusAccessory { public: - std::vector mReceivedSignalsSource; - DbusAccessory(int id) : mId(id), mClient(DbusConnection::create(acquireAddress())), @@ -110,12 +114,9 @@ public: mNameCondition.notify_one(); } - void signalSubscribe(Latch& referenceLatch) + void signalSubscribe(const DbusConnection::SignalCallback& callback) { - using namespace std::placeholders; - mClient->signalSubscribe(std::bind(&DbusAccessory::handler, - this, std::ref(referenceLatch), _1, _2, _3, _4, _5), - api::BUS_NAME); + mClient->signalSubscribe(callback, api::BUS_NAME); } void emitSignal(const std::string& objectPath, @@ -126,9 +127,9 @@ public: mClient->emitSignal(objectPath, interface, name, parameters); } - void callMethod() + void callMethodNotify() { - GVariant* parameters = g_variant_new("(ss)", TEST_APP_NAME.c_str(), TEST_MESSGAE.c_str()); + GVariant* parameters = g_variant_new("(ss)", TEST_APP_NAME.c_str(), TEST_MESSAGE.c_str()); mClient->callMethod(api::BUS_NAME, api::OBJECT_PATH, api::INTERFACE, @@ -137,9 +138,19 @@ public: "()"); } - std::string getContainerName() const + std::string callMethodMove(const std::string& dest, const std::string& path) { - return PREFIX_CONSOLE_NAME + std::to_string(mId); + GVariant* parameters = g_variant_new("(ss)", dest.c_str(), path.c_str()); + GVariantPtr result = mClient->callMethod(api::BUS_NAME, + api::OBJECT_PATH, + api::INTERFACE, + api::METHOD_FILE_MOVE_REQUEST, + parameters, + "(s)"); + + const gchar* retcode = NULL; + g_variant_get(result.get(), "(&s)", &retcode); + return std::string(retcode); } private: @@ -155,29 +166,6 @@ private: return "unix:path=/tmp/ut-containers-manager/console" + std::to_string(mId) + "-dbus/dbus/system_bus_socket"; } - - void handler(Latch& referenceLatch, - const std::string& /*senderBusName*/, - const std::string& objectPath, - const std::string& interface, - const std::string& signalName, - GVariant* parameters) - { - if (objectPath == api::OBJECT_PATH && - interface == api::INTERFACE && - signalName == api::SIGNAL_NOTIFICATION && - g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) { - - const gchar* container = NULL; - const gchar* application = NULL; - const gchar* message = NULL; - g_variant_get(parameters, "(&s&s&s)", &container, &application, &message); - mReceivedSignalsSource.push_back(container); - if (application == TEST_APP_NAME && message == TEST_MESSGAE) { - referenceLatch.set(); - } - } - } }; @@ -262,36 +250,65 @@ BOOST_AUTO_TEST_CASE(FocusTest) BOOST_AUTO_TEST_CASE(NotifyActiveContainerTest) { - Latch signalReceivedLatch; - ContainersManager cm(TEST_DBUS_CONFIG_PATH); cm.startAll(); - std::vector< std::unique_ptr > dbuses; + std::map> dbuses; for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) { - dbuses.push_back(std::unique_ptr(new DbusAccessory(i))); + dbuses[i] = std::unique_ptr(new DbusAccessory(i)); } - for (auto& dbus : dbuses) { - dbus->signalSubscribe(signalReceivedLatch); + + Latch signalReceivedLatch; + std::map> signalReceivedSourcesMap; + auto handler = [](Latch& latch, + std::vector& receivedSignalSources, + const std::string& /*senderBusName*/, + const std::string& objectPath, + const std::string& interface, + const std::string& signalName, + GVariant* parameters) + { + if (objectPath == api::OBJECT_PATH && + interface == api::INTERFACE && + signalName == api::SIGNAL_NOTIFICATION && + g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) { + + const gchar* container = NULL; + const gchar* application = NULL; + const gchar* message = NULL; + g_variant_get(parameters, "(&s&s&s)", &container, &application, &message); + receivedSignalSources.push_back(container); + if (application == TEST_APP_NAME && message == TEST_MESSAGE) { + latch.set(); + } + } + }; + + using namespace std::placeholders; + for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) { + dbuses[i]->signalSubscribe(std::bind(handler, + std::ref(signalReceivedLatch), + std::ref(signalReceivedSourcesMap[i]), + _1, _2, _3, _4, _5)); } for (auto& dbus : dbuses) { - dbus->callMethod(); + dbus.second->callMethodNotify(); } BOOST_CHECK(signalReceivedLatch.waitForN(dbuses.size() - 1, EVENT_TIMEOUT)); BOOST_CHECK(signalReceivedLatch.empty()); //check if there are no signals that was received more than once - for (const auto& source : dbuses[0]->mReceivedSignalsSource) { - BOOST_CHECK_EQUAL(std::count(dbuses[0]->mReceivedSignalsSource.begin(), - dbuses[0]->mReceivedSignalsSource.end(), - source), 1); + for (const auto& source : signalReceivedSourcesMap[1]) { + BOOST_CHECK_EQUAL(std::count(signalReceivedSourcesMap[1].begin(), + signalReceivedSourcesMap[1].end(), + source), 1); } //check if all signals was received by active container - BOOST_CHECK_EQUAL(dbuses[0]->mReceivedSignalsSource.size(), dbuses.size() - 1); + BOOST_CHECK_EQUAL(signalReceivedSourcesMap[1].size(), dbuses.size() - 1); //check if no signals was received by inactive container - for (size_t i = 1; i < dbuses.size(); ++i) { - BOOST_CHECK(dbuses[i]->mReceivedSignalsSource.empty()); + for (size_t i = 2; i <= dbuses.size(); ++i) { + BOOST_CHECK(signalReceivedSourcesMap[i].empty()); } dbuses.clear(); @@ -315,13 +332,13 @@ BOOST_AUTO_TEST_CASE(DisplayOffTest) std::unique_lock Lock(Mutex); std::condition_variable Condition; auto cond = [&cm]() -> bool { - return cm.getRunningForegroundContainerId() == "ut-containers-manager-console1"; + return cm.getRunningForegroundContainerId() == "ut-containers-manager-console1-dbus"; }; for (auto& client : clients) { // TEST SWITCHING TO DEFAULT CONTAINER // focus non-default container - BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console3")); + BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console3-dbus")); // emit signal from dbus connection BOOST_REQUIRE_NO_THROW(client->emitSignal(fake_power_manager_api::OBJECT_PATH, @@ -334,4 +351,102 @@ BOOST_AUTO_TEST_CASE(DisplayOffTest) } } +BOOST_AUTO_TEST_CASE(MoveFileTest) +{ + ContainersManager cm(TEST_DBUS_CONFIG_PATH); + cm.startAll(); + + std::map> dbuses; + for (int i = 1; i <= 2; ++i) { + dbuses[i] = std::unique_ptr(new DbusAccessory(i)); + } + + Latch notificationLatch; + std::string notificationSource; + std::string notificationPath; + std::string notificationRetcode; + auto handler = [&](const std::string& /*senderBusName*/, + const std::string& objectPath, + const std::string& interface, + const std::string& signalName, + GVariant* parameters) + { + if (objectPath == api::OBJECT_PATH && + interface == api::INTERFACE && + signalName == api::SIGNAL_NOTIFICATION && + g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) { + + const gchar* source = NULL; + const gchar* path = NULL; + const gchar* retcode = NULL; + g_variant_get(parameters, "(&s&s&s)", &source, &path, &retcode); + + notificationSource = source; + notificationPath = path; + notificationRetcode = retcode; + notificationLatch.set(); + } + }; + + // subscribe the second (destination) container for notifications + dbuses.at(2)->signalSubscribe(handler); + + const std::string TMP = "/tmp"; + const std::string NO_PATH = "path_doesnt_matter_here"; + const std::string BUGGY_PATH = TMP + "/this_file_does_not_exist"; + const std::string BUGGY_CONTAINER = "this-container-does-not-exist"; + const std::string CONTAINER1 = "ut-containers-manager-console1-dbus"; + const std::string CONTAINER2 = "ut-containers-manager-console2-dbus"; + const std::string CONTAINER1PATH = TMP + "/" + CONTAINER1 + TMP; + const std::string CONTAINER2PATH = TMP + "/" + CONTAINER2 + TMP; + + // sending to a non existing container + BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(BUGGY_CONTAINER, NO_PATH), + api::FILE_MOVE_DESTINATION_NOT_FOUND); + BOOST_CHECK(notificationLatch.empty()); + + // sending to self + BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER1, NO_PATH), + api::FILE_MOVE_WRONG_DESTINATION); + BOOST_CHECK(notificationLatch.empty()); + + // no permission to send + BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER2, "/etc/secret1"), + api::FILE_MOVE_NO_PERMISSIONS_SEND); + BOOST_CHECK(notificationLatch.empty()); + + // no permission to receive + BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER2, "/etc/secret2"), + api::FILE_MOVE_NO_PERMISSIONS_RECEIVE); + BOOST_CHECK(notificationLatch.empty()); + + // non existing file + BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER2, BUGGY_PATH), + api::FILE_MOVE_FAILED); + BOOST_CHECK(notificationLatch.empty()); + + // a working scenario + namespace fs = boost::filesystem; + boost::system::error_code ec; + fs::remove_all(CONTAINER1PATH, ec); + fs::remove_all(CONTAINER2PATH, ec); + BOOST_REQUIRE(fs::create_directories(CONTAINER1PATH, ec)); + BOOST_REQUIRE(fs::create_directories(CONTAINER2PATH, ec)); + BOOST_REQUIRE(utils::saveFileContent(CONTAINER1PATH + "/file", FILE_CONTENT)); + + BOOST_CHECK_EQUAL(dbuses.at(1)->callMethodMove(CONTAINER2, TMP + "/file"), + api::FILE_MOVE_SUCCEEDED); + BOOST_CHECK(notificationLatch.wait(EVENT_TIMEOUT)); + BOOST_CHECK(notificationLatch.empty()); + BOOST_CHECK_EQUAL(notificationSource, CONTAINER1); + BOOST_CHECK_EQUAL(notificationPath, TMP + "/file"); + BOOST_CHECK_EQUAL(notificationRetcode, api::FILE_MOVE_SUCCEEDED); + BOOST_CHECK(!fs::exists(CONTAINER1PATH + "/file")); + BOOST_CHECK_EQUAL(utils::readFileContent(CONTAINER2PATH + "/file"), FILE_CONTENT); + + fs::remove_all(CONTAINER1PATH, ec); + fs::remove_all(CONTAINER2PATH, ec); +} + + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit_tests/utils/ut-fs.cpp b/tests/unit_tests/utils/ut-fs.cpp index adc8797..8f7c965 100644 --- a/tests/unit_tests/utils/ut-fs.cpp +++ b/tests/unit_tests/utils/ut-fs.cpp @@ -30,17 +30,34 @@ #include "utils/exception.hpp" #include +#include +#include BOOST_AUTO_TEST_SUITE(UtilsFSSuite) using namespace security_containers; using namespace security_containers::utils; +namespace { + const std::string FILE_PATH = SC_TEST_CONFIG_INSTALL_DIR "/utils/ut-fs/file.txt"; const std::string FILE_CONTENT = "File content\n" "Line 1\n" "Line 2\n"; const std::string BUGGY_FILE_PATH = "/some/missing/file/path/file.txt"; +const std::string TMP_PATH = "/tmp"; +const std::string FILE_PATH_RANDOM = + boost::filesystem::unique_path("/tmp/testFile-%%%%").string(); +const std::string MOUNT_POINT_RANDOM_1 = + boost::filesystem::unique_path("/tmp/mountPoint-%%%%").string(); +const std::string MOUNT_POINT_RANDOM_2 = + boost::filesystem::unique_path("/tmp/mountPoint-%%%%").string(); +const std::string FILE_NAME_RANDOM_1 = + boost::filesystem::unique_path("testFile-%%%%").string(); +const std::string FILE_NAME_RANDOM_2 = + boost::filesystem::unique_path("testFile-%%%%").string(); + +} // namespace BOOST_AUTO_TEST_CASE(ReadFileContentTest) { @@ -48,4 +65,70 @@ BOOST_AUTO_TEST_CASE(ReadFileContentTest) BOOST_CHECK_THROW(readFileContent(BUGGY_FILE_PATH), UtilsException); } +BOOST_AUTO_TEST_CASE(SaveFileContentTest) +{ + BOOST_REQUIRE(saveFileContent(FILE_PATH_RANDOM, FILE_CONTENT)); + BOOST_CHECK_EQUAL(FILE_CONTENT, readFileContent(FILE_PATH)); + + boost::system::error_code ec; + boost::filesystem::remove(FILE_PATH_RANDOM, ec); +} + +BOOST_AUTO_TEST_CASE(MountPointTest) +{ + bool result; + namespace fs = boost::filesystem; + boost::system::error_code ec; + + BOOST_REQUIRE(fs::create_directory(MOUNT_POINT_RANDOM_1, ec)); + BOOST_REQUIRE(isMountPoint(MOUNT_POINT_RANDOM_1, result)); + BOOST_CHECK_EQUAL(result, false); + BOOST_REQUIRE(hasSameMountPoint(TMP_PATH, MOUNT_POINT_RANDOM_1, result)); + BOOST_CHECK_EQUAL(result, true); + + BOOST_REQUIRE(mountRun(MOUNT_POINT_RANDOM_1)); + BOOST_REQUIRE(isMountPoint(MOUNT_POINT_RANDOM_1, result)); + BOOST_CHECK_EQUAL(result, true); + BOOST_REQUIRE(hasSameMountPoint(TMP_PATH, MOUNT_POINT_RANDOM_1, result)); + BOOST_CHECK_EQUAL(result, false); + + BOOST_REQUIRE(umount(MOUNT_POINT_RANDOM_1)); + BOOST_REQUIRE(fs::remove(MOUNT_POINT_RANDOM_1, ec)); +} + +BOOST_AUTO_TEST_CASE(MoveFileTest) +{ + namespace fs = boost::filesystem; + boost::system::error_code ec; + std::string src, dst; + + // same mount point + src = TMP_PATH + "/" + FILE_NAME_RANDOM_1; + dst = TMP_PATH + "/" + FILE_NAME_RANDOM_2; + + BOOST_REQUIRE(saveFileContent(src, FILE_CONTENT)); + + BOOST_CHECK(moveFile(src, dst)); + BOOST_CHECK(!fs::exists(src)); + BOOST_CHECK_EQUAL(readFileContent(dst), FILE_CONTENT); + + BOOST_REQUIRE(fs::remove(dst)); + + // different mount point + src = TMP_PATH + "/" + FILE_NAME_RANDOM_1; + dst = MOUNT_POINT_RANDOM_2 + "/" + FILE_NAME_RANDOM_2; + + BOOST_REQUIRE(fs::create_directory(MOUNT_POINT_RANDOM_2, ec)); + BOOST_REQUIRE(mountRun(MOUNT_POINT_RANDOM_2)); + BOOST_REQUIRE(saveFileContent(src, FILE_CONTENT)); + + BOOST_CHECK(moveFile(src, dst)); + BOOST_CHECK(!fs::exists(src)); + BOOST_CHECK_EQUAL(readFileContent(dst), FILE_CONTENT); + + BOOST_REQUIRE(fs::remove(dst)); + BOOST_REQUIRE(umount(MOUNT_POINT_RANDOM_2)); + BOOST_REQUIRE(fs::remove(MOUNT_POINT_RANDOM_2, ec)); +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 074d35a10695b412514dfe96581204044c3217c2 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Fri, 4 Jul 2014 14:39:17 +0200 Subject: [PATCH 06/16] Destroy libvirt domains with signal [Feature] Libvirt now destroys its domains with signal. [Cause] Destroying a domain in other way requires setns, which might not be available on some systems. [Solution] Tell libvirt to destroy a domain with signal. [Verification] Build, install, run tests. All should pass. Change-Id: I9d990488dd9a049feba2c02b070be2e4320029db --- server/container-admin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/container-admin.cpp b/server/container-admin.cpp index 9bc3c2e..b624817 100644 --- a/server/container-admin.cpp +++ b/server/container-admin.cpp @@ -237,7 +237,7 @@ void ContainerAdmin::shutdown() setSchedulerLevel(SchedulerLevel::FOREGROUND); - if (virDomainShutdown(mDom.get()) < 0) { + if (virDomainShutdownFlags(mDom.get(), VIR_DOMAIN_SHUTDOWN_SIGNAL) < 0) { LOGE(mId << ": Error while shutting down the container:\n" << libvirt::libvirtFormatError()); throw ContainerOperationException(); -- 2.7.4 From 796c23b2ce7b8003ee28044a009523ab76255eb9 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Thu, 3 Jul 2014 12:24:29 +0200 Subject: [PATCH 07/16] Connection to the hosts system dbus [Bug/Feature] Introduce hosts dbus connection [Cause] It's required by MDM and other hosts services [Solution] N/A [Verification] Build, install, run tests, run daemon Change-Id: Ia88b249a00dff8674cd8387d08e05f3115c36912 --- container-daemon/CMakeLists.txt | 2 +- .../configs/org.tizen.container.daemon.conf | 14 --- .../org.tizen.containers.domain.daemon.conf | 14 +++ container-daemon/daemon-dbus-definitions.hpp | 6 +- packaging/security-containers.spec | 3 +- server/configs/CMakeLists.txt | 5 +- .../dbus-1/system.d/org.tizen.containers.host.conf | 14 +++ .../etc/dbus-1/system.d/org.tizen.containers.conf | 14 --- .../system.d/org.tizen.containers.domain.conf | 14 +++ server/container-dbus-definitions.hpp | 6 +- server/containers-manager.hpp | 2 + server/exception.hpp | 8 ++ server/host-connection.cpp | 137 +++++++++++++++++++++ server/host-connection.hpp | 76 ++++++++++++ server/host-dbus-definitions.hpp | 54 ++++++++ 15 files changed, 332 insertions(+), 37 deletions(-) delete mode 100644 container-daemon/configs/org.tizen.container.daemon.conf create mode 100644 container-daemon/configs/org.tizen.containers.domain.daemon.conf create mode 100644 server/configs/dbus-1/system.d/org.tizen.containers.host.conf delete mode 100644 server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.conf create mode 100644 server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf create mode 100644 server/host-connection.cpp create mode 100644 server/host-connection.hpp create mode 100644 server/host-dbus-definitions.hpp diff --git a/container-daemon/CMakeLists.txt b/container-daemon/CMakeLists.txt index 3408f43..e26eaac 100644 --- a/container-daemon/CMakeLists.txt +++ b/container-daemon/CMakeLists.txt @@ -40,5 +40,5 @@ TARGET_LINK_LIBRARIES(${CONTAINER_DAEMON_CODENAME} ${CONTAINER_DAEMON_DEPS_LIBRA ## Install ##################################################################### INSTALL(TARGETS ${CONTAINER_DAEMON_CODENAME} DESTINATION bin) -INSTALL(FILES configs/org.tizen.container.daemon.conf +INSTALL(FILES configs/org.tizen.containers.domain.daemon.conf DESTINATION /etc/dbus-1/system.d/) diff --git a/container-daemon/configs/org.tizen.container.daemon.conf b/container-daemon/configs/org.tizen.container.daemon.conf deleted file mode 100644 index d962c15..0000000 --- a/container-daemon/configs/org.tizen.container.daemon.conf +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - diff --git a/container-daemon/configs/org.tizen.containers.domain.daemon.conf b/container-daemon/configs/org.tizen.containers.domain.daemon.conf new file mode 100644 index 0000000..21373c2 --- /dev/null +++ b/container-daemon/configs/org.tizen.containers.domain.daemon.conf @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/container-daemon/daemon-dbus-definitions.hpp b/container-daemon/daemon-dbus-definitions.hpp index 2cc283e..f18d87f 100644 --- a/container-daemon/daemon-dbus-definitions.hpp +++ b/container-daemon/daemon-dbus-definitions.hpp @@ -32,9 +32,9 @@ namespace security_containers { namespace container_daemon { namespace api { -const std::string BUS_NAME = "org.tizen.container.daemon"; -const std::string OBJECT_PATH = "/org/tizen/container/daemon"; -const std::string INTERFACE = "org.tizen.container.daemon"; +const std::string BUS_NAME = "org.tizen.containers.domain.daemon"; +const std::string OBJECT_PATH = "/org/tizen/containers/domain/daemon"; +const std::string INTERFACE = "org.tizen.containers.domain.daemon"; const std::string METHOD_GAIN_FOCUS = "GainFocus"; const std::string METHOD_LOSE_FOCUS = "LoseFocus"; diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec index 3afbdd1..eebe4d0 100644 --- a/packaging/security-containers.spec +++ b/packaging/security-containers.spec @@ -32,6 +32,7 @@ between them. A process from inside a container can request a switch of context %{_unitdir}/security-containers.service %{_unitdir}/multi-user.target.wants/security-containers.service %config %attr(400,root,root) /etc/security-containers/libvirt-config/*.xml +/etc/dbus-1/system.d/org.tizen.containers.host.conf /etc/security-containers/image-skel %prep @@ -132,7 +133,7 @@ Daemon running inside every container. %manifest packaging/security-containers-container-daemon.manifest %defattr(644,root,root,755) %attr(755,root,root) %{_bindir}/security-containers-container-daemon -/etc/dbus-1/system.d/org.tizen.container.daemon.conf +/etc/dbus-1/system.d/org.tizen.containers.domain.daemon.conf ## Test Package ################################################################ diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index 2e46a66..2f54222 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -28,7 +28,7 @@ INSTALL(FILES daemon.conf DESTINATION ${SC_CONFIG_INSTALL_DIR}) # TODO This file should be installed to /etc/dbus-1/system.d/ on an every container -INSTALL(FILES image-skel/etc/dbus-1/system.d/org.tizen.containers.conf +INSTALL(FILES image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf DESTINATION ${SC_CONFIG_INSTALL_DIR}/image-skel/etc/dbus-1/system.d) INSTALL(FILES ${container_CONF} @@ -39,3 +39,6 @@ INSTALL(FILES ${admin_CONF} INSTALL(FILES ${SYSTEMD_SERVICES} DESTINATION ${SYSTEMD_UNIT_DIR}) + +INSTALL(FILES dbus-1/system.d/org.tizen.containers.host.conf + DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d/) diff --git a/server/configs/dbus-1/system.d/org.tizen.containers.host.conf b/server/configs/dbus-1/system.d/org.tizen.containers.host.conf new file mode 100644 index 0000000..234832b --- /dev/null +++ b/server/configs/dbus-1/system.d/org.tizen.containers.host.conf @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.conf b/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.conf deleted file mode 100644 index f672c76..0000000 --- a/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.conf +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - diff --git a/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf b/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf new file mode 100644 index 0000000..709965b --- /dev/null +++ b/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/server/container-dbus-definitions.hpp b/server/container-dbus-definitions.hpp index 118a348..febcbbc 100644 --- a/server/container-dbus-definitions.hpp +++ b/server/container-dbus-definitions.hpp @@ -32,9 +32,9 @@ namespace security_containers { namespace api { -const std::string BUS_NAME = "org.tizen.containers"; -const std::string OBJECT_PATH = "/org/tizen/containers"; -const std::string INTERFACE = "org.tizen.containers.manager"; +const std::string BUS_NAME = "org.tizen.containers.domain"; +const std::string OBJECT_PATH = "/org/tizen/containers/domain"; +const std::string INTERFACE = "org.tizen.containers.domain.manager"; const std::string METHOD_NOTIFY_ACTIVE_CONTAINER = "NotifyActiveContainer"; const std::string METHOD_FILE_MOVE_REQUEST = "FileMoveRequest"; diff --git a/server/containers-manager.hpp b/server/containers-manager.hpp index 1a1af88..32ca341 100644 --- a/server/containers-manager.hpp +++ b/server/containers-manager.hpp @@ -28,6 +28,7 @@ #include "container.hpp" #include "containers-manager-config.hpp" +#include "host-connection.hpp" #include "input-monitor.hpp" #include @@ -75,6 +76,7 @@ public: private: ContainersManagerConfig mConfig; + HostConnection mHostConnection; // to hold InputMonitor pointer to monitor if container switching sequence is recognized std::unique_ptr mSwitchingSequenceMonitor; typedef std::unordered_map> ContainerMap; diff --git a/server/exception.hpp b/server/exception.hpp index 37fa45e..adfbdf7 100644 --- a/server/exception.hpp +++ b/server/exception.hpp @@ -58,6 +58,14 @@ struct ContainerConnectionException: public ServerException { }; /** + * Exception during performing an operation on a host connection + */ +struct HostConnectionException: public ServerException { + + HostConnectionException(const std::string& error = "") : ServerException(error) {} +}; + +/** * Exception during performing an operation by input monitor, * e.g. create channel, register callback etc. */ diff --git a/server/host-connection.cpp b/server/host-connection.cpp new file mode 100644 index 0000000..4b3c59d --- /dev/null +++ b/server/host-connection.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * 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 + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Implementation of a class for communication with server + */ + +#include "config.hpp" + +#include "host-connection.hpp" +#include "host-dbus-definitions.hpp" +#include "exception.hpp" + +#include "log/logger.hpp" + + +namespace security_containers { + +namespace { + +// Timeout in ms for waiting for dbus name. +// Can happen if glib loop is busy or not present. +// TODO: this should be in host's configuration file +const unsigned int NAME_ACQUIRED_TIMEOUT = 5 * 1000; + +} // namespace + + +HostConnection::HostConnection() + : mNameAcquired(false) + , mNameLost(false) +{ + LOGT("Connecting to host system DBUS"); + mDbusConnection = dbus::DbusConnection::createSystem(); + + LOGT("Setting DBUS name"); + mDbusConnection->setName(hostapi::BUS_NAME, + std::bind(&HostConnection::onNameAcquired, this), + std::bind(&HostConnection::onNameLost, this)); + + if (!waitForName(NAME_ACQUIRED_TIMEOUT)) { + LOGE("Could not acquire dbus name: " << hostapi::BUS_NAME); + throw HostConnectionException("Could not acquire dbus name: " + hostapi::BUS_NAME); + } + + LOGT("Registering DBUS interface"); + using namespace std::placeholders; + mDbusConnection->registerObject(hostapi::OBJECT_PATH, + hostapi::DEFINITION, + std::bind(&HostConnection::onMessageCall, + this, + _1, + _2, + _3, + _4, + _5)); + + LOGD("Connected"); +} + +HostConnection::~HostConnection() +{ +} + +bool HostConnection::waitForName(const unsigned int timeoutMs) +{ + std::unique_lock lock(mNameMutex); + mNameCondition.wait_for(lock, + std::chrono::milliseconds(timeoutMs), + [this] { + return mNameAcquired || mNameLost; + }); + + return mNameAcquired; +} + +void HostConnection::onNameAcquired() +{ + std::unique_lock lock(mNameMutex); + mNameAcquired = true; + mNameCondition.notify_one(); +} + +void HostConnection::onNameLost() +{ + std::unique_lock lock(mNameMutex); + mNameLost = true; + mNameCondition.notify_one(); + + if (mNameAcquired) { + // TODO implement reconnecting + LOGE("TODO Reconnect !!!"); + } +} + +void HostConnection::setTestCallback(const TestCallback& callback) +{ + mTestCallback = callback; +} + +void HostConnection::onMessageCall(const std::string& objectPath, + const std::string& interface, + const std::string& methodName, + GVariant* /*parameters*/, + dbus::MethodResultBuilder& result) +{ + if (objectPath != hostapi::OBJECT_PATH || interface != hostapi::INTERFACE) { + return; + } + + if (methodName == hostapi::METHOD_TEST) { + if (mTestCallback) { + mTestCallback(); + result.setVoid(); + } + } +} + + +} // namespace security_containers diff --git a/server/host-connection.hpp b/server/host-connection.hpp new file mode 100644 index 0000000..4d7eccd --- /dev/null +++ b/server/host-connection.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * 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 + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Declaration of a class for communication with server + */ + + +#ifndef SERVER_HOST_CONNECTION_HPP +#define SERVER_HOST_CONNECTION_HPP + +#include "dbus/connection.hpp" + +#include +#include + + +namespace security_containers { + + +class HostConnection { + +public: + HostConnection(); + ~HostConnection(); + + // ------------- API -------------- + + typedef std::function TestCallback; + + /** + * Register test callback + */ + void setTestCallback(const TestCallback& callback); + +private: + dbus::DbusConnection::Pointer mDbusConnection; + std::mutex mNameMutex; + std::condition_variable mNameCondition; + bool mNameAcquired; + bool mNameLost; + TestCallback mTestCallback; + + void onNameAcquired(); + void onNameLost(); + bool waitForName(const unsigned int timeoutMs); + + void onMessageCall(const std::string& objectPath, + const std::string& interface, + const std::string& methodName, + GVariant* parameters, + dbus::MethodResultBuilder& result); +}; + + +} // namespace security_containers + + +#endif // SERVER_HOST_CONNECTION_HPP diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp new file mode 100644 index 0000000..2d82fd3 --- /dev/null +++ b/server/host-dbus-definitions.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Piotr Bartosiewicz + * + * 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 + * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) + * @brief Host dbus api definitions + */ + +#ifndef SERVER_HOST_DBUS_DEFINITIONS_HPP +#define SERVER_HOST_DBUS_DEFINITIONS_HPP + +#include + + +namespace security_containers { +namespace hostapi { + + +const std::string BUS_NAME = "org.tizen.containers.host"; +const std::string OBJECT_PATH = "/org/tizen/containers/host"; +const std::string INTERFACE = "org.tizen.containers.host.test"; + +const std::string METHOD_TEST = "Test"; + +const std::string DEFINITION = + "" + " " + " " + " " + " " + ""; + + +} // namespace hostapi +} // namespace security_containers + + +#endif // SERVER_HOST_DBUS_DEFINITIONS_HPP -- 2.7.4 From a5da8114776cc08b5efa02e35b0ab39f64e81d7a Mon Sep 17 00:00:00 2001 From: Michal Witanowski Date: Wed, 11 Jun 2014 11:36:00 +0200 Subject: [PATCH 08/16] Add image configuration tests [Bug/Feature] Integration tests verifying containers' images completeness. If the tests fail, the containers will most probably not run under SCS. The following elements are checked: * existence of "security-containers" user with UID of 377 * existence and correctness of dbus configuration ("security-containers" should be allowed to use "org.tizen.containers.domain" socket) The names and paths to the containers' root file systems are extracted from SCS daemon and libvirt configs (/etc/security-containers/). [Cause] N/A [Solution] N/A [Verification] Build, install, run tests (sc_int_tests.py). Check various scenarios: remove or corrupt dbus config (etc/dbus-1/system.d/org.tizen.containers.domain.conf) or libvirt's XML config, remove "security-containers" user inside a container, change it's UID, etc. Change-Id: I69782f348ecb1c6b63a60286a3a8ee4ae3f8465b Signed-off-by: Michal Witanowski --- tests/integration_tests/CMakeLists.txt | 2 +- tests/integration_tests/__init__.py | 1 + tests/integration_tests/common/sc_test_utils.py | 16 +--- tests/integration_tests/image_tests/CMakeLists.txt | 27 +++++++ tests/integration_tests/image_tests/__init__.py | 2 + .../image_tests/config_checker.py | 89 ++++++++++++++++++++++ tests/integration_tests/image_tests/image_tests.py | 88 +++++++++++++++++++++ tests/integration_tests/sc_int_tests.py | 7 +- 8 files changed, 217 insertions(+), 15 deletions(-) create mode 100644 tests/integration_tests/image_tests/CMakeLists.txt create mode 100644 tests/integration_tests/image_tests/__init__.py create mode 100644 tests/integration_tests/image_tests/config_checker.py create mode 100644 tests/integration_tests/image_tests/image_tests.py diff --git a/tests/integration_tests/CMakeLists.txt b/tests/integration_tests/CMakeLists.txt index 044f6f7..3f96c47 100644 --- a/tests/integration_tests/CMakeLists.txt +++ b/tests/integration_tests/CMakeLists.txt @@ -37,4 +37,4 @@ INSTALL(PROGRAMS ${main_SCRIPT} DESTINATION ${SCRIPT_INSTALL_DIR}) ## Subdirectories ############################################################## ADD_SUBDIRECTORY(common) - +ADD_SUBDIRECTORY(image_tests) diff --git a/tests/integration_tests/__init__.py b/tests/integration_tests/__init__.py index cb111b5..731d042 100644 --- a/tests/integration_tests/__init__.py +++ b/tests/integration_tests/__init__.py @@ -1,2 +1,3 @@ __all__ = ["common", + "image_tests" ] diff --git a/tests/integration_tests/common/sc_test_utils.py b/tests/integration_tests/common/sc_test_utils.py index 09f45e6..4e77824 100644 --- a/tests/integration_tests/common/sc_test_utils.py +++ b/tests/integration_tests/common/sc_test_utils.py @@ -6,7 +6,6 @@ import subprocess import os - def launchProc(cmd): '''! Launch specified command as a subprocess. @@ -14,22 +13,15 @@ def launchProc(cmd): stderr. @param cmd Command to be launched - @return Output provided by specified command. - @exception Exception When a process exits with error code, a Exception object containing message - with error data is raised. + @return Tuple containing output provided by specified command and return code. ''' p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) ret = p.wait() output = p.stdout.read() - - if ret != 0: - raise Exception(cmd + " failed. error: " + os.strerror(ret) + ", output: " + output) - - return output + return (output, ret) - -def mount(dir, opts = []): +def mount(dir, opts=[]): '''! Mounts specified directory with additional command line options. @param dir Directory to be mounted @@ -39,7 +31,6 @@ def mount(dir, opts = []): launchProc(" ".join(["mount"] + opts + [dir])) - def umount(dir): '''! Unmounts specified directory. @@ -49,7 +40,6 @@ def umount(dir): launchProc(" ".join(["umount"] + [dir])) - def isNumber(str): '''! Checks if provided String is a number. diff --git a/tests/integration_tests/image_tests/CMakeLists.txt b/tests/integration_tests/image_tests/CMakeLists.txt new file mode 100644 index 0000000..6403880 --- /dev/null +++ b/tests/integration_tests/image_tests/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (c) 2014 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 CMakeLists.txt +# @author Michal Witanowski (m.witanowski@samsung.com) +# + +MESSAGE(STATUS "Including image tests package for Integration Tests...") + +SET(IMAGE_TESTS_DEST_DIR "${TEST_DEST_DIR}/image_tests") + +FILE(GLOB image_tests_SCRIPTS *.py) + +INSTALL(FILES ${image_tests_SCRIPTS} DESTINATION ${IMAGE_TESTS_DEST_DIR}) + diff --git a/tests/integration_tests/image_tests/__init__.py b/tests/integration_tests/image_tests/__init__.py new file mode 100644 index 0000000..45cc1dd --- /dev/null +++ b/tests/integration_tests/image_tests/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["image_tests", + ] diff --git a/tests/integration_tests/image_tests/config_checker.py b/tests/integration_tests/image_tests/config_checker.py new file mode 100644 index 0000000..6788bbe --- /dev/null +++ b/tests/integration_tests/image_tests/config_checker.py @@ -0,0 +1,89 @@ +'''! Module used to collect list of containers based on the security-containers configuration files. + +@author: Michal Witanowski (m.witanowski@samsung.com) +''' +import os +import json +import xml.etree.ElementTree as ET +from sc_integration_tests.common import sc_test_utils +from pprint import pprint + + +class ConfigChecker: + '''! This class verifies security-containers configuration files and collects dictionary with + containers existing in the system (name and rootfs path). + ''' + + def __parseLibvirtXML(self, path): + '''! Parses libvirt's configuration in order to extract container name and path. + + @param path Libvirt's domain configuration path + ''' + tree = ET.parse(path) + root = tree.getroot() + name = root.find("name").text + rootFound = False + + # extract directory mountings + for elem in root.iterfind('devices/filesystem'): + if "type" not in elem.attrib: + raise Exception("'type' attribute not found for 'filesystem' node in file: " + path) + + nodeSource = elem.find("source") + if nodeSource is None: + raise Exception("'source' not found in 'filesystem' node in file: " + path) + + nodeTarget = elem.find("target") + if nodeTarget is None: + raise Exception("'target' not found in 'filesystem' node in file: " + path) + + source = nodeSource.attrib["dir"] + target = nodeTarget.attrib["dir"] + if target == "/": + if rootFound: + raise Exception("Multiple root fs mounts found in file: " + path) + else: + self.containers[name] = source + print " Container '" + name + "' found at: " + source + rootFound = True + + if not rootFound: + raise Exception("Root directory of '" + name + "' container not specified in XML") + + def __init__(self, mainConfigPath): + '''! Parses daemon's JSON configuration files. + + @param mainConfigPath Path to the main config "daemon.conf" + ''' + self.containers = {} + print "Looking for container IDs..." + + # load main daemon JSON config file + if not os.path.isfile(mainConfigPath): + raise Exception(mainConfigPath + " not found. " + + "Please verify that security containers is properly installed.") + with open(mainConfigPath) as daemonConfigStr: + daemonConfigData = json.load(daemonConfigStr) + daemonConfigDir = os.path.dirname(os.path.abspath(mainConfigPath)) + + # get dictionary with containers + containerConfigPaths = daemonConfigData["containerConfigs"] + for configPath in containerConfigPaths: + + # open container config file + containerConfigPath = os.path.join(daemonConfigDir, configPath) + if not os.path.isfile(containerConfigPath): + raise Exception(containerConfigPath + " not found. " + + "Please verify that security containers is properly installed.") + with open(containerConfigPath) as containerConfigStr: + containerConfigData = json.load(containerConfigStr) + + # extract XML config path for libvirt + libvirtConfigPath = os.path.join(daemonConfigDir, "containers", + containerConfigData["config"]) + + output, ret = sc_test_utils.launchProc("virt-xml-validate " + libvirtConfigPath) + if ret == 0: + self.__parseLibvirtXML(libvirtConfigPath) + else: + raise Exception(output) diff --git a/tests/integration_tests/image_tests/image_tests.py b/tests/integration_tests/image_tests/image_tests.py new file mode 100644 index 0000000..34e61cc6 --- /dev/null +++ b/tests/integration_tests/image_tests/image_tests.py @@ -0,0 +1,88 @@ +'''! Module used to test containers' images completeness + +@author: Michal Witanowski (m.witanowski@samsung.com) +''' +import unittest +from sc_integration_tests.common import sc_test_utils +from config_checker import * +import xml.etree.ElementTree as ET + + +# security-containers daemon user name and user ID +SCS_USER_NAME = "security-containers" +SCS_UID = 377 + +DAEMON_DBUS_SOCKET_NAME = "org.tizen.containers.domain" + +# dbus config file path relative to container's root +DBUS_CONFIG_PATH = "etc/dbus-1/system.d/" + DAEMON_DBUS_SOCKET_NAME + ".conf" + +# main daemon config +DAEMON_CONFIG_PATH = "/etc/security-containers/daemon.conf" + + +class ContainerImageTestCase(unittest.TestCase): + '''! Test case class verifying containers' images + ''' + + @classmethod + def setUpClass(self): + '''! Sets up testing environment - collects container names and paths. + ''' + self.configChecker = ConfigChecker(DAEMON_CONFIG_PATH) + + def test01_scsUserExistence(self): + '''! Verifies if "security-containers" user with an appropriate UID exists within the + containers. + ''' + for containerName, containerPath in self.configChecker.containers.iteritems(): + # chroot into a container and get UID of the user + output, ret = sc_test_utils.launchProc("chroot " + containerPath + + " /usr/bin/id -u " + SCS_USER_NAME) + + self.assertEqual(ret, 0, "User '" + SCS_USER_NAME + "' does not exist in '" + + containerName + "' container.") + + # cast to integer to remove white spaces, etc. + uid = int(output) + self.assertEqual(uid, SCS_UID, "Invalid UID of '" + SCS_USER_NAME + "' in '" + + containerName + "' container: got " + str(uid) + + ", should be " + str(SCS_UID)) + + def test02_dbusConfig(self): + '''! Verifies if dbus configuration file exists within containers. + ''' + for containerName, containerPath in self.configChecker.containers.iteritems(): + configPath = os.path.join(containerPath, DBUS_CONFIG_PATH) + self.assertTrue(os.path.isfile(configPath), "Dbus configuration not found in '" + + containerName + "' container") + + tree = ET.parse(configPath) + root = tree.getroot() + self.assertEqual(root.tag, "busconfig", "Invalid root node name") + + # validate "security-containers" access to the dbus + ownCheck = False + sendDestinationCheck = False + receiveSenderCheck = False + + # extract directory mountings + for elem in root.iterfind("policy"): + if "user" not in elem.attrib: + continue + + self.assertEqual(elem.attrib["user"], SCS_USER_NAME, "dbus configuration allows '" + + elem.attrib["user"] + "' user to access the dbus socket.") + + for allowNode in elem.iterfind("allow"): + if "own" in allowNode.attrib: + ownCheck = (allowNode.attrib["own"] == DAEMON_DBUS_SOCKET_NAME) + if "send_destination" in allowNode.attrib: + sendDestinationCheck = (allowNode.attrib["send_destination"] == + DAEMON_DBUS_SOCKET_NAME) + if "receive_sender" in allowNode.attrib: + receiveSenderCheck = (allowNode.attrib["receive_sender"] == + DAEMON_DBUS_SOCKET_NAME) + + if not (ownCheck and sendDestinationCheck and sendDestinationCheck): + raise Exception("Invalid dbus configuration in '" + containerName + "' container") diff --git a/tests/integration_tests/sc_int_tests.py b/tests/integration_tests/sc_int_tests.py index 8a05cba..42e2812 100644 --- a/tests/integration_tests/sc_int_tests.py +++ b/tests/integration_tests/sc_int_tests.py @@ -6,9 +6,14 @@ Security-containers integration tests launcher. Launches all integration tests. ''' import unittest -test_groups = [# add tests here... # +from sc_integration_tests.image_tests import * + +# add tests here... +test_groups = [ + image_tests ] + def main(): for test_group in test_groups: print "Starting", test_group.__name__, " ..." -- 2.7.4 From b908eed9f607c7f669bacfa020c244445088069e Mon Sep 17 00:00:00 2001 From: Michal Witanowski Date: Mon, 12 May 2014 11:35:20 +0200 Subject: [PATCH 09/16] Run Security Containers Server as non root user [Bug/Feature] Drop root privileges of the server during startup. [Solution] * User "security-containers" has been added to the "libvirt" group. * CAP_SYS_ADMIN and CAP_MAC_OVERRIDE capabilities have been provided using libcap-ng. [Verification] 1. Make sure that "security-containers" user (with UID == 377) exists in the conainers. If no, execute: chroot /path/to/container /bin/bash \ -c "useradd -r security-containers -u 377" 2. Run tests. 3. Start SCS service as root (directly or via systemd service). Verify /proc//status of the process: * Uid == 377 * CapPrm == CapEff == 0000000000200000 * Groups: , 4. Run the service with "--root" option. Remember to change policy in dbus configuration file "etc/dbus-1/system.d/com.samsung.containers.conf" from "security-containers" to "root". 5. Trigger update (via sending SIGUSR1) and check if UID, groups and capabilities set did not change. NOTE: Latest libvirt (from "tizen" branch on tizen.org) is required. Change-Id: Idfda05fb081ca48193b19a99a6628cf14ec4bf57 Signed-off-by: Michal Witanowski --- CMakeLists.txt | 13 ++++ common/utils/environment.cpp | 87 ++++++++++++++++++++++ common/utils/environment.hpp | 52 +++++++++++++ common/utils/fs.cpp | 39 ++++++++++ common/utils/fs.hpp | 6 ++ container-daemon/CMakeLists.txt | 7 +- ... => org.tizen.containers.domain.daemon.conf.in} | 2 +- packaging/security-containers.spec | 51 ++++++++----- server/CMakeLists.txt | 8 +- server/configs/CMakeLists.txt | 14 +++- server/configs/containers/business.conf | 2 +- server/configs/containers/private.conf | 2 +- server/configs/daemon.conf | 1 + ...host.conf => org.tizen.containers.host.conf.in} | 6 ++ ...in.conf => org.tizen.containers.domain.conf.in} | 2 +- server/container.cpp | 8 +- server/container.hpp | 4 +- server/containers-manager-config.hpp | 8 +- server/containers-manager.cpp | 3 +- server/main.cpp | 8 +- server/server.cpp | 71 +++++++++++++++++- server/server.hpp | 9 ++- tests/unit_tests/CMakeLists.txt | 3 +- .../ut-containers-manager/buggy-daemon.conf | 1 + .../buggy-default-daemon.conf | 1 + .../buggy-foreground-daemon.conf | 1 + .../configs/ut-containers-manager/test-daemon.conf | 1 + .../ut-containers-manager/test-dbus-daemon.conf | 1 + .../server/configs/ut-server/buggy-daemon.conf | 1 + .../server/configs/ut-server/test-daemon.conf | 1 + 30 files changed, 371 insertions(+), 42 deletions(-) create mode 100644 common/utils/environment.cpp create mode 100644 common/utils/environment.hpp rename container-daemon/configs/{org.tizen.containers.domain.daemon.conf => org.tizen.containers.domain.daemon.conf.in} (92%) rename server/configs/dbus-1/system.d/{org.tizen.containers.host.conf => org.tizen.containers.host.conf.in} (67%) rename server/configs/image-skel/etc/dbus-1/system.d/{org.tizen.containers.domain.conf => org.tizen.containers.domain.conf.in} (91%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d5cd90..e5bc053 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,19 @@ ADD_DEFINITIONS("-pedantic-errors") # Make pedantic warnings into errors ADD_DEFINITIONS(-DPROGRAM_VERSION="${VERSION}") ADD_DEFINITIONS(-DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}") +IF(NOT DEFINED SECURITY_CONTAINERS_USER) + SET(SECURITY_CONTAINERS_USER "security-containers") +ENDIF(NOT DEFINED SECURITY_CONTAINERS_USER) +IF(NOT DEFINED LIBVIRT_GROUP) + SET(LIBVIRT_GROUP "libvirt") +ENDIF(NOT DEFINED LIBVIRT_GROUP) +IF(NOT DEFINED INPUT_EVENT_GROUP) + SET(INPUT_EVENT_GROUP "input") +ENDIF(NOT DEFINED INPUT_EVENT_GROUP) + +ADD_DEFINITIONS(-DSECURITY_CONTAINERS_USER="${SECURITY_CONTAINERS_USER}") +ADD_DEFINITIONS(-DLIBVIRT_GROUP="${LIBVIRT_GROUP}") +ADD_DEFINITIONS(-DINPUT_EVENT_GROUP="${INPUT_EVENT_GROUP}") ## Python packages directory ################################################### diff --git a/common/utils/environment.cpp b/common/utils/environment.cpp new file mode 100644 index 0000000..b74983d --- /dev/null +++ b/common/utils/environment.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Michal Witanowski + * + * 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 + * @author Michal Witanowski (m.witanowski@samsung.com) + * @brief Implementaion of environment setup routines that require root privileges + */ + +#include "config.hpp" + +#include "utils/environment.hpp" +#include "log/logger.hpp" + +#include +#include +#include +#include + + +namespace security_containers { +namespace utils { + + +bool setSuppGroups(const std::vector& groups) +{ + std::vector gids; + + for (const std::string& group : groups) { + // get GID from name + struct group* grp = ::getgrnam(group.c_str()); + if (grp == NULL) { + LOGE("getgrnam failed to find group '" << group << "'"); + return false; + } + + LOGD("'" << group << "' group ID: " << grp->gr_gid); + gids.push_back(grp->gr_gid); + } + + if (::setgroups(gids.size(), gids.data()) != 0) { + LOGE("setgroups() failed: " << strerror(errno)); + return false; + } + + return true; +} + +bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps) +{ + ::capng_clear(CAPNG_SELECT_BOTH); + + for (const auto cap : caps) { + if (::capng_update(CAPNG_ADD, static_cast(CAPNG_EFFECTIVE | + CAPNG_PERMITTED | + CAPNG_INHERITABLE), cap)) { + LOGE("Failed to set capability: " << ::capng_capability_to_name(cap)); + return false; + } + } + + if (::capng_change_id(uid, gid, static_cast(CAPNG_CLEAR_BOUNDING))) { + LOGE("Failed to change process user"); + return false; + } + + return true; +} + + +} // namespace utils +} // namespace security_containers diff --git a/common/utils/environment.hpp b/common/utils/environment.hpp new file mode 100644 index 0000000..b62189b --- /dev/null +++ b/common/utils/environment.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Michal Witanowski + * + * 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 + * @author Michal Witanowski (m.witanowski@samsung.com) + * @brief Declaration of environment setup routines that requires root privileges + */ + +#ifndef COMMON_UTILS_ENVIRONMENT_HPP +#define COMMON_UTILS_ENVIRONMENT_HPP + +#include +#include +#include + + +namespace security_containers { +namespace utils { + + +/** + * Set supplementary groups to the current process. + */ +bool setSuppGroups(const std::vector& groups); + +/** + * Set effective and permited capabilities on the current process and drop root privileges. + */ +bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps); + + +} // namespace utils +} // namespace security_containers + + +#endif // COMMON_UTILS_ENVIRONMENT_HPP diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index 421ff54..354e726 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -199,6 +199,45 @@ bool moveFile(const std::string& src, const std::string& dst) return true; } +bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem::perms mode) +{ + namespace fs = boost::filesystem; + + fs::path dirPath(path); + boost::system::error_code ec; + bool runDirCreated = false; + if (!fs::exists(dirPath)) { + if (!fs::create_directory(dirPath, ec)) { + LOGE("Failed to create directory '" << path << "': " + << ec.message()); + return false; + } + runDirCreated = true; + } else if (!fs::is_directory(dirPath)) { + LOGE("Path '" << path << " already exists"); + return false; + } + + // set permissions + fs::permissions(dirPath, mode, ec); + if (fs::status(dirPath).permissions() != mode) { + LOGE("Failed to set permissions to '" << path << "': " + << ec.message()); + return false; + } + + // set owner + if (::chown(path.c_str(), uid, gid) != 0) { + // remove the directory only if it hadn't existed before + if (runDirCreated) { + fs::remove(dirPath); + } + LOGE("chown() failed for path '" << path << "': " << strerror(errno)); + return false; + } + + return true; +} } // namespace utils } // namespace security_containers diff --git a/common/utils/fs.hpp b/common/utils/fs.hpp index 9e69cbd..9cff7a9 100644 --- a/common/utils/fs.hpp +++ b/common/utils/fs.hpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace security_containers { @@ -85,6 +86,11 @@ bool hasSameMountPoint(const std::string& path1, const std::string& path2, bool& */ bool moveFile(const std::string& src, const std::string& dst); +/** + * Creates a directory with specific UID, GID and permissions set. + */ +bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem::perms mode); + } // namespace utils } // namespace security_containers diff --git a/container-daemon/CMakeLists.txt b/container-daemon/CMakeLists.txt index e26eaac..238af6f 100644 --- a/container-daemon/CMakeLists.txt +++ b/container-daemon/CMakeLists.txt @@ -31,7 +31,7 @@ ADD_EXECUTABLE(${CONTAINER_DAEMON_CODENAME} ${project_SRCS} ${common_SRCS}) ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS program_options system filesystem) -PKG_CHECK_MODULES(CONTAINER_DAEMON_DEPS REQUIRED gio-2.0 libsystemd-journal) +PKG_CHECK_MODULES(CONTAINER_DAEMON_DEPS REQUIRED gio-2.0 libsystemd-journal libcap-ng) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${CONTAINER_DAEMON_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(${CONTAINER_DAEMON_CODENAME} ${CONTAINER_DAEMON_DEPS_LIBRARIES} ${Boost_LIBRARIES}) @@ -40,5 +40,8 @@ TARGET_LINK_LIBRARIES(${CONTAINER_DAEMON_CODENAME} ${CONTAINER_DAEMON_DEPS_LIBRA ## Install ##################################################################### INSTALL(TARGETS ${CONTAINER_DAEMON_CODENAME} DESTINATION bin) -INSTALL(FILES configs/org.tizen.containers.domain.daemon.conf +CONFIGURE_FILE(configs/org.tizen.containers.domain.daemon.conf.in + ${CMAKE_BINARY_DIR}/configs/org.tizen.containers.domain.daemon.conf) + +INSTALL(FILES ${CMAKE_BINARY_DIR}/configs/org.tizen.containers.domain.daemon.conf DESTINATION /etc/dbus-1/system.d/) diff --git a/container-daemon/configs/org.tizen.containers.domain.daemon.conf b/container-daemon/configs/org.tizen.containers.domain.daemon.conf.in similarity index 92% rename from container-daemon/configs/org.tizen.containers.domain.daemon.conf rename to container-daemon/configs/org.tizen.containers.domain.daemon.conf.in index 21373c2..e080a1d 100644 --- a/container-daemon/configs/org.tizen.containers.domain.daemon.conf +++ b/container-daemon/configs/org.tizen.containers.domain.daemon.conf.in @@ -2,7 +2,7 @@ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> - + diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec index eebe4d0..e214d14 100644 --- a/packaging/security-containers.spec +++ b/packaging/security-containers.spec @@ -1,19 +1,28 @@ %define script_dir %{_sbindir} - -Name: security-containers -Version: 0.1.0 -Release: 0 -Source0: %{name}-%{version}.tar.gz -License: Apache-2.0 -Group: Security/Other -Summary: Daemon for managing containers -BuildRequires: cmake -BuildRequires: boost-devel -BuildRequires: libvirt-devel -BuildRequires: libjson-devel -BuildRequires: pkgconfig(glib-2.0) -BuildRequires: pkgconfig(libsystemd-journal) -BuildRequires: pkgconfig(libvirt-glib-1.0) +# Security Containers Server's user info - it should already exist in the system +%define scs_user security-containers +%define libvirt_group libvirt +# The group that has read and write access to /dev/input/event* devices. +# It may vary between platforms. +%define input_event_group video + +Name: security-containers +Version: 0.1.0 +Release: 0 +Source0: %{name}-%{version}.tar.gz +License: Apache-2.0 +Group: Security/Other +Summary: Daemon for managing containers +BuildRequires: cmake +BuildRequires: boost-devel +BuildRequires: libvirt-devel +BuildRequires: libjson-devel +BuildRequires: libcap-ng-devel +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(libsystemd-journal) +BuildRequires: pkgconfig(libvirt-glib-1.0) +Requires: libvirt-daemon >= 1.2.4 +Requires(post): libcap-tools %description This package provides a daemon used to manage containers - start, stop and switch @@ -29,11 +38,11 @@ between them. A process from inside a container can request a switch of context %dir /etc/security-containers/libvirt-config %config /etc/security-containers/daemon.conf %config /etc/security-containers/containers/*.conf +%config /etc/security-containers/libvirt-config/*.xml +/etc/security-containers/image-skel %{_unitdir}/security-containers.service %{_unitdir}/multi-user.target.wants/security-containers.service -%config %attr(400,root,root) /etc/security-containers/libvirt-config/*.xml /etc/dbus-1/system.d/org.tizen.containers.host.conf -/etc/security-containers/image-skel %prep %setup -q @@ -50,7 +59,10 @@ between them. A process from inside a container can request a switch of context -DCMAKE_BUILD_TYPE=%{build_type} \ -DSCRIPT_INSTALL_DIR=%{script_dir} \ -DSYSTEMD_UNIT_DIR=%{_unitdir} \ - -DPYTHON_SITELIB=%{python_sitelib} + -DPYTHON_SITELIB=%{python_sitelib} \ + -DSECURITY_CONTAINERS_USER=%{scs_user} \ + -DLIBVIRT_GROUP=%{libvirt_group} \ + -DINPUT_EVENT_GROUP=%{input_event_group} make -k %{?jobs:-j%jobs} %install @@ -66,6 +78,8 @@ rm -rf %{buildroot} if [ $1 == 1 ]; then systemctl daemon-reload || : fi +# set needed caps on the binary to allow restart without loosing them +setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE+ei %{_bindir}/security-containers-server %preun # Stop the service before uninstall @@ -158,4 +172,3 @@ Unit tests for both: server and client and integration tests. %{script_dir}/sc_test_parser.py %{_datadir}/security-containers %{python_sitelib}/sc_integration_tests - diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 595ec72..1e639cd 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -28,9 +28,10 @@ ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS} ${common_SRCS}) ## Link libraries ############################################################## -FIND_PACKAGE (Boost COMPONENTS program_options system filesystem regex) +FIND_PACKAGE(Boost COMPONENTS program_options system filesystem regex) +PKG_CHECK_MODULES(SERVER_DEPS REQUIRED libvirt libvirt-glib-1.0 json gio-2.0 libsystemd-journal + libcap-ng) -PKG_CHECK_MODULES(SERVER_DEPS REQUIRED libvirt libvirt-glib-1.0 json gio-2.0 libsystemd-journal) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${SERVER_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(${SERVER_CODENAME} ${SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES}) @@ -42,3 +43,6 @@ ADD_SUBDIRECTORY(configs) ## Install ##################################################################### INSTALL(TARGETS ${SERVER_CODENAME} DESTINATION bin) + +## Set capabilities on server executable ####################################### +INSTALL(CODE "EXECUTE_PROCESS(COMMAND setcap CAP_SYS_ADMIN,CAP_MAC_OVERRIDE+ei \$ENV{DESTDIR}/${CMAKE_INSTALL_PREFIX}/bin/${SERVER_CODENAME})") diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index 2f54222..4a15fe3 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -27,10 +27,19 @@ FILE(GLOB SYSTEMD_SERVICES systemd/*.service) INSTALL(FILES daemon.conf DESTINATION ${SC_CONFIG_INSTALL_DIR}) +# preprocess d-bus configs +CONFIGURE_FILE(dbus-1/system.d/org.tizen.containers.host.conf.in + ${CMAKE_BINARY_DIR}/dbus-1/system.d/org.tizen.containers.host.conf) +CONFIGURE_FILE(image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf.in + ${CMAKE_BINARY_DIR}/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf) + # TODO This file should be installed to /etc/dbus-1/system.d/ on an every container -INSTALL(FILES image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf +INSTALL(FILES ${CMAKE_BINARY_DIR}/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf DESTINATION ${SC_CONFIG_INSTALL_DIR}/image-skel/etc/dbus-1/system.d) +INSTALL(FILES ${CMAKE_BINARY_DIR}/dbus-1/system.d/org.tizen.containers.host.conf + DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d/) + INSTALL(FILES ${container_CONF} DESTINATION ${SC_CONFIG_INSTALL_DIR}/containers) @@ -39,6 +48,3 @@ INSTALL(FILES ${admin_CONF} INSTALL(FILES ${SYSTEMD_SERVICES} DESTINATION ${SYSTEMD_UNIT_DIR}) - -INSTALL(FILES dbus-1/system.d/org.tizen.containers.host.conf - DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d/) diff --git a/server/configs/containers/business.conf b/server/configs/containers/business.conf index fbd1bbb..80efdd4 100644 --- a/server/configs/containers/business.conf +++ b/server/configs/containers/business.conf @@ -4,7 +4,7 @@ "privilege" : 1, "config" : "../libvirt-config/business.xml", "networkConfig" : "../libvirt-config/business-network.xml", - "runMountPoint" : "/var/run/containers/business/run", + "runMountPoint" : "business/run", "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ] } diff --git a/server/configs/containers/private.conf b/server/configs/containers/private.conf index a12a847..3984476 100644 --- a/server/configs/containers/private.conf +++ b/server/configs/containers/private.conf @@ -4,7 +4,7 @@ "privilege" : 10, "config" : "../libvirt-config/private.xml", "networkConfig" : "../libvirt-config/private-network.xml", - "runMountPoint" : "/var/run/containers/private/run", + "runMountPoint" : "private/run", "permittedToSend" : [ "/tmp/.*" ], "permittedToRecv" : [ "/tmp/.*" ] } diff --git a/server/configs/daemon.conf b/server/configs/daemon.conf index 94af879..c67f607 100644 --- a/server/configs/daemon.conf +++ b/server/configs/daemon.conf @@ -1,6 +1,7 @@ { "containerConfigs" : ["containers/private.conf", "containers/business.conf" ], "containersPath" : "/opt/usr/containers", + "runMountPointPrefix" : "/var/run/containers", "foregroundId" : "private", "defaultId" : "private", "inputConfig" : {"enabled" : true, diff --git a/server/configs/dbus-1/system.d/org.tizen.containers.host.conf b/server/configs/dbus-1/system.d/org.tizen.containers.host.conf.in similarity index 67% rename from server/configs/dbus-1/system.d/org.tizen.containers.host.conf rename to server/configs/dbus-1/system.d/org.tizen.containers.host.conf.in index 234832b..c29a684 100644 --- a/server/configs/dbus-1/system.d/org.tizen.containers.host.conf +++ b/server/configs/dbus-1/system.d/org.tizen.containers.host.conf.in @@ -2,6 +2,12 @@ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> + + + + + + diff --git a/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf b/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf.in similarity index 91% rename from server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf rename to server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf.in index 709965b..49da048 100644 --- a/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf +++ b/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf.in @@ -2,7 +2,7 @@ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> - + diff --git a/server/container.cpp b/server/container.cpp index ea45b39..f8a8798 100644 --- a/server/container.cpp +++ b/server/container.cpp @@ -50,7 +50,8 @@ const int RECONNECT_DELAY = 1 * 1000; } // namespace -Container::Container(const std::string& containerConfigPath) +Container::Container(const std::string& containerConfigPath, + const std::string& baseRunMountPointPath) { config::loadFromFile(containerConfigPath, mConfig); @@ -64,6 +65,9 @@ Container::Container(const std::string& containerConfigPath) const std::string baseConfigPath = utils::dirName(containerConfigPath); mConfig.config = fs::absolute(mConfig.config, baseConfigPath).string(); mConfig.networkConfig = fs::absolute(mConfig.networkConfig, baseConfigPath).string(); + if (!mConfig.runMountPoint.empty()) { + mRunMountPoint = fs::absolute(mConfig.runMountPoint, baseRunMountPointPath).string(); + } LOGT("Creating Network Admin " << mConfig.networkConfig); mNetworkAdmin.reset(new NetworkAdmin(mConfig)); @@ -110,7 +114,7 @@ int Container::getPrivilege() const void Container::start() { Lock lock(mReconnectMutex); - mConnectionTransport.reset(new ContainerConnectionTransport(mConfig.runMountPoint)); + mConnectionTransport.reset(new ContainerConnectionTransport(mRunMountPoint)); mNetworkAdmin->start(); mAdmin->start(); mConnection.reset(new ContainerConnection(mConnectionTransport->acquireAddress(), diff --git a/server/container.hpp b/server/container.hpp index 7cc0c5b..8ab37d8 100644 --- a/server/container.hpp +++ b/server/container.hpp @@ -44,7 +44,8 @@ namespace security_containers { class Container { public: - Container(const std::string& containerConfigPath); + Container(const std::string& containerConfigPath, + const std::string& baseRunMountPointPath = ""); Container(Container&&) = default; virtual ~Container(); @@ -166,6 +167,7 @@ private: NotifyActiveContainerCallback mNotifyCallback; DisplayOffCallback mDisplayOffCallback; FileMoveRequestCallback mFileMoveCallback; + std::string mRunMountPoint; void onNameLostCallback(); void reconnectHandler(); diff --git a/server/containers-manager-config.hpp b/server/containers-manager-config.hpp index c890880..7f5cb9d 100644 --- a/server/containers-manager-config.hpp +++ b/server/containers-manager-config.hpp @@ -66,13 +66,19 @@ struct ContainersManagerConfig { */ InputConfig inputConfig; + /** + * Prefix added to a path of "run" tmpfs mount point for each container. + */ + std::string runMountPointPrefix; + CONFIG_REGISTER ( containerConfigs, foregroundId, defaultId, containersPath, - inputConfig + inputConfig, + runMountPointPrefix ) }; diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp index 44539da..2f8e8dd 100644 --- a/server/containers-manager.cpp +++ b/server/containers-manager.cpp @@ -74,7 +74,8 @@ ContainersManager::ContainersManager(const std::string& managerConfigPath): mDet } LOGD("Creating Container " << containerConfigPath); - std::unique_ptr c(new Container(containerConfigPath)); + std::unique_ptr c(new Container(containerConfigPath, + mConfig.runMountPointPrefix)); std::string id = c->getId(); using namespace std::placeholders; c->setNotifyActiveContainerCallback(bind(&ContainersManager::notifyActiveContainerHandler, diff --git a/server/main.cpp b/server/main.cpp index 521f683..d84a850 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -54,16 +54,17 @@ const std::string PROGRAM_NAME_AND_VERSION = } // namespace - int main(int argc, char* argv[]) { - std::string configPath ; + std::string configPath; + bool runAsRoot = false; try { po::options_description desc("Allowed options"); desc.add_options() ("help,h", "print this help") + ("root,r", "Don't drop root privileges at startup") ("version,v", "show application version") ("log-level,l", po::value()->default_value("DEBUG"), "set log level") ("config,c", po::value()->default_value("/etc/security-containers/daemon.conf"), "server configuration file") @@ -108,6 +109,7 @@ int main(int argc, char* argv[]) #endif configPath = vm["config"].as(); + runAsRoot = vm.count("root") > 0; } catch (std::exception& e) { std::cerr << e.what() << std::endl; @@ -115,7 +117,7 @@ int main(int argc, char* argv[]) } try { - Server server(configPath); + Server server(configPath, runAsRoot); server.run(); server.reloadIfRequired(argv); diff --git a/server/server.cpp b/server/server.cpp index d04d562..c2fae7d 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -28,8 +28,10 @@ #include "containers-manager.hpp" #include "exception.hpp" +#include "config/manager.hpp" #include "log/logger.hpp" #include "utils/glib-loop.hpp" +#include "utils/environment.hpp" #include #include @@ -37,15 +39,35 @@ #include #include #include +#include +#include +#include +#include + + +#ifndef SECURITY_CONTAINERS_USER +#error "SECURITY_CONTAINERS_USER must be defined!" +#endif + +#ifndef INPUT_EVENT_GROUP +#error "INPUT_EVENT_GROUP must be defined!" +#endif + +#ifndef LIBVIRT_GROUP +#error "LIBVIRT_GROUP must be defined!" +#endif extern char** environ; namespace security_containers { -Server::Server(const std::string& configPath) +Server::Server(const std::string& configPath, bool runAsRoot) : mConfigPath(configPath) { + if (!prepareEnvironment(configPath, runAsRoot)) { + throw ServerException("Environment setup failed"); + } } @@ -115,4 +137,51 @@ void Server::terminate() gSignalLatch.set(); } +bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot) +{ + namespace fs = boost::filesystem; + + // TODO: currently this config is loaded twice: here and in ContainerManager + ContainersManagerConfig config; + config::loadFromFile(configPath, config); + + struct passwd* pwd = ::getpwnam(SECURITY_CONTAINERS_USER); + if (pwd == NULL) { + LOGE("getpwnam failed to find user '" << SECURITY_CONTAINERS_USER << "'"); + return false; + } + uid_t uid = pwd->pw_uid; + gid_t gid = pwd->pw_gid; + LOGD("security-containers UID = " << uid << ", GID = " << gid); + + // create directory for dbus socket (if needed) + if (!config.runMountPointPrefix.empty()) { + if (!utils::createDir(config.runMountPointPrefix, uid, gid, + fs::perms::owner_all | + fs::perms::group_read | fs::perms::group_exe | + fs::perms::others_read | fs::perms::others_exe)) { + return false; + } + } + + // Omit supplementaty group setup and root drop if the user is already switched. + // This situation will happen during daemon update triggered by SIGUSR1. + if (!runAsRoot && geteuid() == uid) { + return true; + } + + // LIBVIRT_GROUP provides access to libvirt's daemon socket. + // INPUT_EVENT_GROUP provides access to /dev/input/event* devices used by InputMonitor. + if (!utils::setSuppGroups({LIBVIRT_GROUP, INPUT_EVENT_GROUP})) { + return false; + } + + // CAP_SYS_ADMIN allows to mount tmpfs' for dbus communication at the runtime. + // NOTE: CAP_MAC_OVERRIDE is temporary and must be removed when "smack namespace" + // is introduced. The capability is needed to allow modify SMACK labels of + // "/var/run/containers//run" mount point. + return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN, CAP_MAC_OVERRIDE})); +} + + } // namespace security_containers diff --git a/server/server.hpp b/server/server.hpp index abb8775..ba2334e 100644 --- a/server/server.hpp +++ b/server/server.hpp @@ -30,14 +30,21 @@ #include + namespace security_containers { + class Server { public: - Server(const std::string& configPath); + Server(const std::string& configPath, bool runAsRoot = true); virtual ~Server(); /** + * Set needed caps, groups and drop root privileges. + */ + static bool prepareEnvironment(const std::string& configPath, bool runAsRoot); + + /** * Starts all the containers and blocks until SIGINT, SIGTERM or SIGUSR1 */ void run(); diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 3be44b7..30d309b 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -34,7 +34,8 @@ ADD_EXECUTABLE(${UT_SERVER_CODENAME} ${project_SRCS} ${common_SRCS} ${server_SRC ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS unit_test_framework system filesystem regex) -PKG_CHECK_MODULES(UT_SERVER_DEPS REQUIRED libvirt libvirt-glib-1.0 json gio-2.0 libsystemd-journal) +PKG_CHECK_MODULES(UT_SERVER_DEPS REQUIRED libvirt libvirt-glib-1.0 json gio-2.0 + libsystemd-journal libcap-ng) INCLUDE_DIRECTORIES(${COMMON_FOLDER} ${SERVER_FOLDER} ${UNIT_TESTS_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${UT_SERVER_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES}) diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf index 8e89f50..c2d0ca3 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf @@ -1,5 +1,6 @@ { "containerConfigs" : ["containers/console1.conf", "missing/file/path/missing.conf", "containers/console3.conf"], + "runMountPointPrefix" : "", "foregroundId" : "ut-containers-manager-console1", "defaultId" : "ut-containers-manager-console1", "containersPath" : "/tmp", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf index 51b2bbd..7b380cb 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf @@ -1,5 +1,6 @@ { "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"], + "runMountPointPrefix" : "", "foregroundId" : "ut-containers-manager-console1", "defaultId" : "in_no_way_there_is_a_valid_id_here", "containersPath" : "/tmp", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf index c62daad..8f177ae 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf @@ -1,5 +1,6 @@ { "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"], + "runMountPointPrefix" : "", "foregroundId" : "this_id_does_not_exist", "defaultId" : "ut-containers-manager-console1", "containersPath" : "/tmp", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf index 7908dea..c5a42c0 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf @@ -1,5 +1,6 @@ { "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"], + "runMountPointPrefix" : "", "foregroundId" : "ut-containers-manager-console1", "defaultId" : "ut-containers-manager-console1", "containersPath" : "/tmp", diff --git a/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf index 5466f3d..f7aedc6 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf @@ -5,6 +5,7 @@ "foregroundId" : "ut-containers-manager-console1-dbus", "defaultId" : "ut-containers-manager-console1-dbus", "containersPath" : "/tmp", + "runMountPointPrefix" : "", "inputConfig" : {"enabled" : false, "device" : "/dev/doesnotexist", "code" : 139, diff --git a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf index 41cfc2f..9e2298f 100644 --- a/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf +++ b/tests/unit_tests/server/configs/ut-server/buggy-daemon.conf @@ -1,6 +1,7 @@ { "containerConfigs" : ["containers/container1.conf", "missing/file/path/missing.conf", "containers/container3.conf"], "containersPath" : "/tmp", + "runMountPointPrefix" : "", "foregroundId" : "ut-server-container1", "defaultId" : "ut-server-container1", "inputConfig" : {"enabled" : false, diff --git a/tests/unit_tests/server/configs/ut-server/test-daemon.conf b/tests/unit_tests/server/configs/ut-server/test-daemon.conf index 8935030..5c3b373 100644 --- a/tests/unit_tests/server/configs/ut-server/test-daemon.conf +++ b/tests/unit_tests/server/configs/ut-server/test-daemon.conf @@ -1,6 +1,7 @@ { "containerConfigs" : ["containers/container1.conf", "containers/container2.conf", "containers/container3.conf"], "containersPath" : "/tmp", + "runMountPointPrefix" : "", "foregroundId" : "ut-server-container1", "defaultId" : "ut-server-container1", "inputConfig" : {"enabled" : false, -- 2.7.4 From e9134d9f9815fb4db25f89611389174f5c5f8bc1 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Thu, 10 Jul 2014 09:10:07 +0200 Subject: [PATCH 10/16] Fix path to the dbus-daemon [Bug/Feature] Fix path to the dbus-daemon [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run daemon Change-Id: I9d8006b238bdf8ad22675c618213c10931938b0f Signed-off-by: Dariusz Michaluk --- tests/unit_tests/dbus/ut-connection.cpp | 2 +- .../server/configs/ut-container/libvirt-config/test-dbus.xml.in | 2 +- .../configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in | 2 +- .../configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in | 2 +- .../configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in | 2 +- tests/unit_tests/server/ut-container-connection.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit_tests/dbus/ut-connection.cpp b/tests/unit_tests/dbus/ut-connection.cpp index eed9af7..46b9aa9 100644 --- a/tests/unit_tests/dbus/ut-connection.cpp +++ b/tests/unit_tests/dbus/ut-connection.cpp @@ -51,7 +51,7 @@ using namespace security_containers::dbus; namespace { -const char* DBUS_DAEMON_PROC = "/bin/dbus-daemon"; +const char* DBUS_DAEMON_PROC = "/usr/bin/dbus-daemon"; const char* const DBUS_DAEMON_ARGS[] = { DBUS_DAEMON_PROC, "--config-file=" SC_TEST_CONFIG_INSTALL_DIR "/dbus/ut-connection/ut-dbus.conf", diff --git a/tests/unit_tests/server/configs/ut-container/libvirt-config/test-dbus.xml.in b/tests/unit_tests/server/configs/ut-container/libvirt-config/test-dbus.xml.in index c57a948..555a9c6 100644 --- a/tests/unit_tests/server/configs/ut-container/libvirt-config/test-dbus.xml.in +++ b/tests/unit_tests/server/configs/ut-container/libvirt-config/test-dbus.xml.in @@ -6,7 +6,7 @@ exe /bin/sh -c - trap exit SIGTERM; /bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container/ut-dbus.conf --fork; read + trap exit SIGTERM; /usr/bin/dbus-daemon --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container/ut-dbus.conf --fork; read diff --git a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in index 6d24978..3bce659 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in +++ b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console1-dbus.xml.in @@ -4,7 +4,7 @@ 102400 exe - /bin/dbus-daemon + /usr/bin/dbus-daemon --nofork --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --address=unix:path=/tmp/ut-containers-manager/console1-dbus/dbus/system_bus_socket diff --git a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in index 5fe2996..f98c9bd 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in +++ b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console2-dbus.xml.in @@ -4,7 +4,7 @@ 102400 exe - /bin/dbus-daemon + /usr/bin/dbus-daemon --nofork --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --address=unix:path=/tmp/ut-containers-manager/console2-dbus/dbus/system_bus_socket diff --git a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in index be4d618..8175bcf 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in +++ b/tests/unit_tests/server/configs/ut-containers-manager/libvirt-config/console3-dbus.xml.in @@ -4,7 +4,7 @@ 102400 exe - /bin/dbus-daemon + /usr/bin/dbus-daemon --nofork --config-file=@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-containers-manager/ut-dbus.conf --address=unix:path=/tmp/ut-containers-manager/console3-dbus/dbus/system_bus_socket diff --git a/tests/unit_tests/server/ut-container-connection.cpp b/tests/unit_tests/server/ut-container-connection.cpp index 92f98ac..9f7b680 100644 --- a/tests/unit_tests/server/ut-container-connection.cpp +++ b/tests/unit_tests/server/ut-container-connection.cpp @@ -48,7 +48,7 @@ using namespace security_containers::dbus; namespace { -const char* DBUS_DAEMON_PROC = "/bin/dbus-daemon"; +const char* DBUS_DAEMON_PROC = "/usr/bin/dbus-daemon"; const char* const DBUS_DAEMON_ARGS[] = { DBUS_DAEMON_PROC, "--config-file=" SC_TEST_CONFIG_INSTALL_DIR "/server/ut-container-connection/ut-dbus.conf", -- 2.7.4 From d9efc6007505f8ab688a5c75ae8577c0f2c2a330 Mon Sep 17 00:00:00 2001 From: Michal Witanowski Date: Fri, 4 Jul 2014 15:02:46 +0200 Subject: [PATCH 11/16] Fix executable path in systemd service configuration [Bug/Feature] N/A [Cause] "usr" path varies between platforms. [Solution] Generate daemon service path at build time. [Verification] Build and install. Check if value of "ExecStart" in /usr/lib/systemd/system/security-containers.service is valid server executable path. Change-Id: I7cd1bbcaedc3ad2e256c4bbe4210886ba6262813 Signed-off-by: Michal Witanowski --- server/configs/CMakeLists.txt | 11 ++++++++--- ...rity-containers.service => security-containers.service.in} | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) rename server/configs/systemd/{security-containers.service => security-containers.service.in} (76%) diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index 4a15fe3..0adcd0d 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -21,9 +21,14 @@ MESSAGE(STATUS "Installing configs to " ${SC_CONFIG_INSTALL_DIR}) FILE(GLOB container_CONF containers/*.conf) FILE(GLOB admin_CONF libvirt-config/*.xml) -FILE(GLOB SYSTEMD_SERVICES systemd/*.service) -## Installations ############################################################### + +## Generate #################################################################### +CONFIGURE_FILE(systemd/security-containers.service.in + ${CMAKE_BINARY_DIR}/systemd/security-containers.service) + + +## Install ##################################################################### INSTALL(FILES daemon.conf DESTINATION ${SC_CONFIG_INSTALL_DIR}) @@ -46,5 +51,5 @@ INSTALL(FILES ${container_CONF} INSTALL(FILES ${admin_CONF} DESTINATION ${SC_CONFIG_INSTALL_DIR}/libvirt-config) -INSTALL(FILES ${SYSTEMD_SERVICES} +INSTALL(FILES ${CMAKE_BINARY_DIR}/systemd/security-containers.service DESTINATION ${SYSTEMD_UNIT_DIR}) diff --git a/server/configs/systemd/security-containers.service b/server/configs/systemd/security-containers.service.in similarity index 76% rename from server/configs/systemd/security-containers.service rename to server/configs/systemd/security-containers.service.in index 38e2fd7..f06dea3 100644 --- a/server/configs/systemd/security-containers.service +++ b/server/configs/systemd/security-containers.service.in @@ -5,7 +5,7 @@ Requires=libvirtd.service [Service] Type=simple -ExecStart=/usr/bin/security-containers-server +ExecStart=${CMAKE_INSTALL_PREFIX}/bin/security-containers-server Restart=on-failure ExecReload=/bin/kill -HUP $MAINPID -- 2.7.4 From 109893c909ac071c848315de252fba29691c30e7 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Tue, 1 Jul 2014 15:08:26 +0200 Subject: [PATCH 12/16] Add flag in container config allowing switch to default after timeout [Feature] Flag in container config which allows switching to default container when timeout occurs. [Cause] Some containers might want to forbid switching to default container after timeout. [Solution] Add flag switchToDefaultAfterTimeout allowing such switch in container config. [Verification] Build, install, run tests. All should pass. Change-Id: Icdcfc007c0a11126fe243988878a2c918d6bdf13 Signed-off-by: Lukasz Kostyra --- server/configs/containers/business.conf | 1 + server/configs/containers/private.conf | 1 + server/container-config.hpp | 7 ++++ server/container.cpp | 5 +++ server/container.hpp | 5 +++ server/containers-manager.cpp | 11 ++++- .../ut-container-admin/containers/buggy.conf.in | 1 + .../ut-container-admin/containers/missing.conf | 1 + .../containers/test-no-shutdown.conf.in | 1 + .../ut-container-admin/containers/test.conf.in | 1 + .../configs/ut-container/containers/buggy.conf | 1 + .../configs/ut-container/containers/test-dbus.conf | 1 + .../configs/ut-container/containers/test.conf | 1 + .../containers/console1-dbus.conf | 1 + .../ut-containers-manager/containers/console1.conf | 1 + .../containers/console2-dbus.conf | 1 + .../ut-containers-manager/containers/console2.conf | 1 + .../containers/console3-dbus.conf | 1 + .../ut-containers-manager/containers/console3.conf | 1 + .../ut-network-admin/containers/buggy.conf.in | 1 + .../ut-network-admin/containers/missing.conf | 1 + .../ut-network-admin/containers/test.conf.in | 1 + .../configs/ut-server/containers/container1.conf | 1 + .../configs/ut-server/containers/container2.conf | 1 + .../configs/ut-server/containers/container3.conf | 1 + tests/unit_tests/server/ut-containers-manager.cpp | 48 ++++++++++++++++++++++ 26 files changed, 95 insertions(+), 2 deletions(-) diff --git a/server/configs/containers/business.conf b/server/configs/containers/business.conf index 80efdd4..f16ccb4 100644 --- a/server/configs/containers/business.conf +++ b/server/configs/containers/business.conf @@ -2,6 +2,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "privilege" : 1, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/business.xml", "networkConfig" : "../libvirt-config/business-network.xml", "runMountPoint" : "business/run", diff --git a/server/configs/containers/private.conf b/server/configs/containers/private.conf index 3984476..cde88c3 100644 --- a/server/configs/containers/private.conf +++ b/server/configs/containers/private.conf @@ -2,6 +2,7 @@ "cpuQuotaForeground" : -1, "cpuQuotaBackground" : 1000, "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/private.xml", "networkConfig" : "../libvirt-config/private-network.xml", "runMountPoint" : "private/run", diff --git a/server/container-config.hpp b/server/container-config.hpp index d5a3038..f5f202e 100644 --- a/server/container-config.hpp +++ b/server/container-config.hpp @@ -43,6 +43,12 @@ struct ContainerConfig { int privilege; /** + * Allow switching to default container after timeout. + * Setting this to false will disable switching to default container after timeout. + */ + bool switchToDefaultAfterTimeout; + + /** * Container's libvirt (XML) config file. * Location can be relative to the Container's config file. */ @@ -83,6 +89,7 @@ struct ContainerConfig { CONFIG_REGISTER ( privilege, + switchToDefaultAfterTimeout, config, networkConfig, cpuQuotaForeground, diff --git a/server/container.cpp b/server/container.cpp index f8a8798..96ca936 100644 --- a/server/container.cpp +++ b/server/container.cpp @@ -182,6 +182,11 @@ bool Container::isPaused() return mAdmin->isPaused(); } +bool Container::isSwitchToDefaultAfterTimeoutAllowed() const +{ + return mConfig.switchToDefaultAfterTimeout; +} + void Container::onNameLostCallback() { LOGI(getId() << ": A connection to the DBUS server has been lost, reconnecting..."); diff --git a/server/container.hpp b/server/container.hpp index 8ab37d8..4c1c879 100644 --- a/server/container.hpp +++ b/server/container.hpp @@ -129,6 +129,11 @@ public: // ContainerConnection API /** + * @return Is switching to default container after timeout allowed? + */ + bool isSwitchToDefaultAfterTimeoutAllowed() const; + + /** * Register notification request callback */ void setNotifyActiveContainerCallback(const NotifyActiveContainerCallback& callback); diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp index 2f8e8dd..657c7bf 100644 --- a/server/containers-manager.cpp +++ b/server/containers-manager.cpp @@ -224,8 +224,15 @@ void ContainersManager::notifyActiveContainerHandler(const std::string& caller, void ContainersManager::displayOffHandler(const std::string& /*caller*/) { - LOGI("Switching to default container " << mConfig.defaultId); - focus(mConfig.defaultId); + // get config of currently set container and switch if switchToDefaultAfterTimeout is true + const std::string activeContainerName = getRunningForegroundContainerId(); + const auto& activeContainer = mContainers.find(activeContainerName); + + if (activeContainer != mContainers.end() && + activeContainer->second->isSwitchToDefaultAfterTimeoutAllowed()) { + LOGI("Switching to default container " << mConfig.defaultId); + focus(mConfig.defaultId); + } } void ContainersManager::handleContainerMoveFileRequest(const std::string& srcContainerId, diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in index e06bf63..341052b 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/buggy.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/buggy.xml", "networkConfig" : "", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf b/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf index 55d6852..7ac04e9 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/missing.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "/this/is/a/missing/file/path/missing.xml", "networkConfig" : "", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in index 6d01a50..8f4da35 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test-no-shutdown.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test-no-shutdown.xml", "networkConfig" : "", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in index 518aa4c..badc3da 100644 --- a/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in +++ b/tests/unit_tests/server/configs/ut-container-admin/containers/test.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-container-admin/libvirt-config/test.xml", "networkConfig" : "", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-container/containers/buggy.conf b/tests/unit_tests/server/configs/ut-container/containers/buggy.conf index d5ccd1e..0dc866a 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/buggy.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/buggy.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "/missing/file/path/libvirt.xml", "networkConfig" : "../libvirt-config/network.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf index fde05d8..bf35f07 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/test-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/test-dbus.xml", "networkConfig" : "../libvirt-config/network.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-container/containers/test.conf b/tests/unit_tests/server/configs/ut-container/containers/test.conf index e1769c3..dc81e44 100644 --- a/tests/unit_tests/server/configs/ut-container/containers/test.conf +++ b/tests/unit_tests/server/configs/ut-container/containers/test.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/test.xml", "networkConfig" : "../libvirt-config/network.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf index 55dfeb5..ef49f19 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/console1-dbus.xml", "networkConfig" : "../libvirt-config/network1.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf index 61668c8..b26e02e 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console1.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/console1.xml", "networkConfig" : "../libvirt-config/network1.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf index 713cb02..76c5e49 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "switchToDefaultAfterTimeout" : false, "config" : "../libvirt-config/console2-dbus.xml", "networkConfig" : "../libvirt-config/network2.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf index 10e5cef..f609a85 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console2.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/console2.xml", "networkConfig" : "../libvirt-config/network2.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf index 70ff251..592cbfa 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3-dbus.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/console3-dbus.xml", "networkConfig" : "../libvirt-config/network3.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf index 8ccf55b..e249df7 100644 --- a/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf +++ b/tests/unit_tests/server/configs/ut-containers-manager/containers/console3.conf @@ -1,5 +1,6 @@ { "privilege" : 15, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/console3.xml", "networkConfig" : "../libvirt-config/network3.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in b/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in index be3f7c1..2b88e29 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/buggy.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "", "networkConfig" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-network-admin/libvirt-config/buggy-network.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf b/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf index f418503..ca580a1 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/missing.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "", "networkConfig" : "", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in b/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in index 771a93b..547c6cd 100644 --- a/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in +++ b/tests/unit_tests/server/configs/ut-network-admin/containers/test.conf.in @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "", "networkConfig" : "@SC_TEST_CONFIG_INSTALL_DIR@/server/ut-network-admin/libvirt-config/network.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-server/containers/container1.conf b/tests/unit_tests/server/configs/ut-server/containers/container1.conf index 952decf..f93690a 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container1.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container1.conf @@ -1,5 +1,6 @@ { "privilege" : 20, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/container1.xml", "networkConfig" : "../libvirt-config/network1.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-server/containers/container2.conf b/tests/unit_tests/server/configs/ut-server/containers/container2.conf index 4e6de09..f519018 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container2.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container2.conf @@ -1,5 +1,6 @@ { "privilege" : 10, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/container2.xml", "networkConfig" : "../libvirt-config/network2.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/configs/ut-server/containers/container3.conf b/tests/unit_tests/server/configs/ut-server/containers/container3.conf index 9170c54..3c5989e 100644 --- a/tests/unit_tests/server/configs/ut-server/containers/container3.conf +++ b/tests/unit_tests/server/configs/ut-server/containers/container3.conf @@ -1,5 +1,6 @@ { "privilege" : 15, + "switchToDefaultAfterTimeout" : true, "config" : "../libvirt-config/container3.xml", "networkConfig" : "../libvirt-config/network3.xml", "cpuQuotaForeground" : -1, diff --git a/tests/unit_tests/server/ut-containers-manager.cpp b/tests/unit_tests/server/ut-containers-manager.cpp index 0182cb8..bf91d9f 100644 --- a/tests/unit_tests/server/ut-containers-manager.cpp +++ b/tests/unit_tests/server/ut-containers-manager.cpp @@ -448,5 +448,53 @@ BOOST_AUTO_TEST_CASE(MoveFileTest) fs::remove_all(CONTAINER2PATH, ec); } +BOOST_AUTO_TEST_CASE(AllowSwitchToDefaultTest) +{ + ContainersManager cm(TEST_DBUS_CONFIG_PATH); + BOOST_REQUIRE_NO_THROW(cm.startAll()); + + std::vector> clients; + for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) { + clients.push_back(std::unique_ptr(new DbusAccessory(i))); + } + + for (auto& client : clients) { + client->setName(fake_power_manager_api::BUS_NAME); + } + + std::mutex condMutex; + std::unique_lock condLock(condMutex); + std::condition_variable condition; + auto cond = [&cm]() -> bool { + return cm.getRunningForegroundContainerId() == "ut-containers-manager-console1-dbus"; + }; + + for (auto& client : clients) { + // focus non-default container with allowed switching + BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console3-dbus")); + + // emit signal from dbus connection + BOOST_REQUIRE_NO_THROW(client->emitSignal(fake_power_manager_api::OBJECT_PATH, + fake_power_manager_api::INTERFACE, + fake_power_manager_api::SIGNAL_DISPLAY_OFF, + nullptr)); + + // check if default container has focus + BOOST_CHECK(condition.wait_for(condLock, std::chrono::milliseconds(EVENT_TIMEOUT), cond)); + + // focus non-default container with disabled switching + BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console2-dbus")); + + // emit signal from dbus connection + BOOST_REQUIRE_NO_THROW(client->emitSignal(fake_power_manager_api::OBJECT_PATH, + fake_power_manager_api::INTERFACE, + fake_power_manager_api::SIGNAL_DISPLAY_OFF, + nullptr)); + + // now default container should not be focused + BOOST_CHECK(!condition.wait_for(condLock, std::chrono::milliseconds(EVENT_TIMEOUT), cond)); + } +} + BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 14f5261f7ce584f000adabc79a004e5d9207ad2c Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Tue, 8 Jul 2014 11:31:31 +0200 Subject: [PATCH 13/16] Containers support package [Bug/Feature] New package to be installed in every container. It replaces image-skel dir. [Cause] N/A [Solution] N/A [Verification] Build, install container-support and container-daemon inside container, install rest packages on host, verify scs works. Change-Id: Ia03a6481d1fe72375cec751701ac9eba1d6cc97c --- CMakeLists.txt | 2 ++ container-support/CMakeLists.txt | 29 ++++++++++++++++++++++ .../configs}/org.tizen.containers.domain.conf.in | 0 .../security-containers-container-support.manifest | 5 ++++ packaging/security-containers.spec | 20 +++++++++++++-- server/configs/CMakeLists.txt | 6 ----- 6 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 container-support/CMakeLists.txt rename {server/configs/image-skel/etc/dbus-1/system.d => container-support/configs}/org.tizen.containers.domain.conf.in (100%) create mode 100644 packaging/security-containers-container-support.manifest diff --git a/CMakeLists.txt b/CMakeLists.txt index e5bc053..266773a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,7 @@ ENDIF(NOT DEFINED PYTHON_SITELIB) SET(COMMON_FOLDER ${PROJECT_SOURCE_DIR}/common) SET(CLIENT_FOLDER ${PROJECT_SOURCE_DIR}/client) SET(SERVER_FOLDER ${PROJECT_SOURCE_DIR}/server) +SET(CONTAINER_SUPPORT_FOLDER ${PROJECT_SOURCE_DIR}/container-support) SET(CONTAINER_DAEMON_FOLDER ${PROJECT_SOURCE_DIR}/container-daemon) SET(TESTS_FOLDER ${PROJECT_SOURCE_DIR}/tests) SET(UNIT_TESTS_FOLDER ${TESTS_FOLDER}/unit_tests) @@ -120,6 +121,7 @@ SET(SC_DATA_INSTALL_DIR ${SHARE_INSTALL_PREFIX}/security-containers) ADD_SUBDIRECTORY(${CLIENT_FOLDER}) ADD_SUBDIRECTORY(${SERVER_FOLDER}) +ADD_SUBDIRECTORY(${CONTAINER_SUPPORT_FOLDER}) ADD_SUBDIRECTORY(${CONTAINER_DAEMON_FOLDER}) ADD_SUBDIRECTORY(${TESTS_FOLDER}) diff --git a/container-support/CMakeLists.txt b/container-support/CMakeLists.txt new file mode 100644 index 0000000..8d9c159 --- /dev/null +++ b/container-support/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) 2014 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 CMakeLists.txt +# @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com) +# + +MESSAGE(STATUS "Generating makefile for the Container Support...") + + +## Install ##################################################################### + +CONFIGURE_FILE(configs/org.tizen.containers.domain.conf.in + ${CMAKE_BINARY_DIR}/dbus-1/system.d/org.tizen.containers.domain.conf) + +INSTALL(FILES ${CMAKE_BINARY_DIR}/dbus-1/system.d/org.tizen.containers.domain.conf + DESTINATION /etc/dbus-1/system.d/) diff --git a/server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf.in b/container-support/configs/org.tizen.containers.domain.conf.in similarity index 100% rename from server/configs/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf.in rename to container-support/configs/org.tizen.containers.domain.conf.in diff --git a/packaging/security-containers-container-support.manifest b/packaging/security-containers-container-support.manifest new file mode 100644 index 0000000..2a0cec5 --- /dev/null +++ b/packaging/security-containers-container-support.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/security-containers.spec b/packaging/security-containers.spec index e214d14..1258c1a 100644 --- a/packaging/security-containers.spec +++ b/packaging/security-containers.spec @@ -39,7 +39,6 @@ between them. A process from inside a container can request a switch of context %config /etc/security-containers/daemon.conf %config /etc/security-containers/containers/*.conf %config /etc/security-containers/libvirt-config/*.xml -/etc/security-containers/image-skel %{_unitdir}/security-containers.service %{_unitdir}/multi-user.target.wants/security-containers.service /etc/dbus-1/system.d/org.tizen.containers.host.conf @@ -134,11 +133,28 @@ Development package including the header files for the client library %{_libdir}/pkgconfig/* +## Container Support Package ################################################### +# TODO move to a separate repository +%package container-support +Summary: Security Containers Support +Group: Security/Other +Conflicts: security-containers + +%description container-support +Containers support installed inside every container. + +%files container-support +%manifest packaging/security-containers-container-support.manifest +%defattr(644,root,root,755) +/etc/dbus-1/system.d/org.tizen.containers.domain.conf + + ## Container Daemon Package #################################################### +# TODO move to a separate repository %package container-daemon Summary: Security Containers Containers Daemon Group: Security/Other -Requires: security-containers = %{version}-%{release} +Requires: security-containers-container-support = %{version}-%{release} %description container-daemon Daemon running inside every container. diff --git a/server/configs/CMakeLists.txt b/server/configs/CMakeLists.txt index 0adcd0d..def06a2 100644 --- a/server/configs/CMakeLists.txt +++ b/server/configs/CMakeLists.txt @@ -35,12 +35,6 @@ INSTALL(FILES daemon.conf # preprocess d-bus configs CONFIGURE_FILE(dbus-1/system.d/org.tizen.containers.host.conf.in ${CMAKE_BINARY_DIR}/dbus-1/system.d/org.tizen.containers.host.conf) -CONFIGURE_FILE(image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf.in - ${CMAKE_BINARY_DIR}/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf) - -# TODO This file should be installed to /etc/dbus-1/system.d/ on an every container -INSTALL(FILES ${CMAKE_BINARY_DIR}/image-skel/etc/dbus-1/system.d/org.tizen.containers.domain.conf - DESTINATION ${SC_CONFIG_INSTALL_DIR}/image-skel/etc/dbus-1/system.d) INSTALL(FILES ${CMAKE_BINARY_DIR}/dbus-1/system.d/org.tizen.containers.host.conf DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d/) -- 2.7.4 From 23cb74030a60c0a0d794b320a451397a559b4f02 Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Mon, 14 Jul 2014 12:33:03 +0200 Subject: [PATCH 14/16] Update input monitor configuration sequence [Bug] Input monitor detected double-pressing, which caused errors. [Cause] Some systems already used double-press as a pattern. [Solution] Change input sequence from double press to triple press. [Verification] Build, install, run SCS with -l TRACE. Run journalctl --unit=security-containers --follow -l Press "HOME" key three times quickly - you should see entries: "Event sequence detected" "Input monitor detected pattern" "switchingSequenceMonitorNotify() called" Change-Id: I52850851f1c72326d50b796d651886c7eec3406c Signed-off-by: Lukasz Kostyra --- server/configs/daemon.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/configs/daemon.conf b/server/configs/daemon.conf index c67f607..9c0eba6 100644 --- a/server/configs/daemon.conf +++ b/server/configs/daemon.conf @@ -7,6 +7,6 @@ "inputConfig" : {"enabled" : true, "device" : "gpio-keys", "code" : 139, - "numberOfEvents" : 2, + "numberOfEvents" : 3, "timeWindowMs" : 500} } -- 2.7.4 From ef1c5e0915624562910c91855d53c5b834d90bca Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Fri, 11 Jul 2014 16:38:19 +0200 Subject: [PATCH 15/16] Dbus async method call [Bug/Feature] Async version of dbus method call added. [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I90bb5d1816a95f9619e2a4b88dd63c9ebd4b64da --- common/dbus/connection.cpp | 70 ++++++++++++++++- common/dbus/connection.hpp | 26 +++++++ common/utils/scoped-gerror.cpp | 5 ++ common/utils/scoped-gerror.hpp | 5 ++ tests/unit_tests/dbus/test-server.cpp | 2 +- tests/unit_tests/dbus/ut-connection.cpp | 130 +++++++++++++++++++++++++++++--- 6 files changed, 225 insertions(+), 13 deletions(-) diff --git a/common/dbus/connection.cpp b/common/dbus/connection.cpp index 479c253..4a4a2cd 100644 --- a/common/dbus/connection.cpp +++ b/common/dbus/connection.cpp @@ -87,6 +87,28 @@ void throwDbusException(const ScopedGError& e) } } +class AsyncMethodCallResultImpl : public AsyncMethodCallResult { +public: + AsyncMethodCallResultImpl(GVariant* result, const ScopedGError& error) + : mResult(result), mError(error) {} + ~AsyncMethodCallResultImpl() + { + if (mResult) { + g_variant_unref(mResult); + } + } + GVariant* get() + { + if (mError) { + throwDbusException(mError); + } + return mResult; + } +private: + GVariant* mResult; + const ScopedGError& mError; +}; + } // namespace DbusConnection::Pointer DbusConnection::create(const std::string& address) @@ -308,7 +330,8 @@ GVariantPtr DbusConnection::callMethod(const std::string& busName, interface.c_str(), method.c_str(), parameters, - G_VARIANT_TYPE(replyType.c_str()), + replyType.empty() ? NULL + : G_VARIANT_TYPE(replyType.c_str()), G_DBUS_CALL_FLAGS_NONE, CALL_METHOD_TIMEOUT_MS, NULL, @@ -321,6 +344,51 @@ GVariantPtr DbusConnection::callMethod(const std::string& busName, return GVariantPtr(result, g_variant_unref); } +void DbusConnection::callMethodAsync(const std::string& busName, + const std::string& objectPath, + const std::string& interface, + const std::string& method, + GVariant* parameters, + const std::string& replyType, + const AsyncMethodCallCallback& callback) +{ + g_dbus_connection_call(mConnection, + busName.c_str(), + objectPath.c_str(), + interface.c_str(), + method.c_str(), + parameters, + replyType.empty() ? NULL + : G_VARIANT_TYPE(replyType.c_str()), + G_DBUS_CALL_FLAGS_NONE, + CALL_METHOD_TIMEOUT_MS, + NULL, + &DbusConnection::onAsyncReady, + utils::createCallbackWrapper(callback, mGuard.spawn())); +} + +void DbusConnection::onAsyncReady(GObject* source, + GAsyncResult* asyncResult, + gpointer userData) +{ + std::unique_ptr + autoDeleteCallback(userData, &utils::deleteCallbackWrapper); + GDBusConnection* connection = reinterpret_cast(source); + const AsyncMethodCallCallback& callback = + utils::getCallbackFromPointer(userData); + + ScopedGError error; + GVariant* result = g_dbus_connection_call_finish(connection, asyncResult, &error); + if (error) { + error.strip(); + LOGE("Call method failed; " << error); + } + AsyncMethodCallResultImpl asyncMethodCallResult(result, error); + if (callback) { + callback(asyncMethodCallResult); + } +} + } // namespace dbus } // namespace security_containers diff --git a/common/dbus/connection.hpp b/common/dbus/connection.hpp index cbdbdf5..28932af 100644 --- a/common/dbus/connection.hpp +++ b/common/dbus/connection.hpp @@ -51,6 +51,15 @@ public: }; /** + * An interface used to get result from async response. + */ +class AsyncMethodCallResult { +public: + virtual ~AsyncMethodCallResult() {} + virtual GVariant* get() = 0; // throws DbusException on error +}; + +/** * Dbus connection. * Provides a functionality that allows to call dbus methods, * register dbus interfaces, etc. @@ -77,6 +86,9 @@ public: GVariant* parameters )> SignalCallback; + typedef std::function AsyncMethodCallCallback; + /** * Creates a connection to the dbus with given address. */ @@ -130,6 +142,17 @@ public: const std::string& replyType); /** + * Async call a dbus method + */ + void callMethodAsync(const std::string& busName, + const std::string& objectPath, + const std::string& interface, + const std::string& method, + GVariant* parameters, + const std::string& replyType, + const AsyncMethodCallCallback& callback); + + /** * Returns an xml with meta description of specified dbus object. */ std::string introspect(const std::string& busName, const std::string& objectPath); @@ -166,6 +189,9 @@ private: GVariant* parameters, GDBusMethodInvocation* invocation, gpointer userData); + static void onAsyncReady(GObject* source, + GAsyncResult* asyncResult, + gpointer userData); }; diff --git a/common/utils/scoped-gerror.cpp b/common/utils/scoped-gerror.cpp index 303dd4e..7ce85d4 100644 --- a/common/utils/scoped-gerror.cpp +++ b/common/utils/scoped-gerror.cpp @@ -32,7 +32,12 @@ namespace utils { ScopedGError::ScopedGError() : mError(NULL) { +} +ScopedGError::ScopedGError(ScopedGError&& other) + : mError(other.mError) +{ + other.mError = NULL; } ScopedGError::~ScopedGError() diff --git a/common/utils/scoped-gerror.hpp b/common/utils/scoped-gerror.hpp index 06e17aa..6df8085 100644 --- a/common/utils/scoped-gerror.hpp +++ b/common/utils/scoped-gerror.hpp @@ -34,8 +34,12 @@ namespace utils { class ScopedGError { public: ScopedGError(); + ScopedGError(ScopedGError&&); ~ScopedGError(); + ScopedGError(const ScopedGError&) = delete; + ScopedGError& operator=(const ScopedGError&) = delete; + /** * Strip the error */ @@ -65,6 +69,7 @@ public: private: GError* mError; + }; } // namespace utils diff --git a/tests/unit_tests/dbus/test-server.cpp b/tests/unit_tests/dbus/test-server.cpp index 6fcbbda..711f16f 100644 --- a/tests/unit_tests/dbus/test-server.cpp +++ b/tests/unit_tests/dbus/test-server.cpp @@ -142,7 +142,7 @@ void DbusTestServer::onMessageCall(const std::string& objectPath, LOGE("unknown method; should never happen"); } } catch (const std::exception& e) { - result.setError("org.tizen.Exception", e.what()); + result.setError("org.tizen.containers.Error.Test", e.what()); } } diff --git a/tests/unit_tests/dbus/ut-connection.cpp b/tests/unit_tests/dbus/ut-connection.cpp index 46b9aa9..131e359 100644 --- a/tests/unit_tests/dbus/ut-connection.cpp +++ b/tests/unit_tests/dbus/ut-connection.cpp @@ -325,21 +325,129 @@ BOOST_AUTO_TEST_CASE(MethodCallTest) const std::string& methodName, GVariant* parameters, MethodResultBuilder& result) { - if (objectPath == TESTAPI_OBJECT_PATH && - interface == TESTAPI_INTERFACE && - methodName == TESTAPI_METHOD_NOOP && - g_variant_is_of_type(parameters, G_VARIANT_TYPE_UNIT)) { + if (objectPath != TESTAPI_OBJECT_PATH || interface != TESTAPI_INTERFACE) { + return; + } + if (methodName == TESTAPI_METHOD_NOOP) { result.setVoid(); + } else if (methodName == TESTAPI_METHOD_PROCESS) { + const gchar* arg = NULL; + g_variant_get(parameters, "(&s)", &arg); + std::string str = std::string("resp: ") + arg; + result.set(g_variant_new("(s)", str.c_str())); + } else if (methodName == TESTAPI_METHOD_THROW) { + int arg = 0; + g_variant_get(parameters, "(i)", &arg); + result.setError("org.tizen.containers.Error.Test", "msg: " + std::to_string(arg)); } }; conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); - GVariantPtr result = conn2->callMethod(TESTAPI_BUS_NAME, - TESTAPI_OBJECT_PATH, - TESTAPI_INTERFACE, - TESTAPI_METHOD_NOOP, - NULL, - "()"); - BOOST_CHECK(g_variant_is_of_type(result.get(), G_VARIANT_TYPE_UNIT)); + + GVariantPtr result1 = conn2->callMethod(TESTAPI_BUS_NAME, + TESTAPI_OBJECT_PATH, + TESTAPI_INTERFACE, + TESTAPI_METHOD_NOOP, + NULL, + "()"); + BOOST_CHECK(g_variant_is_of_type(result1.get(), G_VARIANT_TYPE_UNIT)); + + GVariantPtr result2 = conn2->callMethod(TESTAPI_BUS_NAME, + TESTAPI_OBJECT_PATH, + TESTAPI_INTERFACE, + TESTAPI_METHOD_PROCESS, + g_variant_new("(s)", "arg"), + "(s)"); + const gchar* ret2 = NULL; + g_variant_get(result2.get(), "(&s)", &ret2); + BOOST_CHECK_EQUAL("resp: arg", ret2); + + BOOST_CHECK_THROW(conn2->callMethod(TESTAPI_BUS_NAME, + TESTAPI_OBJECT_PATH, + TESTAPI_INTERFACE, + TESTAPI_METHOD_THROW, + g_variant_new("(i)", 7), + "()"), + DbusCustomException); +} + +BOOST_AUTO_TEST_CASE(MethodAsyncCallTest) +{ + ScopedDbusDaemon daemon; + ScopedGlibLoop loop; + Latch nameAcquired; + + DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS); + DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS); + + conn1->setName(TESTAPI_BUS_NAME, + [&] {nameAcquired.set();}, + [] {}); + BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT)); + auto handler = [](const std::string& objectPath, + const std::string& interface, + const std::string& methodName, + GVariant* parameters, + MethodResultBuilder& result) { + if (objectPath != TESTAPI_OBJECT_PATH || interface != TESTAPI_INTERFACE) { + return; + } + if (methodName == TESTAPI_METHOD_NOOP) { + result.setVoid(); + } else if (methodName == TESTAPI_METHOD_PROCESS) { + const gchar* arg = NULL; + g_variant_get(parameters, "(&s)", &arg); + std::string str = std::string("resp: ") + arg; + result.set(g_variant_new("(s)", str.c_str())); + } else if (methodName == TESTAPI_METHOD_THROW) { + int arg = 0; + g_variant_get(parameters, "(i)", &arg); + result.setError("org.tizen.containers.Error.Test", "msg: " + std::to_string(arg)); + } + }; + conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); + + Latch callDone; + + auto asyncResult1 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { + BOOST_CHECK(g_variant_is_of_type(asyncMethodCallResult.get(), G_VARIANT_TYPE_UNIT)); + callDone.set(); + }; + conn2->callMethodAsync(TESTAPI_BUS_NAME, + TESTAPI_OBJECT_PATH, + TESTAPI_INTERFACE, + TESTAPI_METHOD_NOOP, + NULL, + "()", + asyncResult1); + BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); + + auto asyncResult2 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { + const gchar* ret = NULL; + g_variant_get(asyncMethodCallResult.get(), "(&s)", &ret); + BOOST_CHECK_EQUAL("resp: arg", ret); + callDone.set(); + }; + conn2->callMethodAsync(TESTAPI_BUS_NAME, + TESTAPI_OBJECT_PATH, + TESTAPI_INTERFACE, + TESTAPI_METHOD_PROCESS, + g_variant_new("(s)", "arg"), + "(s)", + asyncResult2); + BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); + + auto asyncResult3 = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { + BOOST_CHECK_THROW(asyncMethodCallResult.get(), DbusCustomException); + callDone.set(); + }; + conn2->callMethodAsync(TESTAPI_BUS_NAME, + TESTAPI_OBJECT_PATH, + TESTAPI_INTERFACE, + TESTAPI_METHOD_THROW, + g_variant_new("(i)", 7), + "()", + asyncResult3); + BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); } BOOST_AUTO_TEST_CASE(MethodCallExceptionTest) -- 2.7.4 From af83a11b30b0cb761b1fbb178652416339534be7 Mon Sep 17 00:00:00 2001 From: Piotr Bartosiewicz Date: Tue, 15 Jul 2014 16:51:26 +0200 Subject: [PATCH 16/16] Dbus async method call handler [Bug/Feature] Enable deferred set of result in dbus method handler. [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I11b3abe0886bc560f8b63f6206c64695f2f7eb1a --- common/dbus/connection.cpp | 17 ++++---- common/dbus/connection.hpp | 4 +- container-daemon/daemon-connection.cpp | 6 +-- container-daemon/daemon-connection.hpp | 2 +- server/container-connection.cpp | 4 +- server/container-connection.hpp | 4 +- server/containers-manager.cpp | 14 +++---- server/containers-manager.hpp | 2 +- server/host-connection.cpp | 4 +- server/host-connection.hpp | 2 +- tests/unit_tests/dbus/test-server.cpp | 10 ++--- tests/unit_tests/dbus/test-server.hpp | 2 +- tests/unit_tests/dbus/ut-connection.cpp | 73 +++++++++++++++++++++++++++++---- 13 files changed, 100 insertions(+), 44 deletions(-) diff --git a/common/dbus/connection.cpp b/common/dbus/connection.cpp index 4a4a2cd..ef6fc46 100644 --- a/common/dbus/connection.cpp +++ b/common/dbus/connection.cpp @@ -47,6 +47,12 @@ class MethodResultBuilderImpl : public MethodResultBuilder { public: MethodResultBuilderImpl(GDBusMethodInvocation* invocation) : mInvocation(invocation), mResultSet(false) {} + ~MethodResultBuilderImpl() + { + if (!mResultSet) { + setError("org.freedesktop.DBus.Error.UnknownMethod", "Not implemented"); + } + } void set(GVariant* parameters) { g_dbus_method_invocation_return_value(mInvocation, parameters); @@ -61,10 +67,6 @@ public: g_dbus_method_invocation_return_dbus_error(mInvocation, name.c_str(), message.c_str()); mResultSet = true; } - bool isUndefined() const - { - return !mResultSet; - } private: GDBusMethodInvocation* mInvocation; bool mResultSet; @@ -305,15 +307,10 @@ void DbusConnection::onMethodCall(GDBusConnection*, LOGD("MethodCall: " << objectPath << "; " << interface << "; " << method); - MethodResultBuilderImpl resultBuilder(invocation); + MethodResultBuilder::Pointer resultBuilder(new MethodResultBuilderImpl(invocation)); if (callback) { callback(objectPath, interface, method, parameters, resultBuilder); } - - if (resultBuilder.isUndefined()) { - LOGW("Unimplemented method: " << objectPath << "; " << interface << "; " << method); - resultBuilder.setError("org.freedesktop.DBus.Error.UnknownMethod", "Not implemented"); - } } GVariantPtr DbusConnection::callMethod(const std::string& busName, diff --git a/common/dbus/connection.hpp b/common/dbus/connection.hpp index 28932af..9ac87de 100644 --- a/common/dbus/connection.hpp +++ b/common/dbus/connection.hpp @@ -44,6 +44,8 @@ typedef std::unique_ptr GVariantPtr; */ class MethodResultBuilder { public: + typedef std::shared_ptr Pointer; + virtual ~MethodResultBuilder() {} virtual void set(GVariant* parameters) = 0; virtual void setVoid() = 0; @@ -76,7 +78,7 @@ public: const std::string& interface, const std::string& methodName, GVariant* parameters, - MethodResultBuilder& result + MethodResultBuilder::Pointer result )> MethodCallCallback; typedef std::functionsetVoid(); } } else if (methodName == api::METHOD_LOSE_FOCUS) { if (mLoseFocusCallback) { mLoseFocusCallback(); - result.setVoid(); + result->setVoid(); } } } diff --git a/container-daemon/daemon-connection.hpp b/container-daemon/daemon-connection.hpp index e2e5154..34129df 100644 --- a/container-daemon/daemon-connection.hpp +++ b/container-daemon/daemon-connection.hpp @@ -68,7 +68,7 @@ private: const std::string& interface, const std::string& methodName, GVariant* parameters, - dbus::MethodResultBuilder& result); + dbus::MethodResultBuilder::Pointer result); }; diff --git a/server/container-connection.cpp b/server/container-connection.cpp index 3ef2dd7..adabace 100644 --- a/server/container-connection.cpp +++ b/server/container-connection.cpp @@ -150,7 +150,7 @@ void ContainerConnection::onMessageCall(const std::string& objectPath, const std::string& interface, const std::string& methodName, GVariant* parameters, - dbus::MethodResultBuilder& result) + dbus::MethodResultBuilder::Pointer result) { if (objectPath != api::OBJECT_PATH || interface != api::INTERFACE) { return; @@ -162,7 +162,7 @@ void ContainerConnection::onMessageCall(const std::string& objectPath, g_variant_get(parameters, "(&s&s)", &application, &message); if (mNotifyActiveContainerCallback) { mNotifyActiveContainerCallback(application, message); - result.setVoid(); + result->setVoid(); } } diff --git a/server/container-connection.hpp b/server/container-connection.hpp index 2f429ce..7759a09 100644 --- a/server/container-connection.hpp +++ b/server/container-connection.hpp @@ -52,7 +52,7 @@ public: typedef std::function FileMoveRequestCallback; /** @@ -96,7 +96,7 @@ private: const std::string& interface, const std::string& methodName, GVariant* parameters, - dbus::MethodResultBuilder& result); + dbus::MethodResultBuilder::Pointer result); void onSignalReceived(const std::string& senderBusName, const std::string& objectPath, const std::string& interface, diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp index 657c7bf..0150e4a 100644 --- a/server/containers-manager.cpp +++ b/server/containers-manager.cpp @@ -238,7 +238,7 @@ void ContainersManager::displayOffHandler(const std::string& /*caller*/) void ContainersManager::handleContainerMoveFileRequest(const std::string& srcContainerId, const std::string& dstContainerId, const std::string& path, - dbus::MethodResultBuilder& result) + dbus::MethodResultBuilder::Pointer result) { // TODO: this implementation is only a placeholder. // There are too many unanswered questions and security concerns: @@ -274,26 +274,26 @@ void ContainersManager::handleContainerMoveFileRequest(const std::string& srcCon ContainerMap::const_iterator dstIter = mContainers.find(dstContainerId); if (dstIter == mContainers.end()) { LOGE("Destination container '" << dstContainerId << "' not found"); - result.set(g_variant_new("(s)", api::FILE_MOVE_DESTINATION_NOT_FOUND.c_str())); + result->set(g_variant_new("(s)", api::FILE_MOVE_DESTINATION_NOT_FOUND.c_str())); return; } Container& dstContanier = *dstIter->second; if (srcContainerId == dstContainerId) { LOGE("Cannot send a file to yourself"); - result.set(g_variant_new("(s)", api::FILE_MOVE_WRONG_DESTINATION.c_str())); + result->set(g_variant_new("(s)", api::FILE_MOVE_WRONG_DESTINATION.c_str())); return; } if (!regexMatchVector(path, srcContainer.getPermittedToSend())) { LOGE("Source container has no permissions to send the file: " << path); - result.set(g_variant_new("(s)", api::FILE_MOVE_NO_PERMISSIONS_SEND.c_str())); + result->set(g_variant_new("(s)", api::FILE_MOVE_NO_PERMISSIONS_SEND.c_str())); return; } if (!regexMatchVector(path, dstContanier.getPermittedToRecv())) { LOGE("Destination container has no permissions to receive the file: " << path); - result.set(g_variant_new("(s)", api::FILE_MOVE_NO_PERMISSIONS_RECEIVE.c_str())); + result->set(g_variant_new("(s)", api::FILE_MOVE_NO_PERMISSIONS_RECEIVE.c_str())); return; } @@ -303,9 +303,9 @@ void ContainersManager::handleContainerMoveFileRequest(const std::string& srcCon if (!utils::moveFile(srcPath, dstPath)) { LOGE("Failed to move the file: " << path); - result.set(g_variant_new("(s)", api::FILE_MOVE_FAILED.c_str())); + result->set(g_variant_new("(s)", api::FILE_MOVE_FAILED.c_str())); } else { - result.set(g_variant_new("(s)", api::FILE_MOVE_SUCCEEDED.c_str())); + result->set(g_variant_new("(s)", api::FILE_MOVE_SUCCEEDED.c_str())); try { dstContanier.sendNotification(srcContainerId, path, api::FILE_MOVE_SUCCEEDED); } catch (ServerException&) { diff --git a/server/containers-manager.hpp b/server/containers-manager.hpp index 32ca341..1e29ed7 100644 --- a/server/containers-manager.hpp +++ b/server/containers-manager.hpp @@ -91,7 +91,7 @@ private: void handleContainerMoveFileRequest(const std::string& srcContainerId, const std::string& dstContainerId, const std::string& path, - dbus::MethodResultBuilder& result); + dbus::MethodResultBuilder::Pointer result); }; diff --git a/server/host-connection.cpp b/server/host-connection.cpp index 4b3c59d..4f9a2f2 100644 --- a/server/host-connection.cpp +++ b/server/host-connection.cpp @@ -119,7 +119,7 @@ void HostConnection::onMessageCall(const std::string& objectPath, const std::string& interface, const std::string& methodName, GVariant* /*parameters*/, - dbus::MethodResultBuilder& result) + dbus::MethodResultBuilder::Pointer result) { if (objectPath != hostapi::OBJECT_PATH || interface != hostapi::INTERFACE) { return; @@ -128,7 +128,7 @@ void HostConnection::onMessageCall(const std::string& objectPath, if (methodName == hostapi::METHOD_TEST) { if (mTestCallback) { mTestCallback(); - result.setVoid(); + result->setVoid(); } } } diff --git a/server/host-connection.hpp b/server/host-connection.hpp index 4d7eccd..d78949f 100644 --- a/server/host-connection.hpp +++ b/server/host-connection.hpp @@ -66,7 +66,7 @@ private: const std::string& interface, const std::string& methodName, GVariant* parameters, - dbus::MethodResultBuilder& result); + dbus::MethodResultBuilder::Pointer result); }; diff --git a/tests/unit_tests/dbus/test-server.cpp b/tests/unit_tests/dbus/test-server.cpp index 711f16f..3a77390 100644 --- a/tests/unit_tests/dbus/test-server.cpp +++ b/tests/unit_tests/dbus/test-server.cpp @@ -117,7 +117,7 @@ void DbusTestServer::onMessageCall(const std::string& objectPath, const std::string& interface, const std::string& methodName, GVariant* parameters, - dbus::MethodResultBuilder& result) + dbus::MethodResultBuilder::Pointer result) { try { if (objectPath != TESTAPI_OBJECT_PATH || interface != TESTAPI_INTERFACE) { @@ -126,23 +126,23 @@ void DbusTestServer::onMessageCall(const std::string& objectPath, if (methodName == TESTAPI_METHOD_NOOP) { noop(); - result.setVoid(); + result->setVoid(); } else if (methodName == TESTAPI_METHOD_PROCESS) { const gchar* arg; g_variant_get(parameters, "(&s)", &arg); std::string ret = process(arg); GVariant* variant = g_variant_new("(s)", ret.c_str()); - result.set(variant); + result->set(variant); } else if (methodName == TESTAPI_METHOD_THROW) { int arg; g_variant_get(parameters, "(i)", &arg); throwException(arg); - result.setVoid(); + result->setVoid(); } else { LOGE("unknown method; should never happen"); } } catch (const std::exception& e) { - result.setError("org.tizen.containers.Error.Test", e.what()); + result->setError("org.tizen.containers.Error.Test", e.what()); } } diff --git a/tests/unit_tests/dbus/test-server.hpp b/tests/unit_tests/dbus/test-server.hpp index b52ebb3..8e2aa7f 100644 --- a/tests/unit_tests/dbus/test-server.hpp +++ b/tests/unit_tests/dbus/test-server.hpp @@ -73,7 +73,7 @@ private: const std::string& interface, const std::string& methodName, GVariant* parameters, - dbus::MethodResultBuilder& result); + dbus::MethodResultBuilder::Pointer result); }; diff --git a/tests/unit_tests/dbus/ut-connection.cpp b/tests/unit_tests/dbus/ut-connection.cpp index 131e359..21be1e8 100644 --- a/tests/unit_tests/dbus/ut-connection.cpp +++ b/tests/unit_tests/dbus/ut-connection.cpp @@ -324,21 +324,21 @@ BOOST_AUTO_TEST_CASE(MethodCallTest) const std::string& interface, const std::string& methodName, GVariant* parameters, - MethodResultBuilder& result) { + MethodResultBuilder::Pointer result) { if (objectPath != TESTAPI_OBJECT_PATH || interface != TESTAPI_INTERFACE) { return; } if (methodName == TESTAPI_METHOD_NOOP) { - result.setVoid(); + result->setVoid(); } else if (methodName == TESTAPI_METHOD_PROCESS) { const gchar* arg = NULL; g_variant_get(parameters, "(&s)", &arg); std::string str = std::string("resp: ") + arg; - result.set(g_variant_new("(s)", str.c_str())); + result->set(g_variant_new("(s)", str.c_str())); } else if (methodName == TESTAPI_METHOD_THROW) { int arg = 0; g_variant_get(parameters, "(i)", &arg); - result.setError("org.tizen.containers.Error.Test", "msg: " + std::to_string(arg)); + result->setError("org.tizen.containers.Error.Test", "msg: " + std::to_string(arg)); } }; conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); @@ -387,21 +387,21 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallTest) const std::string& interface, const std::string& methodName, GVariant* parameters, - MethodResultBuilder& result) { + MethodResultBuilder::Pointer result) { if (objectPath != TESTAPI_OBJECT_PATH || interface != TESTAPI_INTERFACE) { return; } if (methodName == TESTAPI_METHOD_NOOP) { - result.setVoid(); + result->setVoid(); } else if (methodName == TESTAPI_METHOD_PROCESS) { const gchar* arg = NULL; g_variant_get(parameters, "(&s)", &arg); std::string str = std::string("resp: ") + arg; - result.set(g_variant_new("(s)", str.c_str())); + result->set(g_variant_new("(s)", str.c_str())); } else if (methodName == TESTAPI_METHOD_THROW) { int arg = 0; g_variant_get(parameters, "(i)", &arg); - result.setError("org.tizen.containers.Error.Test", "msg: " + std::to_string(arg)); + result->setError("org.tizen.containers.Error.Test", "msg: " + std::to_string(arg)); } }; conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); @@ -450,6 +450,63 @@ BOOST_AUTO_TEST_CASE(MethodAsyncCallTest) BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); } +BOOST_AUTO_TEST_CASE(MethodAsyncCallAsyncHandlerTest) +{ + ScopedDbusDaemon daemon; + ScopedGlibLoop loop; + Latch nameAcquired; + + DbusConnection::Pointer conn1 = DbusConnection::create(DBUS_ADDRESS); + DbusConnection::Pointer conn2 = DbusConnection::create(DBUS_ADDRESS); + + conn1->setName(TESTAPI_BUS_NAME, + [&] {nameAcquired.set();}, + [] {}); + BOOST_REQUIRE(nameAcquired.wait(EVENT_TIMEOUT)); + + Latch handlerDone; + std::string strResult; + MethodResultBuilder::Pointer deferredResult; + + auto handler = [&](const std::string& objectPath, + const std::string& interface, + const std::string& methodName, + GVariant* parameters, + MethodResultBuilder::Pointer result) { + if (objectPath != TESTAPI_OBJECT_PATH || interface != TESTAPI_INTERFACE) { + return; + } + if (methodName == TESTAPI_METHOD_PROCESS) { + const gchar* arg = NULL; + g_variant_get(parameters, "(&s)", &arg); + strResult = std::string("resp: ") + arg; + deferredResult = result; + handlerDone.set(); + } + }; + conn1->registerObject(TESTAPI_OBJECT_PATH, TESTAPI_DEFINITION, handler); + + Latch callDone; + + auto asyncResult = [&](dbus::AsyncMethodCallResult& asyncMethodCallResult) { + const gchar* ret = NULL; + g_variant_get(asyncMethodCallResult.get(), "(&s)", &ret); + BOOST_CHECK_EQUAL("resp: arg", ret); + callDone.set(); + }; + conn2->callMethodAsync(TESTAPI_BUS_NAME, + TESTAPI_OBJECT_PATH, + TESTAPI_INTERFACE, + TESTAPI_METHOD_PROCESS, + g_variant_new("(s)", "arg"), + "(s)", + asyncResult); + BOOST_REQUIRE(handlerDone.wait(EVENT_TIMEOUT)); + BOOST_REQUIRE(callDone.empty()); + deferredResult->set(g_variant_new("(s)", strResult.c_str())); + BOOST_REQUIRE(callDone.wait(EVENT_TIMEOUT)); +} + BOOST_AUTO_TEST_CASE(MethodCallExceptionTest) { ScopedDbusDaemon daemon; -- 2.7.4