From 46bf0c683aad2818f119c275042d39e8d7dcb19b Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Thu, 16 Oct 2014 14:44:52 +0200 Subject: [PATCH] Add launchAsRoot and use it when adding new container [Feature] Function launchAsRoot. [Cause] Some functions need to be launched as root. [Solution] Add launchAsRoot which forks, sets UID to 0 and then calls a function. [Verification] Build, install, run tests. Add new container - no copying errors should occur. Change-Id: Iaf917108ea4c7c699d9f2d69c8100430daa4f9c4 --- common/utils/environment.cpp | 39 +++++++++++++++++++++++++++++++++++++++ common/utils/environment.hpp | 8 ++++++++ common/utils/fs.cpp | 6 ------ server/containers-manager.cpp | 13 +++++++++---- server/server.cpp | 4 +++- 5 files changed, 59 insertions(+), 11 deletions(-) diff --git a/common/utils/environment.cpp b/common/utils/environment.cpp index 70ef27c..eaaef12 100644 --- a/common/utils/environment.cpp +++ b/common/utils/environment.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include @@ -82,6 +84,43 @@ bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps) return true; } +bool launchAsRoot(const std::function& func) +{ + pid_t pid = fork(); + if (pid < 0) { + LOGE("Fork failed: " << strerror(errno)); + return false; + } + + if (pid == 0) { + if (::setuid(0) < 0) { + LOGW("Failed to become root: " << strerror(errno)); + ::exit(EXIT_FAILURE); + } + + try { + func(); + } catch (std::exception& e) { + LOGE("Failed to successfully execute func: " << e.what()); + ::exit(EXIT_FAILURE); + } + + ::exit(EXIT_SUCCESS); + } + + int result; + if (::waitpid(pid, &result, 0) < 0) { + LOGE("waitpid failed: " << strerror(errno)); + return false; + } + if (result != 0) { + LOGE("Function launched as root failed with result " << result); + return false; + } + + return true; +} + } // namespace utils } // namespace security_containers diff --git a/common/utils/environment.hpp b/common/utils/environment.hpp index b62189b..120b6ac 100644 --- a/common/utils/environment.hpp +++ b/common/utils/environment.hpp @@ -27,6 +27,7 @@ #include #include +#include #include @@ -44,6 +45,13 @@ bool setSuppGroups(const std::vector& groups); */ bool dropRoot(uid_t uid, gid_t gid, const std::vector& caps); +/** + * Launch func as root user. + * + * This function forks, sets UID 0 to child process and calls func. + */ +bool launchAsRoot(const std::function& func); + } // namespace utils } // namespace security_containers diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index 8a6441c..660db9f 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -207,12 +207,6 @@ bool copyDirContentsRec(const boost::filesystem::path& src, const boost::filesys { namespace fs = boost::filesystem; - // TODO: Right now this function skips files which produce error when copying. Errors show up - // when fs::directory_iterator file(src) is created - lack of permissions is the issue. - // - // To fix lack of permissions, copying must be done as root. The easiest way would be to launch - // copyDirContents after fork() and setuid(0). - try { for (fs::directory_iterator file(src); file != fs::directory_iterator(); diff --git a/server/containers-manager.cpp b/server/containers-manager.cpp index c9c7ff8..82be28d 100644 --- a/server/containers-manager.cpp +++ b/server/containers-manager.cpp @@ -37,6 +37,7 @@ #include "dbus/exception.hpp" #include "utils/fs.hpp" #include "utils/img.hpp" +#include "utils/environment.hpp" #include #include @@ -591,7 +592,11 @@ void ContainersManager::handleAddContainerCall(const std::string& id, // copy container image if config contains path to image LOGT("image path: " << mConfig.containerImagePath); if (!mConfig.containerImagePath.empty()) { - if (!utils::copyImageContents(mConfig.containerImagePath, containerPathStr)) { + auto copyImageContentsWrapper = std::bind(&utils::copyImageContents, + mConfig.containerImagePath, + containerPathStr); + + if (!utils::launchAsRoot(copyImageContentsWrapper)) { LOGE("Failed to copy container image."); result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, "Failed to copy container image."); @@ -636,7 +641,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id, generateNewConfig(id, libvirtNetworkFilterPath, newLibvirtNetworkFilterPath); } catch (SecurityContainersException& e) { LOGE(e.what()); - removeAllWrapper(containerPathStr); + utils::launchAsRoot(std::bind(removeAllWrapper, containerPathStr)); result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what()); return; } @@ -646,7 +651,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id, addContainer(newConfigPath); } catch (SecurityContainersException& e) { LOGE(e.what()); - removeAllWrapper(containerPathStr); + utils::launchAsRoot(std::bind(removeAllWrapper, containerPathStr)); result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, e.what()); return; } @@ -656,7 +661,7 @@ void ContainersManager::handleAddContainerCall(const std::string& id, result->setVoid(); } else { LOGE("Failed to start container."); - removeAllWrapper(containerPathStr); + utils::launchAsRoot(std::bind(removeAllWrapper, containerPathStr)); result->setError(api::host::ERROR_CONTAINER_CREATE_FAILED, "Failed to start container."); } diff --git a/server/server.cpp b/server/server.cpp index 7b03f4c..f477f0a 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -204,10 +204,12 @@ bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot) // CAP_SYS_TTY_CONFIG is needed to activate virtual terminals through ioctl calls // CAP_CHOWN is needed when creating new container from image to set owner/group for each file, // directory or symlink + // CAP_SETUID is needed to launch specific funtions as root (see environment.cpp) return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN, CAP_MAC_OVERRIDE, CAP_SYS_TTY_CONFIG, - CAP_CHOWN})); + CAP_CHOWN, + CAP_SETUID})); } -- 2.7.4