nspawn.c revision a41fe3a29372f8e6c4e7733bf85940a023811301
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering This file is part of systemd.
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering Copyright 2010 Lennart Poettering
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering under the terms of the GNU General Public License as published by
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering the Free Software Foundation; either version 2 of the License, or
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering (at your option) any later version.
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering systemd is distributed in the hope that it will be useful, but
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering General Public License for more details.
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering You should have received a copy of the GNU General Public License
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poetteringstatic bool arg_no_net = false;
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poetteringstatic int help(void) {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering "Spawn a minimal namespace container for debugging, testing and building.\n\n"
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering " -h --help Show this help\n"
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering " -D --directory=NAME Root directory for the container\n"
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering " -u --user=USER Run the command under specified user or uid\n"
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering " --no-net Disable network in container\n",
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poetteringstatic int parse_argv(int argc, char *argv[]) {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "directory", required_argument, NULL, 'D' },
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "user", required_argument, NULL, 'u' },
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "no-net", no_argument, NULL, ARG_NO_NET },
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering while ((c = getopt_long(argc, argv, "+hD:u:", options, NULL)) >= 0) {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering log_error("Failed to duplicate root directory.");
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering log_error("Failed to duplicate user name.");
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering typedef struct MountPoint {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering unsigned long flags;
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering static const MountPoint mount_table[] = {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "/proc/sys", "/proc/sys", "bind", NULL, MS_BIND, true }, /* Bind mount first */
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "/proc/sys", "/proc/sys", "bind", NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, true }, /* Then, make it r/o */
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "/sys", "/sys", "bind", NULL, MS_BIND, true }, /* Bind mount first */
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "/sys", "/sys", "bind", NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, true }, /* Then, make it r/o */
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID, true },
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "/dev/pts", "/dev/pts", "bind", NULL, MS_BIND, true },
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV, true },
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "/sys/fs/selinux", "/sys/fs/selinux", "bind", NULL, MS_BIND, false }, /* Bind mount first */
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering { "/sys/fs/selinux", "/sys/fs/selinux", "bind", NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, false }, /* Then, make it r/o */
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering for (k = 0; k < ELEMENTSOF(mount_table); k++) {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering if (asprintf(&where, "%s/%s", dest, mount_table[k].where) < 0) {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering if ((t = path_is_mount_point(where)) < 0) {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering log_error("Failed to detect whether %s is a mount point: %s", where, strerror(-t));
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering log_error("mount(%s) failed: %m", where);
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering /* Fix the timezone, if possible */
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering if (asprintf(&where, "%s/%s", dest, "/etc/localtime") >= 0) {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering mount("/etc/localtime", where, "bind", MS_BIND, NULL);
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering mount("/etc/localtime", where, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL);
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poetteringstatic int copy_devnodes(const char *dest, const char *console) {
1a2be33aa584df0d2fe8fa30d35b7c04eb092920Lennart Poettering static const char devnodes[] =
mode_t u;
u = umask(0000);
r = -ENOMEM;
r = -errno;
r = -EIO;
r = -errno;
r = -errno;
goto finish;
r = -EIO;
goto finish;
r = -ENOMEM;
goto finish;
r = -errno;
umask(u);
static int drop_capabilities(void) {
static const unsigned long retain[] = {
if (retain[i] == l)
return -errno;
return -ENOMEM;
free(p);
bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
r = -errno;
goto finish;
r = -errno;
goto finish;
r = -errno;
goto finish;
ssize_t k;
int i, nfds;
r = -errno;
goto finish;
for (i = 0; i < nfds; i++) {
stdin_readable = true;
stdout_writable = true;
master_readable = true;
master_writable = true;
ssize_t n;
r = -EIO;
goto finish;
r = -errno;
goto finish;
goto finish;
stdin_readable = false;
r = -errno;
goto finish;
master_writable = false;
r = -errno;
goto finish;
in_buffer_full -= k;
master_readable = false;
r = -errno;
goto finish;
stdout_writable = false;
r = -errno;
goto finish;
out_buffer_full -= k;
if (ep >= 0)
if (signal_fd >= 0)
int r = EXIT_FAILURE, k;
bool saved_attr_valid = false;
log_open();
goto finish;
if (arg_directory) {
arg_directory = p;
if (!arg_directory) {
goto finish;
if (geteuid() != 0) {
goto finish;
if (sd_booted() <= 0) {
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
saved_attr_valid = true;
goto finish;
if ((pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWIPC|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWUTS|(arg_no_net ? CLONE_NEWNET : 0), NULL)) < 0) {
goto finish;
if (pid == 0) {
const char *hn;
const char *envp[] = {
if (setsid() < 0)
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
if (drop_capabilities() < 0)
goto child_fail;
if (arg_user) {
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto child_fail;
goto finish;
if (saved_attr_valid) {
saved_attr_valid = false;
r = EXIT_FAILURE;
if (saved_attr_valid)
if (master >= 0)
if (oldcg)
if (newcg)