From: Mateusz Malicki Date: Fri, 17 Jul 2015 14:49:43 +0000 (+0200) Subject: Clean up zones root path X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=da007dabea6e5a0724844ed7eae1e48cd598b723;p=platform%2Fcore%2Fsecurity%2Fvasum.git Clean up zones root path [Feature] Clean up zones root path (according to cleanUpZonesPath flag) [Cause] N/A [Solution] Added cleanUpZonesPath to daemon.conf which tells whether to remove unknown files from the zonesPath; Added (vsm_)clean_up_zones_root to cli and client [Verification] Build, install, create files in zonesPath, run vasum-server with different flag value, check if zonesPath is as it should; execute command Change-Id: I64a1656ef05ccd5fd7e83a48cd50234e2e6bd4b4 --- diff --git a/cli/command-line-interface.cpp b/cli/command-line-interface.cpp index cdd64b4..29dd4a3 100644 --- a/cli/command-line-interface.cpp +++ b/cli/command-line-interface.cpp @@ -649,5 +649,12 @@ void netdev_down(const Args& argv) argv[2].c_str())); } +void clean_up_zones_root(const Args& /* argv */) +{ + using namespace std::placeholders; + + CommandLineInterface::executeCallback(bind(vsm_clean_up_zones_root, _1)); +} + } // namespace cli } // namespace vasum diff --git a/cli/command-line-interface.hpp b/cli/command-line-interface.hpp index 54ea7b9..f13fab5 100644 --- a/cli/command-line-interface.hpp +++ b/cli/command-line-interface.hpp @@ -340,6 +340,13 @@ void netdev_up(const Args& argv); */ void netdev_down(const Args& argv); +/** + * Parses command line arguments and call vsm_clean_up_zones_root + * + * @see vsm_clean_up_zones_root + */ +void clean_up_zones_root(const Args& argv); + } // namespace cli } // namespace vasum diff --git a/cli/main.cpp b/cli/main.cpp index c5fe0c1..efff7c6 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -328,6 +328,15 @@ std::map commands = { {{"zone_id", "id zone name"}, {"netdev_id", "network device id"}} } + }, + { + "clean_up_zones_root", { + clean_up_zones_root, + "clean_up_zones_root", + "Clean up zones root directory", + MODE_COMMAND_LINE | MODE_INTERACTIVE, + {} + } } }; diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index d99b08b..78c2d8f 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -882,3 +882,12 @@ VsmStatus Client::vsm_remove_declaration(const char* id, VsmString declaration) }); } +VsmStatus Client::vsm_clean_up_zones_root() noexcept +{ + return coverException([&] { + mClient->callSync( + api::ipc::METHOD_CLEAN_UP_ZONES_ROOT, + std::make_shared()); + }); +} + diff --git a/client/vasum-client-impl.hpp b/client/vasum-client-impl.hpp index 57797c2..1195b66 100644 --- a/client/vasum-client-impl.hpp +++ b/client/vasum-client-impl.hpp @@ -340,6 +340,11 @@ public: */ VsmStatus vsm_remove_declaration(const char* zone, VsmString declaration) noexcept; + /** + * @see ::vsm_clean_up_zones_root + */ + VsmStatus vsm_clean_up_zones_root() noexcept; + private: struct Status { Status(); diff --git a/client/vasum-client.cpp b/client/vasum-client.cpp index ac77187..68496d5 100644 --- a/client/vasum-client.cpp +++ b/client/vasum-client.cpp @@ -390,3 +390,8 @@ API VsmStatus vsm_remove_declaration(VsmClient client, return getClient(client).vsm_remove_declaration(zone, declaration); } +API VsmStatus vsm_clean_up_zones_root(VsmClient client) +{ + return getClient(client).vsm_clean_up_zones_root(); +} + diff --git a/client/vasum-client.h b/client/vasum-client.h index cd38aee..06ad043 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -894,6 +894,13 @@ VsmStatus vsm_remove_declaration(VsmClient client, const char* zone, VsmString declaration); +/** + * Clean up zones root directory + * + * Removes all unknown zones root directory entry + * @return status of this function call + */ +VsmStatus vsm_clean_up_zones_root(VsmClient client); /** @} Host API */ diff --git a/server/configs/daemon.conf.in b/server/configs/daemon.conf.in index f3dd9fd..96d748f 100644 --- a/server/configs/daemon.conf.in +++ b/server/configs/daemon.conf.in @@ -2,6 +2,7 @@ "dbPath" : "/etc/vasum/vasum.db", "zoneIds" : [], "zonesPath" : "${DATA_DIR}/zones", + "cleanUpZonesPath" : false, "zoneImagePath" : "", "zoneTemplateDir" : "/etc/vasum/templates/", "runMountPointPrefix" : "/var/run/zones", diff --git a/server/host-dbus-connection.cpp b/server/host-dbus-connection.cpp index 53fc271..90a248b 100644 --- a/server/host-dbus-connection.cpp +++ b/server/host-dbus-connection.cpp @@ -405,6 +405,12 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath, mZonesManagerPtr->handleSwitchToDefaultCall(EMPTY_CALLER, rb); return; } + + if (methodName == api::dbus::METHOD_CLEAN_UP_ZONES_ROOT) { + auto rb = std::make_shared>(result); + mZonesManagerPtr->handleCleanUpZonesRootCall(rb); + return; + } } void HostDbusConnection::onClientVanished(const std::string& name) diff --git a/server/host-dbus-definitions.hpp b/server/host-dbus-definitions.hpp index 7aeaf31..d06d087 100644 --- a/server/host-dbus-definitions.hpp +++ b/server/host-dbus-definitions.hpp @@ -66,6 +66,7 @@ const std::string METHOD_CREATE_FILE = "CreateFile"; const std::string METHOD_LOCK_QUEUE = "LockQueue"; const std::string METHOD_UNLOCK_QUEUE = "UnlockQueue"; const std::string METHOD_SWITCH_TO_DEFAULT = "SwitchToDefault"; +const std::string METHOD_CLEAN_UP_ZONES_ROOT = "CleanUpZonesRoot"; const std::string DEFINITION = "" @@ -205,6 +206,8 @@ const std::string DEFINITION = " " " " " " + " " + " " " " ""; diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp index d3684b9..c2ba755 100644 --- a/server/host-ipc-connection.cpp +++ b/server/host-ipc-connection.cpp @@ -135,6 +135,9 @@ HostIPCConnection::HostIPCConnection(ipc::epoll::EventPoll& eventPoll, ZonesMana setCreateFileCallback(std::bind(&ZonesManager::handleCreateFileCall, mZonesManagerPtr, _1, _2)); + + setCleanUpZonesRootCallback(std::bind(&ZonesManager::handleCleanUpZonesRootCall, + mZonesManagerPtr, _1)); } HostIPCConnection::~HostIPCConnection() @@ -392,4 +395,12 @@ void HostIPCConnection::setCreateFileCallback(const Method::type& callback) +{ + typedef IPCMethodWrapper Callback; + mService->setMethodHandler( + api::ipc::METHOD_CLEAN_UP_ZONES_ROOT, + Callback::getWrapper(callback)); +} + } // namespace vasum diff --git a/server/host-ipc-connection.hpp b/server/host-ipc-connection.hpp index da3dbd4..47a7612 100644 --- a/server/host-ipc-connection.hpp +++ b/server/host-ipc-connection.hpp @@ -87,6 +87,7 @@ private: void setRevokeDeviceCallback(const Method::type& callback); void setSwitchToDefaultCallback(const Method::type& callback); void setCreateFileCallback(const Method::type& callback); + void setCleanUpZonesRootCallback(const Method::type& callback); std::unique_ptr mService; ZonesManager* mZonesManagerPtr; diff --git a/server/host-ipc-definitions.hpp b/server/host-ipc-definitions.hpp index 5fb6114..143f89d 100644 --- a/server/host-ipc-definitions.hpp +++ b/server/host-ipc-definitions.hpp @@ -60,6 +60,7 @@ const ::ipc::MethodID METHOD_CREATE_FILE = 27; const ::ipc::MethodID METHOD_LOCK_QUEUE = 28; const ::ipc::MethodID METHOD_UNLOCK_QUEUE = 29; const ::ipc::MethodID METHOD_SWITCH_TO_DEFAULT = 30; +const ::ipc::MethodID METHOD_CLEAN_UP_ZONES_ROOT = 31; } // namespace ipc } // namespace api diff --git a/server/zones-manager-config.hpp b/server/zones-manager-config.hpp index 6e4625f..e300e75 100644 --- a/server/zones-manager-config.hpp +++ b/server/zones-manager-config.hpp @@ -49,6 +49,11 @@ struct ZonesManagerConfig { std::string zonesPath; /** + * If set then all files not related with existing containers will be removed + */ + bool cleanUpZonesPath; + + /** * A path where the zones image reside. Empty path means that zones image won't be * copied to zonesPath when creating new zone. */ @@ -83,6 +88,7 @@ struct ZonesManagerConfig { ( dbPath, zonesPath, + cleanUpZonesPath, zoneImagePath, zoneTemplateDir, availableVTs, diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 0787be0..484b3e9 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -45,6 +45,8 @@ #include #include #include +#include +#include namespace vasum { @@ -61,6 +63,11 @@ const boost::regex ZONE_IP_THIRD_OCTET_REGEX("~IP~"); const unsigned int ZONE_IP_BASE_THIRD_OCTET = 100; +const std::vector prohibitedZonesNames{ + ENABLED_FILE_NAME, + "lxc-monitord.log" +}; + template void remove(std::vector& v, const T& item) { @@ -97,6 +104,55 @@ bool zoneIsRunning(const std::unique_ptr& zone) { return zone->isRunning(); } +bool isalnum(const std::string& str) +{ + for (const auto& c : str) { + if (!std::isalnum(c)) { + return false; + } + } + return true; +} + +void cleanUpUnknownsFromRoot(const boost::filesystem::path& zonesPath, + const std::vector& zoneIds, + bool dryRun) +{ + namespace fs = boost::filesystem; + const auto end = fs::directory_iterator(); + + std::set knowns(zoneIds.begin(), zoneIds.end()); + knowns.insert(prohibitedZonesNames.begin(), prohibitedZonesNames.end()); + + // Remove all directories that start with '.' + for (auto zoneDir = fs::directory_iterator(zonesPath); zoneDir != end; ++zoneDir) { + if (zoneDir->path().filename().string()[0] == '.') { + if (!dryRun) { + fs::remove_all(zoneDir->path()); + LOGI("Remove directory entry: " << *zoneDir); + } else { + LOGI("Remove directory entry (dry run): " << *zoneDir); + } + } + } + + for (auto zoneDir = fs::directory_iterator(zonesPath); zoneDir != end; ++zoneDir) { + const auto zoneIt = knowns.find(zoneDir->path().filename().string()); + if (zoneIt == knowns.end()) { + if (!dryRun) { + const std::string filename = '.' + zoneDir->path().filename().string(); + fs::path newName = zoneDir->path().parent_path() / filename; + + fs::rename(zoneDir->path(), newName); + fs::remove_all(newName); + LOGI("Remove directory entry: " << *zoneDir); + } else { + LOGI("Remove directory entry (dry run): " << *zoneDir); + } + } + } +} + } // namespace @@ -133,6 +189,8 @@ void ZonesManager::start() mIsRunning = true; + cleanUpUnknownsFromRoot(mConfig.zonesPath, mDynamicConfig.zoneIds, !mConfig.cleanUpZonesPath); + #ifdef DBUS_CONNECTION using namespace std::placeholders; mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules)); @@ -1132,11 +1190,16 @@ int ZonesManager::getVTForNewZone() void ZonesManager::createZone(const std::string& id, const std::string& templateName) { - if (id.empty()) { // TODO validate id (no spaces, slashes etc) + if (id.empty() || !isalnum(id)) { LOGE("Failed to add zone - invalid name."); throw InvalidZoneIdException("Invalid name"); } + if (find(prohibitedZonesNames.begin(), prohibitedZonesNames.end(), id) != prohibitedZonesNames.end()) { + LOGE("Cannot create " << id << " zone - name is not allowed!"); + throw InvalidZoneIdException("Zone name is not allowed"); + } + LOGI("Creating zone " << id); Lock lock(mMutex); @@ -1151,6 +1214,12 @@ void ZonesManager::createZone(const std::string& id, throw InvalidZoneIdException("Already exists"); } + if (fs::exists(fs::path(mConfig.zonesPath) / id)) { + LOGE("Cannot create " << id << " zone - file system already exists!"); + throw InvalidZoneIdException("Zone file system already exists but there is no configuration for it. " + "Check cleanUpZonesPath in daemon.conf"); + } + const std::string zonePathStr = utils::createFilePath(mConfig.zonesPath, id, "/"); // copy zone image if config contains path to image @@ -1210,9 +1279,9 @@ void ZonesManager::handleCreateZoneCall(const api::CreateZoneIn& data, createZone(data.first, data.second); result->setVoid(); } catch (const InvalidZoneIdException& e) { - result->setError(api::ERROR_INVALID_ID, "Existing or invalid zone id"); - } catch (const std::runtime_error& e) { - result->setError(api::ERROR_INTERNAL, "Failed to create zone"); + result->setError(api::ERROR_INVALID_ID, e.what()); + } catch (const std::exception& e) { + result->setError(api::ERROR_INTERNAL, e.what()); } }; @@ -1456,4 +1525,24 @@ void ZonesManager::handleRevokeDeviceCall(const api::RevokeDeviceIn& data, tryAddTask(handler, result, true); } +void ZonesManager::handleCleanUpZonesRootCall(api::MethodResultBuilder::Pointer result) +{ + auto handler = [&, this] { + LOGI("CleanUpZonesRoot call"); + try { + std::vector zonesIds; + Lock lock(mMutex); + for (const auto& zone : mZones) { + zonesIds.push_back(zone->getId()); + } + cleanUpUnknownsFromRoot(mConfig.zonesPath, zonesIds, false); + } catch (const std::exception& e) { + result->setError(api::ERROR_INTERNAL, e.what()); + } + result->setVoid(); + }; + + tryAddTask(handler, result, true); +} + } // namespace vasum diff --git a/server/zones-manager.hpp b/server/zones-manager.hpp index 6a7a2c4..de6663d 100644 --- a/server/zones-manager.hpp +++ b/server/zones-manager.hpp @@ -196,6 +196,7 @@ public: api::MethodResultBuilder::Pointer result); void handleSwitchToDefaultCall(const std::string& caller, api::MethodResultBuilder::Pointer result); + void handleCleanUpZonesRootCall(api::MethodResultBuilder::Pointer result); private: typedef std::recursive_mutex Mutex; diff --git a/tests/unit_tests/configs/test-daemon.conf.in b/tests/unit_tests/configs/test-daemon.conf.in index 5151fbe..66ca69f 100644 --- a/tests/unit_tests/configs/test-daemon.conf.in +++ b/tests/unit_tests/configs/test-daemon.conf.in @@ -2,6 +2,7 @@ "dbPath" : "/tmp/ut-zones/vasum.db", "zoneIds" : [], "zonesPath" : "/tmp/ut-zones", + "cleanUpZonesPath" : false, "zoneImagePath" : "", "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/templates/", "runMountPointPrefix" : "",