lxcpp: Attach process helper 69/48369/10
authorJan Olszak <j.olszak@samsung.com>
Thu, 17 Sep 2015 12:55:25 +0000 (14:55 +0200)
committerJan Olszak <j.olszak@samsung.com>
Tue, 22 Sep 2015 15:24:28 +0000 (17:24 +0200)
[Feature]       N/A
[Cause]         Attach should work in multi-threaded programs
[Solution]      Moved part of Attach implementation to a helper binary
[Verification]  Build, install, run test

Change-Id: Ibdf5e0049ed41fdbbdb67a5f11de8aa415bdb1a5

15 files changed:
libs/lxcpp/CMakeLists.txt
libs/lxcpp/attach/CMakeLists.txt [new file with mode: 0644]
libs/lxcpp/attach/attach-config.hpp [new file with mode: 0644]
libs/lxcpp/attach/attach-helper.cpp [new file with mode: 0644]
libs/lxcpp/attach/attach-helper.hpp [new file with mode: 0644]
libs/lxcpp/attach/main.cpp [new file with mode: 0644]
libs/lxcpp/commands/attach.cpp
libs/lxcpp/commands/attach.hpp
libs/lxcpp/config.hpp [new file with mode: 0644]
libs/lxcpp/container-impl.cpp
libs/lxcpp/container-impl.hpp
libs/lxcpp/container.hpp
libs/lxcpp/utils.cpp
libs/lxcpp/utils.hpp
packaging/vasum.spec

index d5e205b..9e49843 100644 (file)
@@ -22,6 +22,9 @@ PROJECT(lxcpp)
 SET(GUARD_CODENAME "${PROJECT_NAME}-guard")
 ADD_SUBDIRECTORY(guard)
 
+SET(ATTACH_CODENAME "${PROJECT_NAME}-attach")
+ADD_SUBDIRECTORY(attach)
+
 MESSAGE(STATUS "")
 MESSAGE(STATUS "Generating makefile for the liblxcpp...")
 FILE(GLOB HEADERS          *.hpp)
@@ -40,7 +43,11 @@ ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_COMMANDS})
 SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
     SOVERSION   ${_LIB_SOVERSION_}
     VERSION     ${_LIB_VERSION_}
-    COMPILE_DEFINITIONS GUARD_PATH="${LIBEXEC_DIR}/${GUARD_CODENAME}"
+)
+
+TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME}
+    PRIVATE GUARD_PATH="${LIBEXEC_DIR}/${GUARD_CODENAME}"
+    PRIVATE ATTACH_PATH="${LIBEXEC_DIR}/${ATTACH_CODENAME}"
 )
 
 ADD_DEPENDENCIES(${PROJECT_NAME} Common Logger)
