From 9b73e1465d6d5c6acc3c06f551569348d3dd9388 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 16 Aug 2017 17:26:06 +0200 Subject: [PATCH] InternalEncryption: make umount logic more error proof Don't umount if the device is not already mounted. Try to umount if the device is mounted more then once (bind). Change-Id: I0656146225fb0df429a4da1af743bc1d1cbdb9f9 --- server/internal-encryption.cpp | 126 +++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 39 deletions(-) diff --git a/server/internal-encryption.cpp b/server/internal-encryption.cpp index 7704078..11a6c1a 100644 --- a/server/internal-encryption.cpp +++ b/server/internal-encryption.cpp @@ -21,6 +21,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -61,6 +65,56 @@ namespace ode { namespace { +std::string findDevPath() +{ + std::string source = INTERNAL_DEV_PATH "/" INTERNAL_DEV_NAME; + try { + runtime::DirectoryIterator iter(INTERNAL_DEV_PATH), end; + + while (iter != end) { + const std::string& path = (*iter).getPath(); + std::string name = path.substr(path.rfind('/') + 1); + std::string upper; + upper.reserve(name.size()); + for (char c : name) { + upper += std::toupper(c); + } + if (upper == INTERNAL_DEV_NAME) { + source = path; + break; + } + ++iter; + } + } catch (runtime::Exception &e) {} + + char *dev = ::realpath(source.c_str(), NULL); + if (dev == NULL) { + throw runtime::Exception("Failed to find device path."); + } + + std::string devPath(dev); + free(dev); + + return devPath; +} + +std::string findMntPath(const std::string &devPath) +{ + std::string ret; + + FILE* mtab = ::setmntent("/etc/mtab", "r"); + struct mntent* entry = NULL; + while ((entry = ::getmntent(mtab)) != NULL) { + if (devPath == entry->mnt_fsname) { + ret = entry->mnt_dir; + break; + } + } + ::endmntent(mtab); + + return ret; +} + std::unique_ptr engine; KeyManager::data mountKey; @@ -215,25 +269,7 @@ InternalEncryption::InternalEncryption(ODEControlContext& ctx) : context.createNotification("InternalEncryption::mount"); - std::string source = INTERNAL_DEV_PATH "/" INTERNAL_DEV_NAME; - try { - runtime::DirectoryIterator iter(INTERNAL_DEV_PATH), end; - - while (iter != end) { - const std::string& path = (*iter).getPath(); - std::string name = path.substr(path.rfind('/') + 1); - std::string upper; - upper.reserve(name.size()); - for (char c : name) { - upper += std::toupper(c); - } - if (upper == INTERNAL_DEV_NAME) { - source = path; - break; - } - ++iter; - } - } catch (runtime::Exception &e) {} + std::string source = findDevPath(); engine.reset(new INTERNAL_ENGINE( source, INTERNAL_PATH, @@ -329,18 +365,27 @@ int InternalEncryption::encrypt(const std::string& password, unsigned int option KeyManager::data MasterKey = keyManager.getMasterKey(pwData); auto encryptWorker = [MasterKey, options, this]() { try { - INFO(SINK, "Close all known systemd services that might be using internal storage..."); - stopKnownSystemdServices(); - INFO(SINK, "Close all processes using internal storage..."); - stopDependedSystemdServices(); - INFO(SINK, "Umount internal storage..."); - while (::umount(INTERNAL_PATH) == -1) { - if (errno != EBUSY) { - throw runtime::Exception("Umount error - " + std::to_string(errno)); - } + std::string source = engine->getSource(); + std::string mntPath = findMntPath(source); + + if (!mntPath.empty()) { + INFO(SINK, "Close all known systemd services that might be using internal storage..."); + stopKnownSystemdServices(); + INFO(SINK, "Close all processes using internal storage..."); stopDependedSystemdServices(); } + while (!mntPath.empty()) { + INFO(SINK, "Umount internal storage..."); + while (::umount(mntPath.c_str()) == -1) { + if (errno != EBUSY) { + throw runtime::Exception("Umount error - " + std::to_string(errno)); + } + stopDependedSystemdServices(); + } + mntPath = findMntPath(source); + } + showProgressUI("Encrypting"); INFO(SINK, "Encryption started..."); @@ -382,17 +427,20 @@ int InternalEncryption::decrypt(const std::string& password) KeyManager::data MasterKey = keyManager.getMasterKey(pwData); auto decryptWorker = [MasterKey, this]() { try { - INFO(SINK, "Close all known systemd services that might be using internal storage..."); - stopKnownSystemdServices(); - INFO(SINK, "Close all processes using internal storage..."); - stopDependedSystemdServices(); - INFO(SINK, "Umount internal storage..."); - while (1) { - try { - engine->umount(); - break; - } catch (runtime::Exception& e) { - stopDependedSystemdServices(); + if (engine->isMounted()) { + INFO(SINK, "Close all known systemd services that might be using internal storage..."); + stopKnownSystemdServices(); + INFO(SINK, "Close all processes using internal storage..."); + stopDependedSystemdServices(); + + INFO(SINK, "Umount internal storage..."); + while (1) { + try { + engine->umount(); + break; + } catch (runtime::Exception& e) { + stopDependedSystemdServices(); + } } } -- 2.34.1