#include <lxc/lxccontainer.h>
#include <sys/stat.h>
+#include <utils/initctl.hpp>
+#include <sys/wait.h>
+
#include <map>
namespace security_containers {
bool LxcDomain::shutdown(int timeout)
{
+ State state = getState();
+ if (state == State::STOPPED) {
+ return true;
+ }
+ if (state != State::RUNNING) {
+ LOGE("Could not gracefully shutdown domain " << getName());
+ return false;
+ }
+
+ // try shutdown by sending poweroff to init
+ if (setRunLevel(utils::RUNLEVEL_POWEROFF)) {
+ if (!mContainer->wait(mContainer, "STOPPED", timeout)) {
+ LOGE("Could not gracefully shutdown domain " + getName() + " in " << timeout << "s");
+ return false;
+ }
+ return true;
+ }
+ LOGW("SetRunLevel failed for domain " + getName());
+
+ // fallback for other inits like bash: lxc sends 'lxc.haltsignal' signal to init
if (!mContainer->shutdown(mContainer, timeout)) {
LOGE("Could not gracefully shutdown domain " + getName() + " in " << timeout << "s");
return false;
return true;
}
+bool LxcDomain::setRunLevel(int runLevel)
+{
+ auto callback = [](void* param) {
+ utils::RunLevel runLevel = *reinterpret_cast<utils::RunLevel*>(param);
+ return utils::setRunLevel(runLevel) ? 0 : 1;
+ };
+
+ lxc_attach_options_t options = LXC_ATTACH_OPTIONS_DEFAULT;
+ pid_t pid;
+ int ret = mContainer->attach(mContainer, callback, &runLevel, &options, &pid);
+ if (ret != 0) {
+ return false;
+ }
+ int status;
+ if (waitpid(pid, &status, 0) < 0) {
+ return false;
+ }
+ return status == 0;
+}
+
} // namespace lxc
} // namespace security_containers
bool unfreeze();
private:
lxc_container* mContainer;
+
+ bool setRunLevel(int runLevel);
};
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz <p.bartosiewi@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 Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Api for talking to init via initctl
+ */
+
+#include "config.hpp"
+#include "utils/initctl.hpp"
+
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+namespace security_containers {
+namespace utils {
+
+namespace {
+ struct InitctlRequest {
+ int magic;
+ int cmd;
+ int runlevel;
+ int sleeptime;
+ char data[368];
+ };
+ const int INITCTL_MAGIC = 0x03091969;
+ const int INITCTL_CMD_RUNLVL = 1;
+
+ bool write(int fd, const void* data, size_t size)
+ {
+ while (size > 0) {
+ ssize_t r = ::write(fd, data, size);
+ if (r < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return false;
+ }
+ size -= r;
+ data = reinterpret_cast<const char*>(data) + r;
+ }
+ return true;
+ }
+
+ void close(int fd)
+ {
+ while (::close(fd) == -1 && errno == EINTR) {}
+ }
+}
+
+bool setRunLevel(RunLevel runLevel)
+{
+ int fd = ::open("/dev/initctl", O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0) {
+ return false;
+ }
+
+ InitctlRequest req;
+ memset(&req, 0, sizeof(req));
+ req.magic = INITCTL_MAGIC;
+ req.cmd = INITCTL_CMD_RUNLVL;
+ req.runlevel = '0' + runLevel;
+ req.sleeptime = 0;
+
+ bool ret = write(fd, &req, sizeof(req));
+ close(fd);
+ return ret;
+}
+
+
+} // namespace utils
+} // namespace security_containers
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Piotr Bartosiewicz <p.bartosiewi@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 Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ * @brief Api for talking to init via initctl
+ */
+
+#ifndef COMMON_UTILS_INITCTL_HPP
+#define COMMON_UTILS_INITCTL_HPP
+
+
+namespace security_containers {
+namespace utils {
+
+enum RunLevel : int {
+ RUNLEVEL_POWEROFF = 0,
+ RUNLEVEL_REBOOT = 6
+};
+
+bool setRunLevel(RunLevel runLevel);
+
+
+} // namespace utils
+} // namespace security_containers
+
+
+#endif // COMMON_UTILS_INITCTL_HPP
lxc.utsname = ${name}
lxc.rootfs = ${rootfs}
-lxc.haltsignal = SIGTERM
+# userns 1-to-1 mapping
+#lxc.id_map = u 0 0 65536
+#lxc.id_map = g 0 0 65536
lxc.pts = 256
lxc.tty = 0
lxc.utsname = ${name}
lxc.rootfs = ${rootfs}
-lxc.haltsignal = SIGTERM
+# userns 1-to-1 mapping
+#lxc.id_map = u 0 0 65536
+#lxc.id_map = g 0 0 65536
lxc.pts = 256
lxc.tty = 0
lxc.utsname = ${name}
lxc.rootfs = ${rootfs}
+# userns 1-to-1 mapping
+lxc.id_map = u 0 0 65536
+lxc.id_map = g 0 0 65536
+
lxc.haltsignal = SIGTERM
lxc.pts = 256
lxc.tty = 0
+lxc.cgroup.devices.deny = a
+
lxc.mount.auto = proc sys cgroup
lxc.mount.entry = /bin bin none ro,bind 0 0
lxc.mount.entry = /etc etc none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,rbind 0 0
-lxc.mount.entry = devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
lxc.mount.entry = /tmp/ut-run1 var/run none rw,bind 0 0
EOF
lxc.utsname = ${name}
lxc.rootfs = ${rootfs}
+# userns 1-to-1 mapping
+lxc.id_map = u 0 0 65536
+lxc.id_map = g 0 0 65536
+
lxc.haltsignal = SIGTERM
lxc.pts = 256
lxc.tty = 0
+lxc.cgroup.devices.deny = a
+
lxc.mount.auto = proc sys cgroup
lxc.mount.entry = /bin bin none ro,bind 0 0
lxc.mount.entry = /etc etc none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,rbind 0 0
-lxc.mount.entry = devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
lxc.mount.entry = /tmp/ut-run2 var/run none rw,bind 0 0
EOF
lxc.utsname = ${name}
lxc.rootfs = ${rootfs}
+# userns 1-to-1 mapping
+lxc.id_map = u 0 0 65536
+lxc.id_map = g 0 0 65536
+
lxc.haltsignal = SIGTERM
lxc.pts = 256
lxc.tty = 0
+lxc.cgroup.devices.deny = a
+
lxc.mount.auto = proc sys cgroup
lxc.mount.entry = /bin bin none ro,bind 0 0
lxc.mount.entry = /etc etc none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,rbind 0 0
-lxc.mount.entry = devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
lxc.mount.entry = /tmp/ut-run3 var/run none rw,bind 0 0
EOF
lxc.utsname = ${name}
lxc.rootfs = ${rootfs}
+# userns 1-to-1 mapping
+lxc.id_map = u 0 0 65536
+lxc.id_map = g 0 0 65536
+
lxc.haltsignal = SIGTERM
lxc.pts = 256
lxc.tty = 0
+lxc.cgroup.devices.deny = a
+
lxc.mount.auto = proc sys cgroup
lxc.mount.entry = /bin bin none ro,bind 0 0
lxc.mount.entry = /etc etc none ro,bind 0 0
lxc.mount.entry = /lib lib none ro,bind 0 0
lxc.mount.entry = /sbin sbin none ro,bind 0 0
lxc.mount.entry = /usr usr none ro,rbind 0 0
-lxc.mount.entry = devtmpfs dev devtmpfs rw,relatime,mode=755 0 0
EOF
if [ "$(uname -m)" = "x86_64" ]; then