diff --git a/libs/lxcpp/attach/CMakeLists.txt b/libs/lxcpp/attach/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cdd40ca
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+# @file   CMakeLists.txt
+# @author Jan Olszak (j.olszak@samsung.com)
+#
+
+MESSAGE(STATUS "")
+MESSAGE(STATUS "Generating makefile for the Attach...")
+FILE(GLOB      attach_SRCS *.cpp *.hpp)
+
+
+## Setup target ################################################################
+ADD_EXECUTABLE(${ATTACH_CODENAME} ${attach_SRCS})
+
+
+## Link libraries ##############################################################
+PKG_CHECK_MODULES(ATTACH_DEPS REQUIRED glib-2.0)
+INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER})
+INCLUDE_DIRECTORIES(SYSTEM ${ATTACH_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS})
+TARGET_LINK_LIBRARIES(${ATTACH_CODENAME} Common lxcpp Config)
+
+
+## Install #####################################################################
+INSTALL(TARGETS ${ATTACH_CODENAME} DESTINATION ${LIBEXEC_DIR})
diff --git a/libs/lxcpp/attach/attach-config.hpp b/libs/lxcpp/attach/attach-config.hpp
new file mode 100644 (file)
index 0000000..9788abe
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Internal structure sent between Attach command and AttachHelper
+ */
+
+#ifndef LXCPP_ATTACH_ATTACH_CONFIG_HPP
+#define LXCPP_ATTACH_ATTACH_CONFIG_HPP
+
+#include "lxcpp/namespace.hpp"
+
+#include <config/config.hpp>
+#include <config/fields.hpp>
+
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
+namespace lxcpp {
+
+struct AttachConfig {
+
+    /// Arguments passed by user, argv[0] is the binary's path in container
+    std::vector<const char*> argv;
+
+    /// PID of the container's init process
+    pid_t initPid;
+
+    /// Namespaces to which we'll attach
+    std::vector<Namespace> namespaces;
+
+    /// User ID to set
+    uid_t uid;
+
+    /// Group ID to set
+    gid_t gid;
+
+    /// PTS that will become the control terminal for the attached process
+    int ttyFD;
+
+    /// Supplementary groups to set
+    std::vector<gid_t> supplementaryGids;
+
+    /// Mask of capabilities that will be available
+    int capsToKeep;
+
+    /// Work directory for the attached process
+    std::string workDirInContainer;
+
+    /// Environment variables that will be kept
+    std::vector<std::string> envToKeep;
+
+    /// Environment variables that will be set/updated for the attached process
+    std::vector<std::pair<std::string, std::string>> envToSet;
+
+    AttachConfig() = default;
+
+    AttachConfig(const std::vector<const char*>& argv,
+                 const pid_t initPid,
+                 const std::vector<Namespace>& namespaces,
+                 const uid_t uid,
+                 const gid_t gid,
+                 const std::vector<gid_t>& supplementaryGids,
+                 const int capsToKeep,
+                 const std::string& workDirInContainer,
+                 const std::vector<std::string>& envToKeep,
+                 const std::vector<std::pair<std::string, std::string>>& envToSet)
+        : argv(argv),
+          initPid(initPid),
+          namespaces(namespaces),
+          uid(uid),
+          gid(gid),
+          ttyFD(-1),
+          supplementaryGids(supplementaryGids),
+          capsToKeep(capsToKeep),
+          workDirInContainer(workDirInContainer),
+          envToKeep(envToKeep),
+          envToSet(envToSet)
+    {}
+
+    CONFIG_REGISTER
+    (
+        //TODO: Uncomment and fix cstring serialization
+        // argv,
+        initPid,
+        //TODO: Uncomment and fix Namespace serialization (or remove Namespace)
+        // namespaces,
+        uid,
+        gid,
+        ttyFD,
+        supplementaryGids,
+        capsToKeep,
+        workDirInContainer,
+        envToKeep
+        //TODO: Uncomment and fix std::pair serialization
+        // envToSet
+    )
+};
+
+} // namespace lxcpp
+
+#endif // LXCPP_ATTACH_ATTACH_CONFIG_HPP
\ No newline at end of file
diff --git a/libs/lxcpp/attach/attach-helper.cpp b/libs/lxcpp/attach/attach-helper.cpp
new file mode 100644 (file)
index 0000000..321502f
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Implementation of attaching to a container
+ */
+
+#include "lxcpp/attach/attach-helper.hpp"
+#include "lxcpp/exception.hpp"
+#include "lxcpp/process.hpp"
+#include "lxcpp/filesystem.hpp"
+#include "lxcpp/namespace.hpp"
+#include "lxcpp/capability.hpp"
+#include "lxcpp/environment.hpp"
+#include "lxcpp/credentials.hpp"
+#include "lxcpp/utils.hpp"
+
+#include "utils/exception.hpp"
+#include "utils/fd-utils.hpp"
+#include "logger/logger.hpp"
+#include "config/manager.hpp"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <string>
+
+namespace lxcpp {
+
+namespace {
+
+int child(void* data)
+{
+    AttachConfig& config = *static_cast<AttachConfig*>(data);
+
+    // Setup /proc /sys mount
+    setupMountPoints();
+
+    // Setup capabilities
+    dropCapsFromBoundingExcept(config.capsToKeep);
+
+    // Setup environment variables
+    clearenvExcept(config.envToKeep);
+    setenv(config.envToSet);
+
+    // Set uid/gids
+    lxcpp::setgid(config.gid);
+    setgroups(config.supplementaryGids);
+    lxcpp::setuid(config.uid);
+
+    // Set control TTY
+    if(!setupControlTTY(config.ttyFD)) {
+        ::_exit(EXIT_FAILURE);
+    }
+
+    // Run user's binary
+    ::execve(config.argv[0], const_cast<char *const*>(config.argv.data()), nullptr);
+    return EXIT_FAILURE;
+}
+
+} // namespace
+
+AttachHelper::AttachHelper(const int channelFD)
+    : mChannel(channelFD)
+{
+    mChannel.setCloseOnExec(true);
+    config::loadFromFD(mChannel.getFD(), mConfig);
+}
+
+AttachHelper::~AttachHelper()
+{
+    utils::close(mConfig.ttyFD);
+}
+
+void AttachHelper::execute()
+{
+    // Move to the right namespaces
+    lxcpp::setns(mConfig.initPid, mConfig.namespaces);
+
+    // Change the current work directory
+    // workDirInContainer is a path relative to the container's root
+    lxcpp::chdir(mConfig.workDirInContainer);
+
+    // Unsharing PID namespace won't affect the returned childPid
+    // CLONE_PARENT: Child's PPID == Caller's PID
+    const pid_t childPid = lxcpp::clone(child,
+                                        &mConfig,
+                                        CLONE_PARENT);
+    mChannel.write(childPid);
+}
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/attach/attach-helper.hpp b/libs/lxcpp/attach/attach-helper.hpp
new file mode 100644 (file)
index 0000000..5362a0c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Implementation of attaching to a container
+ */
+
+#ifndef LXCPP_ATTACH_ATTACH_HELPER_HPP
+#define LXCPP_ATTACH_ATTACH_HELPER_HPP
+
+#include "lxcpp/attach/attach-config.hpp"
+
+#include "utils/channel.hpp"
+
+namespace lxcpp {
+
+/**
+ * Implementation of the Intermediate helper process.
+ * @see Attach
+ */
+class AttachHelper {
+public:
+    AttachHelper(const int channelFD);
+    ~AttachHelper();
+
+    void execute();
+
+private:
+    utils::Channel mChannel;
+    AttachConfig mConfig;
+};
+
+} // namespace lxcpp
+
+#endif // LXCPP_ATTACH_ATTACH_HELPER_HPP
\ No newline at end of file
diff --git a/libs/lxcpp/attach/main.cpp b/libs/lxcpp/attach/main.cpp
new file mode 100644 (file)
index 0000000..d5924ec
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License version 2.1 as published by the Free Software Foundation.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * @file
+ * @author  Jan Olszak (j.olszak@samsung.com)
+ * @brief   Main file for the Intermediate process (libexec)
+ */
+
+#include "lxcpp/attach/attach-helper.hpp"
+
+#include "utils/fd-utils.hpp"
+#include "utils/typeinfo.hpp"
+
+// TODO: Implement passing logger configuration and uncomment this.
+// #include "logger/logger.hpp"
+
+#include <iostream>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+    if (argc == 1) {
+        std::cout << "This file should not be executed by hand" << std::endl;
+        ::_exit(EXIT_FAILURE);
+    }
+
+    // NOTE: this might not be required now, but I leave it here not to forget.
+    // We need to investigate this with vasum and think about possibility of
+    // poorly written software that leaks file descriptors and might use LXCPP.
+#if 0
+    for(int fd = 3; fd < ::sysconf(_SC_OPEN_MAX); ++fd) {
+        if(fd != std::stoi(argv[1])) {
+            utils::close(fd);
+        }
+    }
+#endif
+
+    try {
+        int fd = std::stoi(argv[1]);
+        lxcpp::AttachHelper attachHelper(fd);
+        attachHelper.execute();
+        return EXIT_SUCCESS;
+    } catch(std::exception& e) {
+        // TODO: Implement passing logger configuration and uncomment this.
+        // LOGE("Unexpected: " << utils::getTypeName(e) << ": " << e.what());
+        return EXIT_FAILURE;
+    }
+}
index e1bdfef..2bfa592 100644 (file)
 #include "lxcpp/commands/attach.hpp"
 #include "lxcpp/exception.hpp"
 #include "lxcpp/process.hpp"
