c->setInit(args);
c->setLogger(logger::LogType::LOG_FILE, logger::LogLevel::TRACE, "/tmp/lxcpp-shell.txt");
c->setTerminalCount(4);
+ // make my own user root in a new namespace
+ c->addUIDMap(0, 1000, 1);
+ c->addGIDMap(0, 1000, 1);
+ // make root and system users non privileged ones
+ c->addUIDMap(1000, 0, 999);
+ c->addGIDMap(1000, 0, 999);
c->start();
c->console();
// You could run the console for the second time to see if it can be reattached
//c->console();
- initPid = c->getInitPid();
-
delete c;
}
catch (const std::exception &e)
setenv(config.envToSet);
// Set uid/gids
- lxcpp::setgid(config.gid);
+ lxcpp::setregid(config.gid, config.gid);
setgroups(config.supplementaryGids);
- lxcpp::setuid(config.uid);
+ lxcpp::setreuid(config.uid, config.uid);
// Set control TTY
if(!setupControlTTY(config.ttyFD)) {
namespace lxcpp {
-Attach::Attach(const lxcpp::ContainerImpl& container,
+Attach::Attach(const ContainerConfig& config,
const std::vector<std::string>& argv,
const uid_t uid,
const gid_t gid,
const std::vector<std::pair<std::string, std::string>>& envToSet)
: mIntermChannel(false),
mConfig(argv,
- container.getInitPid(),
- container.getNamespaces(),
+ config.mInitPid,
+ config.mNamespaces,
uid,
gid,
supplementaryGids,
* Object attach should be used immediately after creation.
* It will not be stored for future use like most other commands.
*
- * @param container container to which it attaches
+ * @param config config of a container to which it attaches
* @param argv path and arguments for the user's executable
* @param uid uid in the container
* @param gid gid in the container
* @param envToKeep environment variables that will be kept
* @param envToSet new environment variables that will be set
*/
- Attach(const lxcpp::ContainerImpl& container,
+ Attach(const ContainerConfig& config,
const std::vector<std::string>& argv,
const uid_t uid,
const gid_t gid,
} // namespace lxcpp
-#endif // LXCPP_COMMANDS_ATTACH_HPP
\ No newline at end of file
+#endif // LXCPP_COMMANDS_ATTACH_HPP
--- /dev/null
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Implementation of user namespace setup
+ */
+
+#include "lxcpp/commands/setup-userns.hpp"
+
+#include "logger/logger.hpp"
+#include "utils/fs.hpp"
+
+#include <vector>
+#include <iostream>
+
+
+namespace lxcpp {
+
+
+SetupUserNS::SetupUserNS(UserNSConfig &userNSConfig, pid_t initPid)
+ : mUserNSConfig(userNSConfig),
+ mInitPid(initPid)
+{
+}
+
+SetupUserNS::~SetupUserNS()
+{
+}
+
+void SetupUserNS::execute()
+{
+ const std::string proc = "/proc/" + std::to_string(mInitPid);
+ const std::string uid_map_path = proc + "/uid_map";
+ const std::string gid_map_path = proc + "/gid_map";
+
+ std::string uid_map;
+ for (const auto map : mUserNSConfig.mUIDMaps) {
+ uid_map.append(std::to_string(map.min));
+ uid_map.append(" ");
+ uid_map.append(std::to_string(map.max));
+ uid_map.append(" ");
+ uid_map.append(std::to_string(map.num));
+ uid_map.append("\n");
+ }
+ if (uid_map.size() && !utils::saveFileContent(uid_map_path, uid_map)) {
+ const std::string msg = "Failed to write the uid_map";
+ LOGE(msg);
+ throw UserNSException(msg);
+ }
+
+ std::string gid_map;
+ for (const auto map : mUserNSConfig.mGIDMaps) {
+ gid_map.append(std::to_string(map.min));
+ gid_map.append(" ");
+ gid_map.append(std::to_string(map.max));
+ gid_map.append(" ");
+ gid_map.append(std::to_string(map.num));
+ gid_map.append("\n");
+ }
+ if (gid_map.size() && !utils::saveFileContent(gid_map_path, gid_map)) {
+ const std::string msg = "Failed to write the gid_map";
+ LOGE(msg);
+ throw UserNSException(msg);
+ }
+}
+
+
+} // namespace lxcpp
--- /dev/null
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Headers of user namespace setup
+ */
+
+#ifndef LXCPP_COMMANDS_SETUP_USERNS_HPP
+#define LXCPP_COMMANDS_SETUP_USERNS_HPP
+
+#include "lxcpp/commands/command.hpp"
+#include "lxcpp/container-config.hpp"
+
+
+namespace lxcpp {
+
+
+class SetupUserNS final: Command {
+public:
+ /**
+ * Setups the user namespace by filling UID/GID mappings
+ *
+ * @param userNSConfig A config containing UID and GID mappings
+ */
+ SetupUserNS(UserNSConfig &userNSConfig, pid_t initPid);
+ ~SetupUserNS();
+
+ void execute();
+
+private:
+ UserNSConfig &mUserNSConfig;
+ pid_t mInitPid;
+};
+
+
+} // namespace lxcpp
+
+
+#endif // LXCPP_COMMANDS_SETUP_USERNS_HPP
#include "lxcpp/network-config.hpp"
#include "lxcpp/terminal-config.hpp"
#include "lxcpp/provision-config.hpp"
+#include "lxcpp/userns-config.hpp"
#include <config/config.hpp>
#include <config/fields.hpp>
*/
ProvisionConfig mProvisions;
+ /**
+ * User namespace config (uid and gid mappings)
+ *
+ * Set: addUIDMap(), addGIDMap()
+ * Get: none
+ */
+ UserNSConfig mUserNSConfig;
+
ContainerConfig() : mGuardPid(-1), mInitPid(-1), mNamespaces(0) {}
CONFIG_REGISTER
mLogger,
mTerminals,
mNamespaces,
- mProvisions
+ mProvisions,
+ mUserNSConfig
)
};
mConfig.mName = name;
mConfig.mRootPath = path;
+ mConfig.mNamespaces = CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS;
}
// TODO: the aim of this constructor is to create a new ContainerImpl based on an already
mConfig.mTerminals.count = count;
}
-void ContainerImpl::setNamespaces(const int namespaces)
+void ContainerImpl::addUIDMap(unsigned min, unsigned max, unsigned num)
{
- mConfig.mNamespaces = namespaces;
-}
+ mConfig.mNamespaces |= CLONE_NEWUSER;
+
+ if (mConfig.mUserNSConfig.mUIDMaps.size() >= 5) {
+ const std::string msg = "Max number of 5 UID mappings has been already reached";
+ LOGE(msg);
+ throw ConfigureException(msg);
+ }
+ mConfig.mUserNSConfig.mUIDMaps.emplace_back(min, max, num);
+}
-int ContainerImpl::getNamespaces() const
+void ContainerImpl::addGIDMap(unsigned min, unsigned max, unsigned num)
{
- return mConfig.mNamespaces;
+ mConfig.mNamespaces |= CLONE_NEWUSER;
+
+ if (mConfig.mUserNSConfig.mGIDMaps.size() >= 5) {
+ const std::string msg = "Max number of 5 GID mappings has been already reached";
+ LOGE(msg);
+ throw ConfigureException(msg);
+ }
+
+ mConfig.mUserNSConfig.mGIDMaps.emplace_back(min, max, num);
}
void ContainerImpl::start()
void ContainerImpl::attach(const std::vector<std::string>& argv,
const std::string& cwdInContainer)
{
- Attach attach(*this,
+ Attach attach(mConfig,
argv,
/*uid in container*/ 0,
/*gid in container*/ 0,
const std::vector<InetAddr>& addrs,
MacVLanMode mode)
{
+ mConfig.mNamespaces |= CLONE_NEWNET;
mConfig.mNetwork.addInterfaceConfig(hostif, zoneif, type, addrs, mode);
}
void setTerminalCount(const unsigned int count);
- void setNamespaces(const int namespaces);
- int getNamespaces() const;
+ void addUIDMap(unsigned min, unsigned max, unsigned num);
+ void addGIDMap(unsigned min, unsigned max, unsigned num);
// Execution actions
void start();
virtual void setTerminalCount(const unsigned int count) = 0;
- virtual void setNamespaces(const int namespaces) = 0;
- virtual int getNamespaces() const = 0;
+ virtual void addUIDMap(unsigned min, unsigned max, unsigned num) = 0;
+ virtual void addGIDMap(unsigned min, unsigned max, unsigned num) = 0;
// Execution actions
virtual void start() = 0;
}
}
-void setgid(const gid_t gid)
+void setregid(const gid_t rgid, const gid_t egid)
{
- if(-1 == ::setgid(gid)) {
- const std::string msg = "setgid() failed: " +
+ if(-1 == ::setregid(rgid, egid)) {
+ const std::string msg = "setregid() failed: " +
utils::getSystemErrorMessage();
LOGE(msg);
throw CredentialSetupException(msg);
}
}
-void setuid(const uid_t uid)
+void setreuid(const uid_t ruid, const uid_t euid)
{
- if(-1 == ::setuid(uid)) {
- const std::string msg = "setuid() failed: " +
+ if(-1 == ::setreuid(ruid, euid)) {
+ const std::string msg = "setreuid() failed: " +
utils::getSystemErrorMessage();
LOGE(msg);
throw CredentialSetupException(msg);
void setgroups(const std::vector<gid_t>& groups);
-void setgid(const gid_t gid);
+void setregid(const gid_t rgid, const gid_t egid);
-void setuid(const uid_t uid);
+void setreuid(const uid_t ruid, const uid_t euid);
pid_t setsid();
: Exception(message) {}
};
+struct UserNSException: public Exception {
+ explicit UserNSException(const std::string& message = "User namespace error")
+ : Exception(message) {}
+};
+
} // namespace lxcpp
#endif // LXCPP_EXCEPTION_HPP
#include "lxcpp/utils.hpp"
#include "lxcpp/guard/guard.hpp"
#include "lxcpp/process.hpp"
+#include "lxcpp/credentials.hpp"
#include "lxcpp/commands/prep-guest-terminal.hpp"
#include "lxcpp/commands/provision.hpp"
+#include "lxcpp/commands/setup-userns.hpp"
#include "config/manager.hpp"
#include "logger/logger.hpp"
namespace lxcpp {
-namespace {
-
-int startContainer(void* data)
+int Guard::startContainer(void* data)
{
- ContainerConfig& config = *static_cast<ContainerConfig*>(data);
+ ContainerConfig& config = static_cast<ContainerData*>(data)->mConfig;
+ utils::Channel& channel = static_cast<ContainerData*>(data)->mChannel;
+
+ // wait for continue sync from guard
+ channel.setRight();
+ channel.read<bool>();
+ channel.shutdown();
- // TODO: container preparation part 2
+ // TODO: container preparation part 3: things to do in the container process
Provisions provisions(config);
provisions.execute();
PrepGuestTerminal terminals(config.mTerminals);
terminals.execute();
+ if (config.mUserNSConfig.mUIDMaps.size()) {
+ lxcpp::setreuid(0, 0);
+ }
+ if (config.mUserNSConfig.mGIDMaps.size()) {
+ lxcpp::setregid(0, 0);
+ }
+
lxcpp::execve(config.mInit);
return EXIT_FAILURE;
}
-} // namespace
-
-
Guard::Guard(const int channelFD)
: mChannel(channelFD)
{
int Guard::execute()
{
- // TODO: container preparation part 1
+ // TODO: container preparation part 1: things to do before clone
+
+ utils::Channel channel;
+ ContainerData data(mConfig, channel);
- const pid_t initPid = lxcpp::clone(startContainer,
- &mConfig,
+ const pid_t initPid = lxcpp::clone(Guard::startContainer,
+ &data,
mConfig.mNamespaces);
mConfig.mGuardPid = ::getpid();
mChannel.write(mConfig.mInitPid);
mChannel.shutdown();
+ // TODO: container preparation part 2: things to do immediately after clone
+
+ SetupUserNS userNS(mConfig.mUserNSConfig, mConfig.mInitPid);
+ userNS.execute();
+
+ // send continue sync to container once userns, netns, cgroups, etc, are configured
+ channel.setLeft();
+ channel.write(true);
+ channel.shutdown();
+
int status = lxcpp::waitpid(initPid);
LOGD("Init exited with status: " << status);
- // TODO: cleanup after child exits
+ // TODO: container (de)preparation part 4: cleanup after container quits
+
Provisions provisions(mConfig);
provisions.revert();
int execute();
private:
+ struct ContainerData {
+ ContainerConfig &mConfig;
+ utils::Channel &mChannel;
+
+ ContainerData(ContainerConfig &config, utils::Channel &channel)
+ : mConfig(config), mChannel(channel) {}
+ };
+
+ static int startContainer(void *data);
+
utils::Channel mChannel;
ContainerConfig mConfig;
};
--- /dev/null
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsumg.com)
+ * @brief User namespace configuration
+ */
+
+#ifndef LXCPP_USERNS_CONFIG_HPP
+#define LXCPP_USERNS_CONFIG_HPP
+
+#include "config/config.hpp"
+#include "config/fields.hpp"
+
+#include <vector>
+#include <string>
+
+
+namespace lxcpp {
+
+
+struct UserNSConfig {
+ // TODO: Replace UserNSMap with std::tuple
+ struct UserNSMap {
+ unsigned min;
+ unsigned max;
+ unsigned num;
+
+ UserNSMap() = default;
+ UserNSMap(unsigned min, unsigned max, unsigned num)
+ : min(min), max(max), num(num) {}
+
+ CONFIG_REGISTER
+ (
+ min,
+ max,
+ num
+ )
+ };
+
+ std::vector<UserNSMap> mUIDMaps;
+ std::vector<UserNSMap> mGIDMaps;
+
+ CONFIG_REGISTER
+ (
+ mUIDMaps,
+ mGIDMaps
+ )
+};
+
+
+} //namespace lxcpp
+
+
+#endif // LXCPP_USERNS_CONFIG_HPP
BOOST_CHECK_NO_THROW(c->setLogger(logger::LogType::LOG_PERSISTENT_FILE,
logger::LogLevel::DEBUG,
LOGGER_FILE));
- BOOST_CHECK_NO_THROW(c->setNamespaces(CLONE_NEWIPC | CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWUTS));
BOOST_CHECK_NO_THROW(c->start());
BOOST_CHECK_NO_THROW(c->stop());
}