Add launchAsRoot and use it when adding new container 22/29022/4
authorLukasz Kostyra <l.kostyra@samsung.com>
Thu, 16 Oct 2014 12:44:52 +0000 (14:44 +0200)
committerJan Olszak <j.olszak@samsung.com>
Mon, 27 Oct 2014 08:49:45 +0000 (01:49 -0700)
[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
common/utils/environment.hpp
common/utils/fs.cpp
server/containers-manager.cpp
server/server.cpp

index 70ef27c..eaaef12 100644 (file)
@@ -30,6 +30,8 @@
 #include <cap-ng.h>
 #include <grp.h>
 #include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
 #include <cstring>
 
 
@@ -82,6 +84,43 @@ bool dropRoot(uid_t uid, gid_t gid, const std::vector<unsigned int>& caps)
     return true;
 }
 
+bool launchAsRoot(const std::function<void()>& 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
index b62189b..120b6ac 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <string>
 #include <vector>
+#include <functional>
 #include <sys/types.h>
 
 
@@ -44,6 +45,13 @@ bool setSuppGroups(const std::vector<std::string>& groups);
  */
 bool dropRoot(uid_t uid, gid_t gid, const std::vector<unsigned int>& caps);
 
+/**
+ * Launch func as root user.
+ *
+ * This function forks, sets UID 0 to child process and calls func.
+ */
+bool launchAsRoot(const std::function<void()>& func);
+
 
 } // namespace utils
 } // namespace security_containers
index 8a6441c..660db9f 100644 (file)
@@ -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();
index c9c7ff8..82be28d 100644 (file)
@@ -37,6 +37,7 @@
 #include "dbus/exception.hpp"
 #include "utils/fs.hpp"
 #include "utils/img.hpp"
+#include "utils/environment.hpp"
 
 #include <boost/filesystem.hpp>
 #include <boost/regex.hpp>
@@ -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.");
         }
index 7b03f4c..f477f0a 100644 (file)
@@ -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}));
 }