-#include "lxcpp/filesystem.hpp"
-#include "lxcpp/namespace.hpp"
-#include "lxcpp/capability.hpp"
-#include "lxcpp/environment.hpp"
-#include "lxcpp/credentials.hpp"
 
 #include "utils/exception.hpp"
 #include "utils/fd-utils.hpp"
 #include "logger/logger.hpp"
 
 #include <unistd.h>
-#include <sys/mount.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-#include <functional>
 
 namespace lxcpp {
 
-namespace {
-
-void setupMountPoints()
-{
-    /* TODO: Uncomment when preparing the final attach() version
-
-    // TODO: This unshare should be optional only if we attach to PID/NET namespace, but not MNT.
-    // Otherwise container already has remounted /proc /sys
-    lxcpp::unshare(Namespace::MNT);
-
-    if (isMountPointShared("/")) {
-        // TODO: Handle case when the container rootfs or mount location is MS_SHARED, but not '/'
-        lxcpp::mount(nullptr, "/", nullptr, MS_SLAVE | MS_REC, nullptr);
-    }
-
-    if(isMountPoint("/proc")) {
-        lxcpp::umount("/proc", MNT_DETACH);
-        lxcpp::mount("none", "/proc", "proc", 0, nullptr);
-    }
-
-    if(isMountPoint("/sys")) {
-        lxcpp::umount("/sys", MNT_DETACH);
-        lxcpp::mount("none", "/sys", "sysfs", 0, nullptr);
-    }
-
-    */
-}
-
-bool setupControlTTY(const int ttyFD)
-{
-    if (!::isatty(ttyFD)) {
-        return false;
-    }
-
-    if (::setsid() < 0) {
-        return false;
-    }
-
-    if (::ioctl(ttyFD, TIOCSCTTY, NULL) < 0) {
-        return false;
-    }
-
-    if (::dup2(ttyFD, STDIN_FILENO) < 0) {
-        return false;
-    }
-
-    if (::dup2(ttyFD, STDOUT_FILENO) < 0) {
-        return false;
-    }
-
-    if (::dup2(ttyFD, STDERR_FILENO) < 0) {
-        return false;
-    }
-
-    return true;
-}
-
-int execFunction(void* call)
-{
-    try {
-        return (*static_cast<Attach::Call*>(call))();
-    } catch(...) {
-        return -1; // Non-zero on failure
-    }
-    return 0; // Success
-}
-
-} // namespace
-
-Attach::Attach(lxcpp::ContainerImpl& container,
-               Container::AttachCall& userCall,
+Attach::Attach(const lxcpp::ContainerImpl& container,
+               const std::vector<const char*>& argv,
                const uid_t uid,
                const gid_t gid,
                const std::string& ttyPath,
@@ -122,112 +43,62 @@ Attach::Attach(lxcpp::ContainerImpl& container,
                const std::string& workDirInContainer,
                const std::vector<std::string>& envToKeep,
                const std::vector<std::pair<std::string, std::string>>& envToSet)
-    : mContainer(container),
-      mUserCall(userCall),
-      mUid(uid),
-      mGid(gid),
-      mSupplementaryGids(supplementaryGids),
-      mCapsToKeep(capsToKeep),
-      mWorkDirInContainer(workDirInContainer),
-      mEnvToKeep(envToKeep),
-      mEnvToSet(envToSet)
+    : mIntermChannel(false),
+      mConfig(argv,
+              container.getInitPid(),
+              container.getNamespaces(),
+              uid,
+              gid,
+              supplementaryGids,
+              capsToKeep,
+              workDirInContainer,
+              envToKeep,
+              envToSet)
 {
-    mTTYFD = utils::open(ttyPath, O_RDWR | O_NOCTTY);
+    // Set TTY
+    if (ttyPath.empty()) {
+        mConfig.ttyFD = -1;
+    } else {
+        mConfig.ttyFD = utils::open(ttyPath, O_RDWR | O_NOCTTY);
+    }
 }
 
 Attach::~Attach()
 {
-    utils::close(mTTYFD);
+    utils::close(mConfig.ttyFD);
 }
 
 void Attach::execute()
 {
-    // Channels for setup synchronization
-    utils::Channel intermChannel;
-
-    Call call = std::bind(&Attach::child,
-                          mUserCall,
-                          mUid,
-                          mGid,
-                          mTTYFD,
-                          mSupplementaryGids,
-                          mCapsToKeep,
-                          mEnvToKeep,
-                          mEnvToSet);
+    // Channels for passing configuration and synchronization
+    const std::string mIntermChannelFDStr = std::to_string(mIntermChannel.getRightFD());
 
     const pid_t interPid = lxcpp::fork();
     if (interPid > 0) {
-        intermChannel.setLeft();
-        parent(intermChannel, interPid);
-        intermChannel.shutdown();
-    } else {
-        // TODO: only safe functions mentioned in signal(7) should be used below.
-        // This is not the case now, needs fixing.
-        intermChannel.setRight();
-        interm(intermChannel, call);
-        intermChannel.shutdown();
-        ::_exit(EXIT_SUCCESS);
-    }
-}
-
-int Attach::child(const Container::AttachCall& call,
-                  const uid_t uid,
-                  const gid_t gid,
-                  const int ttyFD,
-                  const std::vector<gid_t>& supplementaryGids,
-                  const int capsToKeep,
-                  const std::vector<std::string>& envToKeep,
-                  const std::vector<std::pair<std::string, std::string>>& envToSet)
-{
-    // Setup /proc /sys mount
-    setupMountPoints();
+        mIntermChannel.setLeft();
 
-    // Setup capabilities
-    dropCapsFromBoundingExcept(capsToKeep);
+        parent(interPid);
 
-    // Setup environment variables
-    clearenvExcept(envToKeep);
-    setenv(envToSet);
-
-    // Set uid/gids
-    lxcpp::setgid(gid);
-    setgroups(supplementaryGids);
-
-    lxcpp::setuid(uid);
+    } else {
+        mIntermChannel.setRight();
 
-    // Set control TTY
-    if(!setupControlTTY(ttyFD)) {
+        const char *argv[] = {ATTACH_PATH,
+                              mIntermChannelFDStr.c_str(),
+                              NULL
+                             };
+        ::execve(argv[0], const_cast<char *const*>(argv), nullptr);
         ::_exit(EXIT_FAILURE);
     }
-
-    // Run user's code
-    return call();
 }
 
-void Attach::parent(utils::Channel& intermChannel, const pid_t interPid)
+void Attach::parent(const pid_t interPid)
 {
     // TODO: Setup cgroups etc
-    const pid_t childPid = intermChannel.read<pid_t>();
+    const pid_t childPid = mIntermChannel.read<pid_t>();
 
     // Wait for all processes
     lxcpp::waitpid(interPid);
     lxcpp::waitpid(childPid);
 }
 
-void Attach::interm(utils::Channel& intermChannel, Call& call)
-{
-    lxcpp::setns(mContainer.getInitPid(), mContainer.getNamespaces());
-
-    // Change the current work directory
-    // workDirInContainer is a path relative to the container's root
-    lxcpp::chdir(mWorkDirInContainer);
-
-    // PID namespace won't affect the returned pid
-    // CLONE_PARENT: Child's PPID == Caller's PID
-    const pid_t childPid = lxcpp::clone(execFunction,
-                                        &call,
-                                        CLONE_PARENT);
-    intermChannel.write(childPid);
-}
-
 } // namespace lxcpp
index 2c1f365..ce39b83 100644 (file)
@@ -25,6 +25,7 @@
 #define LXCPP_COMMANDS_ATTACH_HPP
 
 #include "lxcpp/commands/command.hpp"
+#include "lxcpp/attach/attach-config.hpp"
 #include "lxcpp/container-impl.hpp"
 #include "utils/channel.hpp"
 
@@ -36,7 +37,6 @@ namespace lxcpp {
 
 class Attach final: Command {
 public:
-    typedef std::function<int(void)> Call;
 
     /**
      * Runs call in the container's context
@@ -45,17 +45,18 @@ public:
      * It will not be stored for future use like most other commands.
      *
      * @param container container to which it attaches
-     * @param userCall user's function to run
+     * @param argv path and arguments for the user's executable
      * @param uid uid in the container
      * @param gid gid in the container
+     * @param ttyPath path of the TTY in the host
      * @param supplementaryGids supplementary groups in container
      * @param capsToKeep capabilities that will be kept
      * @param workDirInContainer work directory set for the new process
      * @param envToKeep environment variables that will be kept
      * @param envToSet new environment variables that will be set
      */
-    Attach(lxcpp::ContainerImpl& container,
-           Container::AttachCall& userCall,
+    Attach(const lxcpp::ContainerImpl& container,
+           const std::vector<const char*>& argv,
            const uid_t uid,
            const gid_t gid,
            const std::string& ttyPath,
@@ -69,32 +70,11 @@ public:
     void execute();
 
 private:
-    const lxcpp::ContainerImpl& mContainer;
-    const Container::AttachCall& mUserCall;
-    const uid_t mUid;
-    const gid_t mGid;
-    int mTTYFD;
-    const std::vector<gid_t>& mSupplementaryGids;
-    const int mCapsToKeep;
-    const std::string& mWorkDirInContainer;
-    const std::vector<std::string>& mEnvToKeep;
-    const std::vector<std::pair<std::string, std::string>>& mEnvToSet;
+    utils::Channel mIntermChannel;
+    AttachConfig mConfig;
 
-    // Methods for different stages of setting up the attachment
-    static int child(const Container::AttachCall& call,
-                     const uid_t uid,
-                     const gid_t gid,
-                     const int ttyFD,
-                     const std::vector<gid_t>& supplementaryGids,
-                     const int capsToKeep,
-                     const std::vector<std::string>& envToKeep,
-                     const std::vector<std::pair<std::string, std::string>>& envToSet);
+    void parent(const pid_t pid);
 
-    void parent(utils::Channel& intermChannel,
-                const pid_t pid);
-
-    void interm(utils::Channel& intermChannel,
-                Call& call);
 };
 
 } // namespace lxcpp
diff --git a/libs/lxcpp/config.hpp b/libs/lxcpp/config.hpp
new file mode 100644 (file)
index 0000000..753430e
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
+ * @brief   Configuration file for the code
+ */
+
+
+#ifndef COMMON_CONFIG_HPP
+#define COMMON_CONFIG_HPP
+
+
+#ifdef __clang__
+#define CLANG_VERSION (__clang__major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
+#endif // __clang__
+
+#if defined __GNUC__ && !defined __clang__  // clang also defines GCC versions
+#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#endif // __GNUC__
+
+
+#ifdef GCC_VERSION
+
+#if GCC_VERSION < 40800
+// GCC 4.8 is the first where those defines are not required for
+// std::this_thread::sleep_for() and ::yield(). They might exist though
+// in previous versions depending on the build configuration of the GCC.
+#ifndef _GLIBCXX_USE_NANOSLEEP
+#define _GLIBCXX_USE_NANOSLEEP
+#endif // _GLIBCXX_USE_NANOSLEEP
+#ifndef _GLIBCXX_USE_SCHED_YIELD
+#define _GLIBCXX_USE_SCHED_YIELD
+#endif // _GLIBCXX_USE_SCHED_YIELD
+#endif // GCC_VERSION < 40800
+
+#if GCC_VERSION < 40700
+// Those appeared in 4.7 with full c++11 support
+#define final
+#define override
+#define thread_local __thread  // use GCC extension instead of C++11
+#define steady_clock monotonic_clock
+#endif // GCC_VERSION < 40700
+
+#endif // GCC_VERSION
+
+// Variadic macros support for boost preprocessor should be enabled
+// manually for clang since they are marked as untested feature
+// (boost trunk if fixed but the latest 1.55 version is not,
+// see boost/preprocessor/config/config.hpp)
+#ifdef __clang__
+#define BOOST_PP_VARIADICS 1
+#endif
+
+// This has to be defined always when the boost has not been compiled
+// using C++11. Headers detect that you are compiling using C++11 and
+// blindly and wrongly assume that boost has been as well.
+#ifndef BOOST_NO_CXX11_SCOPED_ENUMS
+#define BOOST_NO_CXX11_SCOPED_ENUMS 1
+#endif
+
+#endif // COMMON_CONFIG_HPP
index 7b715f3..5301cb5 100644 (file)
@@ -205,11 +205,11 @@ void ContainerImpl::reboot()
     throw NotImplementedException();
 }
 
-void ContainerImpl::attach(Container::AttachCall& call,
+void ContainerImpl::attach(const std::vector<const char*>& argv,
                            const std::string& cwdInContainer)
 {
     Attach attach(*this,
-                  call,
+                  argv,
                   /*uid in container*/ 0,
                   /*gid in container*/ 0,
                   "/dev/tty",
@@ -217,7 +217,7 @@ void ContainerImpl::attach(Container::AttachCall& call,
                   /*capsToKeep*/ 0,
                   cwdInContainer,
                   /*envToKeep*/ {},
-                  /*envInContainer*/ {{"container","lxcpp"}});
+    /*envInContainer*/ {{"container","lxcpp"}});
     // TODO: Env variables should agree with the ones already in the container
     attach.execute();
 }
index 97b9155..b0786a1 100644 (file)
@@ -66,7 +66,7 @@ public:
     void reboot();
 
     // Other
-    void attach(Container::AttachCall& attachCall,
+    void attach(const std::vector<const char*>& argv,
                 const std::string& cwdInContainer);
 
     // Network interfaces setup/config
index bf10a76..96af842 100644 (file)
@@ -45,8 +45,6 @@ struct NetworkInterfaceInfo {
 
 class Container {
 public:
-    typedef std::function<int(void)> AttachCall;
-
     virtual ~Container() {};
 
     // Configuration
@@ -73,7 +71,7 @@ public:
     virtual void reboot() = 0;
 
     // Other
-    virtual void attach(AttachCall& attachCall,
+    virtual void attach(const std::vector<const char*>& argv,
                         const std::string& cwdInContainer) = 0;
 
     // Network interfaces setup/config
index 685d915..0c731b5 100644 (file)
@@ -26,6 +26,9 @@
 #endif
 
 #include "lxcpp/exception.hpp"
+#include "lxcpp/namespace.hpp"
+#include "lxcpp/filesystem.hpp"
+#include "lxcpp/process.hpp"
 
 #include "logger/logger.hpp"
 #include "utils/fd-utils.hpp"
 #include <iterator>
 #include <unistd.h>
 #include <string.h>
+
 #include <sys/prctl.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
 
 
 namespace lxcpp {
@@ -82,5 +88,63 @@ void setProcTitle(const std::string &title)
     ::strcpy(mem, title.c_str());
 }
 
+void setupMountPoints()
+{
+#if 0
+    // TODO: This unshare should be optional only if we attach to PID/NET namespace, but not MNT.
+    // Otherwise container already has remounted /proc /sys
+    lxcpp::unshare(Namespace::MNT);
+
+    if (isMountPointShared("/")) {
+        // TODO: Handle case when the container rootfs or mount location is MS_SHARED, but not '/'
+        lxcpp::mount(nullptr, "/", nullptr, MS_SLAVE | MS_REC, nullptr);
+    }
+
+    if(isMountPoint("/proc")) {
+        lxcpp::umount("/proc", MNT_DETACH);
+        lxcpp::mount("none", "/proc", "proc", 0, nullptr);
+    }
+
+    if(isMountPoint("/sys")) {
+        lxcpp::umount("/sys", MNT_DETACH);
+        lxcpp::mount("none", "/sys", "sysfs", 0, nullptr);
+    }
+#endif
+}
+
+bool setupControlTTY(const int ttyFD)
+{
+    if (ttyFD != -1) {
+        return true;
+    }
+
+    if (!::isatty(ttyFD)) {
+        return false;
+    }
+
+    if (::setsid() < 0) {
+        return false;
+    }
+
+    if (::ioctl(ttyFD, TIOCSCTTY, NULL) < 0) {
+        return false;
+    }
+
+    if (::dup2(ttyFD, STDIN_FILENO) < 0) {
+        return false;
+    }
+
+    if (::dup2(ttyFD, STDOUT_FILENO) < 0) {
+        return false;
+    }
+
+    if (::dup2(ttyFD, STDERR_FILENO) < 0) {
+        return false;
+    }
+
+    return true;
+}
+
+
 
 } // namespace lxcpp
index e4c158b..c4d469b 100644 (file)
@@ -37,6 +37,10 @@ namespace lxcpp {
  */
 void setProcTitle(const std::string &title);
 
+void setupMountPoints();
+
+bool setupControlTTY(const int ttyFD);
+
 
 } // namespace lxcpp
 
index 7709ab4..546c782 100644 (file)
@@ -488,6 +488,7 @@ The package provides liblxcpp library.
 %defattr(644,root,root,755)
 %{_libdir}/liblxcpp.so.0
 %attr(755,root,root) %{_libexecdir}/lxcpp-guard
+%attr(755,root,root) %{_libexecdir}/lxcpp-attach
 %attr(755,root,root) %{_libdir}/liblxcpp.so.%{version}
 
 %package -n liblxcpp-devel