#include <cap-ng.h>
#include <grp.h>
#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
#include <cstring>
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
#include <string>
#include <vector>
+#include <functional>
#include <sys/types.h>
*/
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
{
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();
#include "dbus/exception.hpp"
#include "utils/fs.hpp"
#include "utils/img.hpp"
+#include "utils/environment.hpp"
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
// 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.");
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;
}
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;
}
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.");
}
// 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}));
}