conf: coding style changes

parent 12e6ab5d
...@@ -114,6 +114,15 @@ ...@@ -114,6 +114,15 @@
lxc_log_define(lxc_conf, lxc); lxc_log_define(lxc_conf, lxc);
/* The lxc_conf of the container currently being worked on in an API call.
* This is used in the error calls.
*/
#ifdef HAVE_TLS
__thread struct lxc_conf *current_config;
#else
struct lxc_conf *current_config;
#endif
/* Define pivot_root() if missing from the C library */ /* Define pivot_root() if missing from the C library */
#ifndef HAVE_PIVOT_ROOT #ifndef HAVE_PIVOT_ROOT
static int pivot_root(const char *new_root, const char *put_old) static int pivot_root(const char *new_root, const char *put_old)
...@@ -129,10 +138,18 @@ static int pivot_root(const char *new_root, const char *put_old) ...@@ -129,10 +138,18 @@ static int pivot_root(const char *new_root, const char *put_old)
extern int pivot_root(const char *new_root, const char *put_old); extern int pivot_root(const char *new_root, const char *put_old);
#endif #endif
char *lxchook_names[NUM_LXC_HOOKS] = {"pre-start", "pre-mount", "mount", char *lxchook_names[NUM_LXC_HOOKS] = {
"autodev", "start", "stop", "pre-start",
"post-stop", "clone", "destroy", "pre-mount",
"start-host"}; "mount",
"autodev",
"start",
"stop",
"post-stop",
"clone",
"destroy",
"start-host"
};
struct mount_opt { struct mount_opt {
char *name; char *name;
...@@ -150,17 +167,6 @@ struct limit_opt { ...@@ -150,17 +167,6 @@ struct limit_opt {
int value; int value;
}; };
/*
* The lxc_conf of the container currently being worked on in an
* API call
* This is used in the error calls
*/
#ifdef HAVE_TLS
__thread struct lxc_conf *current_config;
#else
struct lxc_conf *current_config;
#endif
static struct mount_opt mount_opt[] = { static struct mount_opt mount_opt[] = {
{ "async", 1, MS_SYNCHRONOUS }, { "async", 1, MS_SYNCHRONOUS },
{ "atime", 1, MS_NOATIME }, { "atime", 1, MS_NOATIME },
...@@ -311,9 +317,9 @@ static struct limit_opt limit_opt[] = { ...@@ -311,9 +317,9 @@ static struct limit_opt limit_opt[] = {
static int run_buffer(char *buffer) static int run_buffer(char *buffer)
{ {
struct lxc_popen_FILE *f;
char *output;
int ret; int ret;
char *output;
struct lxc_popen_FILE *f;
f = lxc_popen(buffer); f = lxc_popen(buffer);
if (!f) { if (!f) {
...@@ -493,10 +499,10 @@ int run_script(const char *name, const char *section, const char *script, ...) ...@@ -493,10 +499,10 @@ int run_script(const char *name, const char *section, const char *script, ...)
{ {
int ret; int ret;
char *buffer, *p; char *buffer, *p;
size_t size = 0;
va_list ap; va_list ap;
size_t size = 0;
INFO("Executing script \"%s\" for container \"%s\", config section \"%s\".", INFO("Executing script \"%s\" for container \"%s\", config section \"%s\"",
script, name, section); script, name, section);
va_start(ap, script); va_start(ap, script);
...@@ -514,26 +520,17 @@ int run_script(const char *name, const char *section, const char *script, ...) ...@@ -514,26 +520,17 @@ int run_script(const char *name, const char *section, const char *script, ...)
return -1; return -1;
buffer = alloca(size); buffer = alloca(size);
if (!buffer) {
ERROR("Failed to allocate memory.");
return -1;
}
ret = snprintf(buffer, size, "exec %s %s %s", script, name, section); ret = snprintf(buffer, size, "exec %s %s %s", script, name, section);
if (ret < 0 || ret >= size) { if (ret < 0 || ret >= size)
ERROR("Script name too long.");
return -1; return -1;
}
va_start(ap, script); va_start(ap, script);
while ((p = va_arg(ap, char *))) { while ((p = va_arg(ap, char *))) {
int len = size - ret; int len = size - ret;
int rc; int rc;
rc = snprintf(buffer + ret, len, " %s", p); rc = snprintf(buffer + ret, len, " %s", p);
if (rc < 0 || rc >= len) { if (rc < 0 || rc >= len)
ERROR("Script args too long.");
return -1; return -1;
}
ret += rc; ret += rc;
} }
va_end(ap); va_end(ap);
...@@ -541,8 +538,7 @@ int run_script(const char *name, const char *section, const char *script, ...) ...@@ -541,8 +538,7 @@ int run_script(const char *name, const char *section, const char *script, ...)
return run_buffer(buffer); return run_buffer(buffer);
} }
/* /* pin_rootfs
* pin_rootfs
* if rootfs is a directory, then open ${rootfs}/lxc.hold for writing for * if rootfs is a directory, then open ${rootfs}/lxc.hold for writing for
* the duration of the container run, to prevent the container from marking * the duration of the container run, to prevent the container from marking
* the underlying fs readonly on shutdown. unlink the file immediately so * the underlying fs readonly on shutdown. unlink the file immediately so
...@@ -553,10 +549,9 @@ int run_script(const char *name, const char *section, const char *script, ...) ...@@ -553,10 +549,9 @@ int run_script(const char *name, const char *section, const char *script, ...)
*/ */
int pin_rootfs(const char *rootfs) int pin_rootfs(const char *rootfs)
{ {
char absrootfs[MAXPATHLEN]; int fd, ret;
char absrootfspin[MAXPATHLEN]; char absrootfs[MAXPATHLEN], absrootfspin[MAXPATHLEN];
struct stat s; struct stat s;
int ret, fd;
if (rootfs == NULL || strlen(rootfs) == 0) if (rootfs == NULL || strlen(rootfs) == 0)
return -2; return -2;
...@@ -564,10 +559,12 @@ int pin_rootfs(const char *rootfs) ...@@ -564,10 +559,12 @@ int pin_rootfs(const char *rootfs)
if (!realpath(rootfs, absrootfs)) if (!realpath(rootfs, absrootfs))
return -2; return -2;
if (access(absrootfs, F_OK)) ret = access(absrootfs, F_OK);
if (ret != 0)
return -1; return -1;
if (stat(absrootfs, &s)) ret = stat(absrootfs, &s);
if (ret < 0)
return -1; return -1;
if (!S_ISDIR(s.st_mode)) if (!S_ISDIR(s.st_mode))
...@@ -577,21 +574,23 @@ int pin_rootfs(const char *rootfs) ...@@ -577,21 +574,23 @@ int pin_rootfs(const char *rootfs)
if (ret >= MAXPATHLEN) if (ret >= MAXPATHLEN)
return -1; return -1;
fd = open(absrootfspin, O_CREAT | O_RDWR, S_IWUSR|S_IRUSR); fd = open(absrootfspin, O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
if (fd < 0) if (fd < 0)
return fd; return fd;
(void)unlink(absrootfspin); (void)unlink(absrootfspin);
return fd; return fd;
} }
/* /* If we are asking to remount something, make sure that any NOEXEC etc are
* If we are asking to remount something, make sure that any * honored.
* NOEXEC etc are honored.
*/ */
unsigned long add_required_remount_flags(const char *s, const char *d, unsigned long add_required_remount_flags(const char *s, const char *d,
unsigned long flags) unsigned long flags)
{ {
#ifdef HAVE_STATVFS #ifdef HAVE_STATVFS
int ret;
struct statvfs sb; struct statvfs sb;
unsigned long required_flags = 0; unsigned long required_flags = 0;
...@@ -603,7 +602,9 @@ unsigned long add_required_remount_flags(const char *s, const char *d, ...@@ -603,7 +602,9 @@ unsigned long add_required_remount_flags(const char *s, const char *d,
if (!s) if (!s)
return flags; return flags;
if (statvfs(s, &sb) < 0)
ret = statvfs(s, &sb);
if (ret < 0)
return flags; return flags;
if (sb.f_flag & MS_NOSUID) if (sb.f_flag & MS_NOSUID)
...@@ -623,8 +624,7 @@ unsigned long add_required_remount_flags(const char *s, const char *d, ...@@ -623,8 +624,7 @@ unsigned long add_required_remount_flags(const char *s, const char *d,
static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_handler *handler) static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_handler *handler)
{ {
int r; int i, r;
int i;
static struct { static struct {
int match_mask; int match_mask;
int match_flag; int match_flag;
...@@ -634,16 +634,17 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha ...@@ -634,16 +634,17 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
unsigned long flags; unsigned long flags;
const char *options; const char *options;
} default_mounts[] = { } default_mounts[] = {
/* Read-only bind-mounting... In older kernels, doing that required /* Read-only bind-mounting... In older kernels, doing that
* to do one MS_BIND mount and then MS_REMOUNT|MS_RDONLY the same * required to do one MS_BIND mount and then
* one. According to mount(2) manpage, MS_BIND honors MS_RDONLY from * MS_REMOUNT|MS_RDONLY the same one. According to mount(2)
* kernel 2.6.26 onwards. However, this apparently does not work on * manpage, MS_BIND honors MS_RDONLY from kernel 2.6.26
* kernel 3.8. Unfortunately, on that very same kernel, doing the * onwards. However, this apparently does not work on kernel
* same trick as above doesn't seem to work either, there one needs * 3.8. Unfortunately, on that very same kernel, doing the same
* to ALSO specify MS_BIND for the remount, otherwise the entire * trick as above doesn't seem to work either, there one needs
* fs is remounted read-only or the mount fails because it's busy... * to ALSO specify MS_BIND for the remount, otherwise the
* MS_REMOUNT|MS_BIND|MS_RDONLY seems to work for kernels as low as * entire fs is remounted read-only or the mount fails because
* 2.6.32... * it's busy... MS_REMOUNT|MS_BIND|MS_RDONLY seems to work for
* kernels as low as 2.6.32...
*/ */
{ LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "proc", "%r/proc", "proc", MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL }, { LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "proc", "%r/proc", "proc", MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL },
/* proc/tty is used as a temporary placeholder for proc/sys/net which we'll move back in a few steps */ /* proc/tty is used as a temporary placeholder for proc/sys/net which we'll move back in a few steps */
...@@ -666,44 +667,48 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha ...@@ -666,44 +667,48 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
}; };
for (i = 0; default_mounts[i].match_mask; i++) { for (i = 0; default_mounts[i].match_mask; i++) {
if ((flags & default_mounts[i].match_mask) == default_mounts[i].match_flag) {
char *source = NULL;
char *destination = NULL;
int saved_errno; int saved_errno;
unsigned long mflags; unsigned long mflags;
char *destination = NULL;
char *source = NULL;
if ((flags & default_mounts[i].match_mask) != default_mounts[i].match_flag)
continue;
if (default_mounts[i].source) { if (default_mounts[i].source) {
/* will act like strdup if %r is not present */ /* will act like strdup if %r is not present */
source = lxc_string_replace("%r", conf->rootfs.path ? conf->rootfs.mount : "", default_mounts[i].source); source = lxc_string_replace("%r", conf->rootfs.path ? conf->rootfs.mount : "", default_mounts[i].source);
if (!source) { if (!source)
SYSERROR("memory allocation error");
return -1; return -1;
} }
}
if (!default_mounts[i].destination) { if (!default_mounts[i].destination) {
ERROR("BUG: auto mounts destination %d was NULL", i); ERROR("BUG: auto mounts destination %d was NULL", i);
free(source); free(source);
return -1; return -1;
} }
/* will act like strdup if %r is not present */ /* will act like strdup if %r is not present */
destination = lxc_string_replace("%r", conf->rootfs.path ? conf->rootfs.mount : "", default_mounts[i].destination); destination = lxc_string_replace("%r", conf->rootfs.path ? conf->rootfs.mount : "", default_mounts[i].destination);
if (!destination) { if (!destination) {
saved_errno = errno; saved_errno = errno;
SYSERROR("memory allocation error");
free(source); free(source);
errno = saved_errno; errno = saved_errno;
return -1; return -1;
} }
mflags = add_required_remount_flags(source, destination, mflags = add_required_remount_flags(source, destination,
default_mounts[i].flags); default_mounts[i].flags);
r = safe_mount(source, destination, default_mounts[i].fstype, mflags, default_mounts[i].options, conf->rootfs.path ? conf->rootfs.mount : NULL); r = safe_mount(source, destination, default_mounts[i].fstype,
mflags, default_mounts[i].options,
conf->rootfs.path ? conf->rootfs.mount : NULL);
saved_errno = errno; saved_errno = errno;
if (r < 0 && errno == ENOENT) { if (r < 0 && errno == ENOENT) {
INFO("Mount source or target for %s on %s doesn't exist. Skipping.", source, destination); INFO("Mount source or target for \"%s\" on \"%s\" does "
"not exist. Skipping", source, destination);
r = 0; r = 0;
} else if (r < 0) {
SYSERROR("Failed to mount \"%s\" on \"%s\" with flags %lu", source, destination, mflags);
} }
else if (r < 0)
SYSERROR("error mounting %s on %s flags %lu", source, destination, mflags);
free(source); free(source);
free(destination); free(destination);
...@@ -712,20 +717,21 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha ...@@ -712,20 +717,21 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
return -1; return -1;
} }
} }
}
if (flags & LXC_AUTO_CGROUP_MASK) { if (flags & LXC_AUTO_CGROUP_MASK) {
int cg_flags; int cg_flags;
cg_flags = flags & (LXC_AUTO_CGROUP_MASK & ~LXC_AUTO_CGROUP_FORCE); cg_flags = flags & (LXC_AUTO_CGROUP_MASK & ~LXC_AUTO_CGROUP_FORCE);
/* If the type of cgroup mount was not specified, it depends on the /* If the type of cgroup mount was not specified, it depends on
* container's capabilities as to what makes sense: if we have * the container's capabilities as to what makes sense: if we
* CAP_SYS_ADMIN, the read-only part can be remounted read-write * have CAP_SYS_ADMIN, the read-only part can be remounted
* anyway, so we may as well default to read-write; then the admin * read-write anyway, so we may as well default to read-write;
* will not be given a false sense of security. (And if they really * then the admin will not be given a false sense of security.
* want mixed r/o r/w, then they can explicitly specify :mixed.) * (And if they really want mixed r/o r/w, then they can
* OTOH, if the container lacks CAP_SYS_ADMIN, do only default to * explicitly specify :mixed.) OTOH, if the container lacks
* :mixed, because then the container can't remount it read-write. */ * CAP_SYS_ADMIN, do only default to :mixed, because then the
* container can't remount it read-write.
*/
if (cg_flags == LXC_AUTO_CGROUP_NOSPEC || cg_flags == LXC_AUTO_CGROUP_FULL_NOSPEC) { if (cg_flags == LXC_AUTO_CGROUP_NOSPEC || cg_flags == LXC_AUTO_CGROUP_FULL_NOSPEC) {
int has_sys_admin = 0; int has_sys_admin = 0;
...@@ -739,10 +745,12 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha ...@@ -739,10 +745,12 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
else else
cg_flags = has_sys_admin ? LXC_AUTO_CGROUP_FULL_RW : LXC_AUTO_CGROUP_FULL_MIXED; cg_flags = has_sys_admin ? LXC_AUTO_CGROUP_FULL_RW : LXC_AUTO_CGROUP_FULL_MIXED;
} }
if (flags & LXC_AUTO_CGROUP_FORCE) if (flags & LXC_AUTO_CGROUP_FORCE)
cg_flags |= LXC_AUTO_CGROUP_FORCE; cg_flags |= LXC_AUTO_CGROUP_FORCE;
if (!cgroup_mount(conf->rootfs.path ? conf->rootfs.mount : "", handler, cg_flags)) { if (!cgroup_mount(conf->rootfs.path ? conf->rootfs.mount : "", handler, cg_flags)) {
SYSERROR("error mounting /sys/fs/cgroup"); SYSERROR("Failed to mount \"/sys/fs/cgroup\"");
return -1; return -1;
} }
} }
...@@ -752,15 +760,18 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha ...@@ -752,15 +760,18 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
static int setup_utsname(struct utsname *utsname) static int setup_utsname(struct utsname *utsname)
{ {
int ret;
if (!utsname) if (!utsname)
return 0; return 0;
if (sethostname(utsname->nodename, strlen(utsname->nodename))) { ret = sethostname(utsname->nodename, strlen(utsname->nodename));
SYSERROR("failed to set the hostname to '%s'", utsname->nodename); if (ret < 0) {
SYSERROR("Failed to set the hostname to \"%s\"", utsname->nodename);
return -1; return -1;
} }
INFO("'%s' hostname has been setup", utsname->nodename); INFO("Set hostname to \"%s\"", utsname->nodename);
return 0; return 0;
} }
...@@ -771,44 +782,44 @@ struct dev_symlinks { ...@@ -771,44 +782,44 @@ struct dev_symlinks {
}; };
static const struct dev_symlinks dev_symlinks[] = { static const struct dev_symlinks dev_symlinks[] = {
{"/proc/self/fd", "fd"}, { "/proc/self/fd", "fd" },
{"/proc/self/fd/0", "stdin"}, { "/proc/self/fd/0", "stdin" },
{"/proc/self/fd/1", "stdout"}, { "/proc/self/fd/1", "stdout" },
{"/proc/self/fd/2", "stderr"}, { "/proc/self/fd/2", "stderr" },
}; };
static int lxc_setup_dev_symlinks(const struct lxc_rootfs *rootfs) static int lxc_setup_dev_symlinks(const struct lxc_rootfs *rootfs)
{ {
int i, ret;
char path[MAXPATHLEN]; char path[MAXPATHLEN];
int ret,i;
struct stat s; struct stat s;
for (i = 0; i < sizeof(dev_symlinks) / sizeof(dev_symlinks[0]); i++) { for (i = 0; i < sizeof(dev_symlinks) / sizeof(dev_symlinks[0]); i++) {
const struct dev_symlinks *d = &dev_symlinks[i]; const struct dev_symlinks *d = &dev_symlinks[i];
ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->path ? rootfs->mount : "", d->name);
ret = snprintf(path, sizeof(path), "%s/dev/%s",
rootfs->path ? rootfs->mount : "", d->name);
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
return -1; return -1;
/* /* Stat the path first. If we don't get an error accept it as
* Stat the path first. If we don't get an error * is and don't try to create it
* accept it as is and don't try to create it
*/ */
if (!stat(path, &s)) { ret = stat(path, &s);
if (ret == 0)
continue; continue;
}
ret = symlink(d->oldpath, path); ret = symlink(d->oldpath, path);
if (ret && errno != EEXIST) { if (ret && errno != EEXIST) {
if ( errno == EROFS ) { if (errno == EROFS) {
WARN("Warning: Read Only file system while creating %s", path); WARN("Failed to create \"%s\". Read-only filesystem", path);
} else { } else {
SYSERROR("Error creating %s", path); SYSERROR("Failed to create \"%s\"", path);
return -1; return -1;
} }
} }
} }
return 0; return 0;
} }
...@@ -821,15 +832,19 @@ static bool append_ptyname(char **pp, char *name) ...@@ -821,15 +832,19 @@ static bool append_ptyname(char **pp, char *name)
*pp = malloc(strlen(name) + strlen("container_ttys=") + 1); *pp = malloc(strlen(name) + strlen("container_ttys=") + 1);
if (!*pp) if (!*pp)
return false; return false;
sprintf(*pp, "container_ttys=%s", name); sprintf(*pp, "container_ttys=%s", name);
return true; return true;
} }
p = realloc(*pp, strlen(*pp) + strlen(name) + 2); p = realloc(*pp, strlen(*pp) + strlen(name) + 2);
if (!p) if (!p)
return false; return false;
*pp = p; *pp = p;
strcat(p, " "); strcat(p, " ");
strcat(p, name); strcat(p, name);
return true; return true;
} }
...@@ -877,7 +892,7 @@ static int lxc_setup_ttys(struct lxc_conf *conf) ...@@ -877,7 +892,7 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
tty->name, path); tty->name, path);
continue; continue;
} }
DEBUG("bind mounted \"%s\" onto \"%s\"", tty->name, DEBUG("Bind mounted \"%s\" onto \"%s\"", tty->name,
path); path);
ret = snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d", ret = snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d",
...@@ -928,8 +943,8 @@ static int lxc_setup_ttys(struct lxc_conf *conf) ...@@ -928,8 +943,8 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
int lxc_allocate_ttys(const char *name, struct lxc_conf *conf) int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
{ {
struct lxc_tty_info *ttys = &conf->ttys;
int i, ret; int i, ret;
struct lxc_tty_info *ttys = &conf->ttys;
/* no tty in the configuration */ /* no tty in the configuration */
if (!conf->tty) if (!conf->tty)
...@@ -945,26 +960,26 @@ int lxc_allocate_ttys(const char *name, struct lxc_conf *conf) ...@@ -945,26 +960,26 @@ int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
ret = openpty(&tty->master, &tty->slave, ret = openpty(&tty->master, &tty->slave,
tty->name, NULL, NULL); tty->name, NULL, NULL);
if (ret) { if (ret) {
SYSERROR("failed to create pty device number %d", i); SYSERROR("Failed to create tty %d", i);
ttys->nbtty = i; ttys->nbtty = i;
lxc_delete_tty(ttys); lxc_delete_tty(ttys);
return -ENOTTY; return -ENOTTY;
} }
DEBUG("allocated pty \"%s\" with master fd %d and slave fd %d", DEBUG("Created tty \"%s\" with master fd %d and slave fd %d",
tty->name, tty->master, tty->slave); tty->name, tty->master, tty->slave);
/* Prevent leaking the file descriptors to the container */ /* Prevent leaking the file descriptors to the container */
ret = fcntl(tty->master, F_SETFD, FD_CLOEXEC); ret = fcntl(tty->master, F_SETFD, FD_CLOEXEC);
if (ret < 0) if (ret < 0)
WARN("failed to set FD_CLOEXEC flag on master fd %d of " WARN("Failed to set FD_CLOEXEC flag on master fd %d of "
"pty device \"%s\": %s", "tty device \"%s\": %s",
tty->master, tty->name, strerror(errno)); tty->master, tty->name, strerror(errno));
ret = fcntl(tty->slave, F_SETFD, FD_CLOEXEC); ret = fcntl(tty->slave, F_SETFD, FD_CLOEXEC);
if (ret < 0) if (ret < 0)
WARN("failed to set FD_CLOEXEC flag on slave fd %d of " WARN("Failed to set FD_CLOEXEC flag on slave fd %d of "
"pty device \"%s\": %s", "tty device \"%s\": %s",
tty->slave, tty->name, strerror(errno)); tty->slave, tty->name, strerror(errno));
tty->busy = 0; tty->busy = 0;
...@@ -972,7 +987,7 @@ int lxc_allocate_ttys(const char *name, struct lxc_conf *conf) ...@@ -972,7 +987,7 @@ int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
ttys->nbtty = conf->tty; ttys->nbtty = conf->tty;
INFO("finished allocating %d pts devices", conf->tty); INFO("Finished creating %d tty devices", conf->tty);
return 0; return 0;
} }
...@@ -995,12 +1010,12 @@ void lxc_delete_tty(struct lxc_tty_info *ttys) ...@@ -995,12 +1010,12 @@ void lxc_delete_tty(struct lxc_tty_info *ttys)
static int lxc_send_ttys_to_parent(struct lxc_handler *handler) static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
{ {
int i; int i;
int ret = -1;
struct lxc_conf *conf = handler->conf; struct lxc_conf *conf = handler->conf;
struct lxc_tty_info *ttys = &conf->ttys; struct lxc_tty_info *ttys = &conf->ttys;
int sock = handler->data_sock[0]; int sock = handler->data_sock[0];
int ret = -1;
if (!conf->tty) if (conf->tty == 0)
return 0; return 0;
for (i = 0; i < conf->tty; i++) { for (i = 0; i < conf->tty; i++) {
...@@ -1014,7 +1029,7 @@ static int lxc_send_ttys_to_parent(struct lxc_handler *handler) ...@@ -1014,7 +1029,7 @@ static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
if (ret < 0) if (ret < 0)
break; break;
TRACE("Send pty \"%s\" with master fd %d and slave fd %d to " TRACE("Sent ty \"%s\" with master fd %d and slave fd %d to "
"parent", tty->name, tty->master, tty->slave); "parent", tty->name, tty->master, tty->slave);
} }
...@@ -1068,62 +1083,70 @@ on_error: ...@@ -1068,62 +1083,70 @@ on_error:
static int setup_rootfs_pivot_root(const char *rootfs) static int setup_rootfs_pivot_root(const char *rootfs)
{ {
int oldroot = -1, newroot = -1; int ret;
int newroot = -1, oldroot = -1;
oldroot = open("/", O_DIRECTORY | O_RDONLY); oldroot = open("/", O_DIRECTORY | O_RDONLY);
if (oldroot < 0) { if (oldroot < 0) {
SYSERROR("Error opening old-/ for fchdir"); SYSERROR("Failed to open old root directory");
return -1; return -1;
} }
newroot = open(rootfs, O_DIRECTORY | O_RDONLY); newroot = open(rootfs, O_DIRECTORY | O_RDONLY);
if (newroot < 0) { if (newroot < 0) {
SYSERROR("Error opening new-/ for fchdir"); SYSERROR("Failed to open new root directory");
goto fail; goto on_error;
} }
/* change into new root fs */ /* change into new root fs */
if (fchdir(newroot)) { ret = fchdir(newroot);
SYSERROR("can't chdir to new rootfs '%s'", rootfs); if (ret < 0) {
goto fail; SYSERROR("Failed to change to new rootfs \"%s\"", rootfs);
goto on_error;
} }
/* pivot_root into our new root fs */ /* pivot_root into our new root fs */
if (pivot_root(".", ".")) { ret = pivot_root(".", ".");
SYSERROR("pivot_root syscall failed"); if (ret < 0) {
goto fail; SYSERROR("Failed to pivot_root()");
goto on_error;
} }
/* /* At this point the old-root is mounted on top of our new-root To
* at this point the old-root is mounted on top of our new-root * unmounted it we must not be chdir'd into it, so escape back to
* To unmounted it we must not be chdir'd into it, so escape back * old-root.
* to old-root
*/ */
if (fchdir(oldroot) < 0) { ret = fchdir(oldroot);
SYSERROR("Error entering oldroot"); if (ret < 0) {
goto fail; SYSERROR("Failed to enter old root directory");
goto on_error;
} }
if (umount2(".", MNT_DETACH) < 0) {
SYSERROR("Error detaching old root"); ret = umount2(".", MNT_DETACH);
goto fail; if (ret < 0) {
SYSERROR("Failed to detach old root directory");
goto on_error;
} }
if (fchdir(newroot) < 0) { ret = fchdir(newroot);
SYSERROR("Error re-entering newroot"); if (ret < 0) {
goto fail; SYSERROR("Failed to re-enter new root directory");
goto on_error;
} }
close(oldroot); close(oldroot);
close(newroot); close(newroot);
DEBUG("pivot_root syscall to '%s' successful", rootfs); DEBUG("pivot_root(\"%s\") successful", rootfs);
return 0; return 0;
fail: on_error:
if (oldroot != -1) if (oldroot != -1)
close(oldroot); close(oldroot);
if (newroot != -1) if (newroot != -1)
close(newroot); close(newroot);
return -1; return -1;
} }
...@@ -1275,22 +1298,25 @@ static int lxc_setup_rootfs(struct lxc_conf *conf) ...@@ -1275,22 +1298,25 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
rootfs = &conf->rootfs; rootfs = &conf->rootfs;
if (!rootfs->path) { if (!rootfs->path) {
if (mount("", "/", NULL, MS_SLAVE | MS_REC, 0)) { ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0);
SYSERROR("Failed to make / rslave."); if (ret < 0) {
SYSERROR("Failed to make / rslave");
return -1; return -1;
} }
return 0; return 0;
} }
if (access(rootfs->mount, F_OK)) { ret = access(rootfs->mount, F_OK);
SYSERROR("Failed to access to \"%s\". Check it is present.", if (ret != 0) {
SYSERROR("Failed to access to \"%s\". Check it is present",
rootfs->mount); rootfs->mount);
return -1; return -1;
} }
bdev = storage_init(conf); bdev = storage_init(conf);
if (!bdev) { if (!bdev) {
ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".", ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
rootfs->path, rootfs->mount, rootfs->path, rootfs->mount,
rootfs->options ? rootfs->options : "(null)"); rootfs->options ? rootfs->options : "(null)");
return -1; return -1;
...@@ -1299,13 +1325,13 @@ static int lxc_setup_rootfs(struct lxc_conf *conf) ...@@ -1299,13 +1325,13 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
ret = bdev->ops->mount(bdev); ret = bdev->ops->mount(bdev);
storage_put(bdev); storage_put(bdev);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".", ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
rootfs->path, rootfs->mount, rootfs->path, rootfs->mount,
rootfs->options ? rootfs->options : "(null)"); rootfs->options ? rootfs->options : "(null)");
return -1; return -1;
} }
DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\".", DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\"",
rootfs->path, rootfs->mount, rootfs->path, rootfs->mount,
rootfs->options ? rootfs->options : "(null)"); rootfs->options ? rootfs->options : "(null)");
...@@ -1314,35 +1340,35 @@ static int lxc_setup_rootfs(struct lxc_conf *conf) ...@@ -1314,35 +1340,35 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
int prepare_ramfs_root(char *root) int prepare_ramfs_root(char *root)
{ {
char buf[LXC_LINELEN], *p; int i, ret;
char nroot[PATH_MAX]; char *p, *p2;
char buf[LXC_LINELEN], nroot[PATH_MAX];
FILE *f; FILE *f;
int i;
char *p2;
if (realpath(root, nroot) == NULL) if (!realpath(root, nroot))
return -errno; return -1;
if (chdir("/") == -1) ret = chdir("/");
return -errno; if (ret < 0)
return -1;
/* /* We could use here MS_MOVE, but in userns this mount is locked and
* We could use here MS_MOVE, but in userns this mount is * can't be moved.
* locked and can't be moved.
*/ */
if (mount(root, "/", NULL, MS_REC | MS_BIND, NULL) < 0) { ret = mount(root, "/", NULL, MS_REC | MS_BIND, NULL);
SYSERROR("Failed to move %s into /", root); if (ret < 0) {
return -errno; SYSERROR("Failed to move \"%s\" into \"/\"", root);
return -1;
} }
if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) < 0) { ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL);
SYSERROR("Failed to make . rprivate"); if (ret < 0) {
return -errno; SYSERROR("Failed to make \"/\" rprivate");
return -1;
} }
/* /* The following code cleans up inhereted mounts which are not required
* The following code cleans up inhereted mounts which are not * for CT.
* required for CT.
* *
* The mountinfo file shows not all mounts, if a few points have been * The mountinfo file shows not all mounts, if a few points have been
* unmounted between read operations from the mountinfo. So we need to * unmounted between read operations from the mountinfo. So we need to
...@@ -1351,7 +1377,7 @@ int prepare_ramfs_root(char *root) ...@@ -1351,7 +1377,7 @@ int prepare_ramfs_root(char *root)
* This loop can be skipped if a container uses unserns, because all * This loop can be skipped if a container uses unserns, because all
* inherited mounts are locked and we should live with all this trash. * inherited mounts are locked and we should live with all this trash.
*/ */
while (1) { for (;;) {
int progress = 0; int progress = 0;
f = fopen("./proc/self/mountinfo", "r"); f = fopen("./proc/self/mountinfo", "r");
...@@ -1359,11 +1385,14 @@ int prepare_ramfs_root(char *root) ...@@ -1359,11 +1385,14 @@ int prepare_ramfs_root(char *root)
SYSERROR("Unable to open /proc/self/mountinfo"); SYSERROR("Unable to open /proc/self/mountinfo");
return -1; return -1;
} }
while (fgets(buf, LXC_LINELEN, f)) { while (fgets(buf, LXC_LINELEN, f)) {
for (p = buf, i=0; p && i < 4; i++) for (p = buf, i=0; p && i < 4; i++)
p = strchr(p+1, ' '); p = strchr(p+1, ' ');
if (!p) if (!p)
continue; continue;
p2 = strchr(p+1, ' '); p2 = strchr(p+1, ' ');
if (!p2) if (!p2)
continue; continue;
...@@ -1373,27 +1402,33 @@ int prepare_ramfs_root(char *root) ...@@ -1373,27 +1402,33 @@ int prepare_ramfs_root(char *root)
if (strcmp(p + 1, "/") == 0) if (strcmp(p + 1, "/") == 0)
continue; continue;
if (strcmp(p + 1, "/proc") == 0) if (strcmp(p + 1, "/proc") == 0)
continue; continue;
if (umount2(p, MNT_DETACH) == 0) ret = umount2(p, MNT_DETACH);
if (ret == 0)
progress++; progress++;
} }
fclose(f); fclose(f);
if (!progress) if (!progress)
break; break;
} }
/* This also can be skipped if a container uses unserns */ /* This also can be skipped if a container uses unserns. */
umount2("./proc", MNT_DETACH); (void)umount2("./proc", MNT_DETACH);
/* It is weird, but chdir("..") moves us in a new root */ /* It is weird, but chdir("..") moves us in a new root */
if (chdir("..") == -1) { ret = chdir("..");
if (ret < 0) {
SYSERROR("Unable to change working directory"); SYSERROR("Unable to change working directory");
return -1; return -1;
} }
if (chroot(".") == -1) { ret = chroot(".");
if (ret < 0) {
SYSERROR("Unable to chroot"); SYSERROR("Unable to chroot");
return -1; return -1;
} }
...@@ -1403,28 +1438,33 @@ int prepare_ramfs_root(char *root) ...@@ -1403,28 +1438,33 @@ int prepare_ramfs_root(char *root)
static int setup_pivot_root(const struct lxc_rootfs *rootfs) static int setup_pivot_root(const struct lxc_rootfs *rootfs)
{ {
int ret;
if (!rootfs->path) { if (!rootfs->path) {
DEBUG("container does not have a rootfs, so not doing pivot root"); DEBUG("Container does not have a rootfs");
return 0; return 0;
} }
if (detect_ramfs_rootfs()) { if (detect_ramfs_rootfs()) {
DEBUG("detected that container is on ramfs"); DEBUG("Detected that container is on ramfs");
if (prepare_ramfs_root(rootfs->mount)) {
ERROR("failed to prepare minimal ramfs root"); ret = prepare_ramfs_root(rootfs->mount);
if (ret < 0) {
ERROR("Failed to prepare minimal ramfs root");
return -1; return -1;
} }
DEBUG("prepared ramfs root for container"); DEBUG("Prepared ramfs root for container");
return 0; return 0;
} }
if (setup_rootfs_pivot_root(rootfs->mount) < 0) { ret = setup_rootfs_pivot_root(rootfs->mount);
ERROR("failed to pivot root"); if (ret < 0) {
ERROR("Failed to pivot_root()");
return -1; return -1;
} }
DEBUG("finished pivot root"); DEBUG("Finished pivot_root()");
return 0; return 0;
} }
...@@ -1465,7 +1505,7 @@ static int lxc_setup_devpts(struct lxc_conf *conf) ...@@ -1465,7 +1505,7 @@ static int lxc_setup_devpts(struct lxc_conf *conf)
char devpts_mntopts[256]; char devpts_mntopts[256];
if (conf->pts <= 0) { if (conf->pts <= 0) {
DEBUG("no new devpts instance will be mounted since no pts " DEBUG("No new devpts instance will be mounted since no pts "
"devices are requested"); "devices are requested");
return 0; return 0;
} }
...@@ -1485,88 +1525,91 @@ static int lxc_setup_devpts(struct lxc_conf *conf) ...@@ -1485,88 +1525,91 @@ static int lxc_setup_devpts(struct lxc_conf *conf)
if (!ret) { if (!ret) {
ret = umount("/dev/pts"); ret = umount("/dev/pts");
if (ret < 0) { if (ret < 0) {
SYSERROR("failed to unmount old devpts instance"); SYSERROR("Failed to unmount old devpts instance");
return -1; return -1;
} }
DEBUG("unmounted old /dev/pts instance"); DEBUG("Unmounted old devpts instance");
} }
/* Create mountpoint for devpts instance. */ /* Create mountpoint for devpts instance. */
ret = mkdir("/dev/pts", 0755); ret = mkdir("/dev/pts", 0755);
if (ret < 0 && errno != EEXIST) { if (ret < 0 && errno != EEXIST) {
SYSERROR("failed to create the \"/dev/pts\" directory"); SYSERROR("Failed to create \"/dev/pts\" directory");
return -1; return -1;
} }
/* Mount new devpts instance. */ /* Mount new devpts instance. */
ret = mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, devpts_mntopts); ret = mount("devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC, devpts_mntopts);
if (ret < 0) { if (ret < 0) {
SYSERROR("failed to mount new devpts instance"); SYSERROR("Failed to mount new devpts instance");
return -1; return -1;
} }
DEBUG("mount new devpts instance with options \"%s\"", devpts_mntopts); DEBUG("Mount new devpts instance with options \"%s\"", devpts_mntopts);
/* Remove any pre-existing /dev/ptmx file. */ /* Remove any pre-existing /dev/ptmx file. */
ret = access("/dev/ptmx", F_OK); ret = access("/dev/ptmx", F_OK);
if (!ret) { if (!ret) {
ret = remove("/dev/ptmx"); ret = remove("/dev/ptmx");
if (ret < 0) { if (ret < 0) {
SYSERROR("failed to remove existing \"/dev/ptmx\""); SYSERROR("Failed to remove existing \"/dev/ptmx\" file");
return -1; return -1;
} }
DEBUG("removed existing \"/dev/ptmx\""); DEBUG("Removed existing \"/dev/ptmx\" file");
} }
/* Create dummy /dev/ptmx file as bind mountpoint for /dev/pts/ptmx. */ /* Create dummy /dev/ptmx file as bind mountpoint for /dev/pts/ptmx. */
ret = open("/dev/ptmx", O_CREAT, 0666); ret = open("/dev/ptmx", O_CREAT, 0666);
if (ret < 0) { if (ret < 0) {
SYSERROR("failed to create dummy \"/dev/ptmx\" file as bind mount target"); SYSERROR("Failed to create dummy \"/dev/ptmx\" file as bind mount target");
return -1; return -1;
} }
close(ret); close(ret);
DEBUG("created dummy \"/dev/ptmx\" file as bind mount target"); DEBUG("Created dummy \"/dev/ptmx\" file as bind mount target");
/* Fallback option: create symlink /dev/ptmx -> /dev/pts/ptmx */ /* Fallback option: create symlink /dev/ptmx -> /dev/pts/ptmx */
ret = mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_BIND, NULL); ret = mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_BIND, NULL);
if (!ret) { if (!ret) {
DEBUG("bind mounted \"/dev/pts/ptmx\" to \"/dev/ptmx\""); DEBUG("Bind mounted \"/dev/pts/ptmx\" to \"/dev/ptmx\"");
return 0; return 0;
} else { } else {
/* Fallthrough and try to create a symlink. */ /* Fallthrough and try to create a symlink. */
ERROR("failed to bind mount \"/dev/pts/ptmx\" to \"/dev/ptmx\""); ERROR("Failed to bind mount \"/dev/pts/ptmx\" to \"/dev/ptmx\"");
} }
/* Remove the dummy /dev/ptmx file we created above. */ /* Remove the dummy /dev/ptmx file we created above. */
ret = remove("/dev/ptmx"); ret = remove("/dev/ptmx");
if (ret < 0) { if (ret < 0) {
SYSERROR("failed to remove existing \"/dev/ptmx\""); SYSERROR("Failed to remove existing \"/dev/ptmx\"");
return -1; return -1;
} }
/* Fallback option: Create symlink /dev/ptmx -> /dev/pts/ptmx. */ /* Fallback option: Create symlink /dev/ptmx -> /dev/pts/ptmx. */
ret = symlink("/dev/pts/ptmx", "/dev/ptmx"); ret = symlink("/dev/pts/ptmx", "/dev/ptmx");
if (ret < 0) { if (ret < 0) {
SYSERROR("failed to create symlink \"/dev/ptmx\" -> \"/dev/pts/ptmx\""); SYSERROR("Failed to create symlink from \"/dev/ptmx\" to \"/dev/pts/ptmx\"");
return -1; return -1;
} }
DEBUG("created symlink \"/dev/ptmx\" -> \"/dev/pts/ptmx\""); DEBUG("Created symlink from \"/dev/ptmx\" to \"/dev/pts/ptmx\"");
return 0; return 0;
} }
static int setup_personality(int persona) static int setup_personality(int persona)
{ {
#if HAVE_SYS_PERSONALITY_H int ret;
#if HAVE_SYS_PERSONALITY_H
if (persona == -1) if (persona == -1)
return 0; return 0;
if (personality(persona) < 0) { ret = personality(persona);
SYSERROR("failed to set personality to '0x%x'", persona); if (ret < 0) {
SYSERROR("Failed to set personality to \"0x%x\"", persona);
return -1; return -1;
} }
INFO("set personality to '0x%x'", persona); INFO("Set personality to \"0x%x\"", persona);
#endif #endif
return 0; return 0;
} }
...@@ -1574,8 +1617,8 @@ static int setup_personality(int persona) ...@@ -1574,8 +1617,8 @@ static int setup_personality(int persona)
static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs, static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs,
const struct lxc_terminal *console) const struct lxc_terminal *console)
{ {
int fd, ret;
char path[MAXPATHLEN]; char path[MAXPATHLEN];
int ret, fd;
char *rootfs_path = rootfs->path ? rootfs->mount : ""; char *rootfs_path = rootfs->path ? rootfs->mount : "";
if (console->path && !strcmp(console->path, "none")) if (console->path && !strcmp(console->path, "none"))
...@@ -1613,13 +1656,14 @@ static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs, ...@@ -1613,13 +1656,14 @@ static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs,
ret = chmod(console->name, S_IXUSR | S_IXGRP | S_IXOTH); ret = chmod(console->name, S_IXUSR | S_IXGRP | S_IXOTH);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to set mode '0%o' to '%s'", S_IXUSR | S_IXGRP | S_IXOTH, console->name); SYSERROR("Failed to set mode \"0%o\" to \"%s\"",
S_IXUSR | S_IXGRP | S_IXOTH, console->name);
return -errno; return -errno;
} }
ret = safe_mount(console->name, path, "none", MS_BIND, 0, rootfs_path); ret = safe_mount(console->name, path, "none", MS_BIND, 0, rootfs_path);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to mount '%s' on '%s'", console->name, path); ERROR("Failed to mount \"%s\" on \"%s\"", console->name, path);
return -1; return -1;
} }
...@@ -1645,7 +1689,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, ...@@ -1645,7 +1689,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
ret = mkdir(path, 0755); ret = mkdir(path, 0755);
if (ret && errno != EEXIST) { if (ret && errno != EEXIST) {
SYSERROR("Failed with errno %d to create %s", errno, path); SYSERROR("Failed to create \"%s\"", path);
return -errno; return -errno;
} }
DEBUG("Created directory for console and tty devices at \"%s\"", path); DEBUG("Created directory for console and tty devices at \"%s\"", path);
...@@ -1656,7 +1700,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, ...@@ -1656,7 +1700,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
ret = creat(lxcpath, 0660); ret = creat(lxcpath, 0660);
if (ret == -1 && errno != EEXIST) { if (ret == -1 && errno != EEXIST) {
SYSERROR("Error %d creating %s", errno, lxcpath); SYSERROR("Failed to create \"%s\"", lxcpath);
return -errno; return -errno;
} }
if (ret >= 0) if (ret >= 0)
...@@ -1669,7 +1713,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, ...@@ -1669,7 +1713,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
if (file_exists(path)) { if (file_exists(path)) {
ret = lxc_unstack_mountpoint(path, false); ret = lxc_unstack_mountpoint(path, false);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to unmount \"%s\": %s", path, strerror(errno)); ERROR("%s - Failed to unmount \"%s\"", strerror(errno), path);
return -ret; return -ret;
} else { } else {
DEBUG("Cleared all (%d) mounts from \"%s\"", ret, path); DEBUG("Cleared all (%d) mounts from \"%s\"", ret, path);
...@@ -1688,14 +1732,15 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, ...@@ -1688,14 +1732,15 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
ret = chmod(console->name, S_IXUSR | S_IXGRP | S_IXOTH); ret = chmod(console->name, S_IXUSR | S_IXGRP | S_IXOTH);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to set mode '0%o' to '%s'", S_IXUSR | S_IXGRP | S_IXOTH, console->name); SYSERROR("Failed to set mode \"0%o\" to \"%s\"",
S_IXUSR | S_IXGRP | S_IXOTH, console->name);
return -errno; return -errno;
} }
/* bind mount console->name to '/dev/<ttydir>/console' */ /* bind mount console->name to '/dev/<ttydir>/console' */
ret = safe_mount(console->name, lxcpath, "none", MS_BIND, 0, rootfs_path); ret = safe_mount(console->name, lxcpath, "none", MS_BIND, 0, rootfs_path);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to mount '%s' on '%s'", console->name, lxcpath); ERROR("Failed to mount \"%s\" on \"%s\"", console->name, lxcpath);
return -1; return -1;
} }
DEBUG("Mounted \"%s\" onto \"%s\"", console->name, lxcpath); DEBUG("Mounted \"%s\" onto \"%s\"", console->name, lxcpath);
...@@ -1703,13 +1748,12 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, ...@@ -1703,13 +1748,12 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
/* bind mount '/dev/<ttydir>/console' to '/dev/console' */ /* bind mount '/dev/<ttydir>/console' to '/dev/console' */
ret = safe_mount(lxcpath, path, "none", MS_BIND, 0, rootfs_path); ret = safe_mount(lxcpath, path, "none", MS_BIND, 0, rootfs_path);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to mount '%s' on '%s'", console->name, lxcpath); ERROR("Failed to mount \"%s\" on \"%s\"", console->name, lxcpath);
return -1; return -1;
} }
DEBUG("Mounted \"%s\" onto \"%s\"", console->name, lxcpath); DEBUG("Mounted \"%s\" onto \"%s\"", console->name, lxcpath);
DEBUG("Console has been setup under \"%s\" and mounted to \"%s\"", lxcpath, path); DEBUG("Console has been setup under \"%s\" and mounted to \"%s\"", lxcpath, path);
return 0; return 0;
} }
...@@ -1731,7 +1775,7 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data) ...@@ -1731,7 +1775,7 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data)
* Otherwise append it to data. */ * Otherwise append it to data. */
for (mo = &mount_opt[0]; mo->name != NULL; mo++) { for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
if (!strncmp(opt, mo->name, strlen(mo->name))) { if (strncmp(opt, mo->name, strlen(mo->name)) == 0) {
if (mo->clear) if (mo->clear)
*flags &= ~mo->flag; *flags &= ~mo->flag;
else else
...@@ -1745,11 +1789,10 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data) ...@@ -1745,11 +1789,10 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data)
strcat(*data, opt); strcat(*data, opt);
} }
int parse_mntopts(const char *mntopts, unsigned long *mntflags, int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata)
char **mntdata)
{ {
char *s, *data; char *data, *p, *s;
char *p, *saveptr = NULL; char *saveptr = NULL;
*mntdata = NULL; *mntdata = NULL;
*mntflags = 0L; *mntflags = 0L;
...@@ -1758,21 +1801,17 @@ int parse_mntopts(const char *mntopts, unsigned long *mntflags, ...@@ -1758,21 +1801,17 @@ int parse_mntopts(const char *mntopts, unsigned long *mntflags,
return 0; return 0;
s = strdup(mntopts); s = strdup(mntopts);
if (!s) { if (!s)
SYSERROR("failed to allocate memory");
return -1; return -1;
}
data = malloc(strlen(s) + 1); data = malloc(strlen(s) + 1);
if (!data) { if (!data) {
SYSERROR("failed to allocate memory");
free(s); free(s);
return -1; return -1;
} }
*data = 0; *data = 0;
for (p = strtok_r(s, ",", &saveptr); p != NULL; for (; (p = strtok_r(s, ",", &saveptr)); s = NULL)
p = strtok_r(NULL, ",", &saveptr))
parse_mntopt(p, mntflags, &data); parse_mntopt(p, mntflags, &data);
if (*data) if (*data)
...@@ -1789,23 +1828,23 @@ static void parse_propagationopt(char *opt, unsigned long *flags) ...@@ -1789,23 +1828,23 @@ static void parse_propagationopt(char *opt, unsigned long *flags)
struct mount_opt *mo; struct mount_opt *mo;
/* If opt is found in propagation_opt, set or clear flags. */ /* If opt is found in propagation_opt, set or clear flags. */
for (mo = &propagation_opt[0]; mo->name != NULL; mo++) { for (mo = &propagation_opt[0]; mo->name != NULL; mo++) {
if (strncmp(opt, mo->name, strlen(mo->name)) == 0) { if (strncmp(opt, mo->name, strlen(mo->name)) != 0)
continue;
if (mo->clear) if (mo->clear)
*flags &= ~mo->flag; *flags &= ~mo->flag;
else else
*flags |= mo->flag; *flags |= mo->flag;
return; return;
} }
}
} }
static int parse_propagationopts(const char *mntopts, unsigned long *pflags) static int parse_propagationopts(const char *mntopts, unsigned long *pflags)
{ {
char *s; char *p, *s;
char *p, *saveptr = NULL; char *saveptr = NULL;
*pflags = 0L;
if (!mntopts) if (!mntopts)
return 0; return 0;
...@@ -1816,11 +1855,11 @@ static int parse_propagationopts(const char *mntopts, unsigned long *pflags) ...@@ -1816,11 +1855,11 @@ static int parse_propagationopts(const char *mntopts, unsigned long *pflags)
return -ENOMEM; return -ENOMEM;
} }
for (p = strtok_r(s, ",", &saveptr); p != NULL; *pflags = 0L;
p = strtok_r(NULL, ",", &saveptr)) for (; (p = strtok_r(s, ",", &saveptr)); s = NULL)
parse_propagationopt(p, pflags); parse_propagationopt(p, pflags);
free(s); free(s);
return 0; return 0;
} }
...@@ -1831,21 +1870,22 @@ static void null_endofword(char *word) ...@@ -1831,21 +1870,22 @@ static void null_endofword(char *word)
*word = '\0'; *word = '\0';
} }
/* /* skip @nfields spaces in @src */
* skip @nfields spaces in @src
*/
static char *get_field(char *src, int nfields) static char *get_field(char *src, int nfields)
{ {
char *p = src;
int i; int i;
char *p = src;
for (i = 0; i < nfields; i++) { for (i = 0; i < nfields; i++) {
while (*p && *p != ' ' && *p != '\t') while (*p && *p != ' ' && *p != '\t')
p++; p++;
if (!*p) if (!*p)
break; break;
p++; p++;
} }
return p; return p;
} }
...@@ -1874,8 +1914,9 @@ static int mount_entry(const char *fsname, const char *target, ...@@ -1874,8 +1914,9 @@ static int mount_entry(const char *fsname, const char *target,
rootfs); rootfs);
if (ret < 0) { if (ret < 0) {
if (optional) { if (optional) {
INFO("Failed to mount \"%s\" on \"%s\" (optional): %s", INFO("%s - Failed to mount \"%s\" on \"%s\" "
srcpath ? srcpath : "(null)", target, strerror(errno)); "(optional)", strerror(errno),
srcpath ? srcpath : "(null)", target);
return 0; return 0;
} }
...@@ -1974,7 +2015,13 @@ skipremount: ...@@ -1974,7 +2015,13 @@ skipremount:
static void cull_mntent_opt(struct mntent *mntent) static void cull_mntent_opt(struct mntent *mntent)
{ {
int i; int i;
char *list[] = {"create=dir", "create=file", "optional", "relative", NULL}; char *list[] = {
"create=dir",
"create=file",
"optional",
"relative",
NULL
};
for (i = 0; list[i]; i++) { for (i = 0; list[i]; i++) {
char *p, *p2; char *p, *p2;
...@@ -1997,8 +2044,7 @@ static void cull_mntent_opt(struct mntent *mntent) ...@@ -1997,8 +2044,7 @@ static void cull_mntent_opt(struct mntent *mntent)
static int mount_entry_create_dir_file(const struct mntent *mntent, static int mount_entry_create_dir_file(const struct mntent *mntent,
const char *path, const char *path,
const struct lxc_rootfs *rootfs, const struct lxc_rootfs *rootfs,
const char *lxc_name, const char *lxc_name, const char *lxc_path)
const char *lxc_path)
{ {
int fd, ret; int fd, ret;
char *p1, *p2; char *p1, *p2;
...@@ -2017,9 +2063,12 @@ static int mount_entry_create_dir_file(const struct mntent *mntent, ...@@ -2017,9 +2063,12 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
} }
} }
if (hasmntopt(mntent, "create=file") && access(path, F_OK)) { if (!hasmntopt(mntent, "create=file"))
int fd; return 0;
char *p1, *p2;
ret = access(path, F_OK);
if (ret == 0)
return 0;
p1 = strdup(path); p1 = strdup(path);
if (!p1) if (!p1)
...@@ -2038,7 +2087,6 @@ static int mount_entry_create_dir_file(const struct mntent *mntent, ...@@ -2038,7 +2087,6 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
if (fd < 0) if (fd < 0)
return -1; return -1;
close(fd); close(fd);
}
return 0; return 0;
} }
...@@ -2156,98 +2204,26 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent, ...@@ -2156,98 +2204,26 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent,
const char *lxc_name, const char *lxc_name,
const char *lxc_path) const char *lxc_path)
{ {
char path[MAXPATHLEN];
int ret; int ret;
char path[MAXPATHLEN];
/* relative to root mount point */ /* relative to root mount point */
ret = snprintf(path, sizeof(path), "%s/%s", rootfs->mount, mntent->mnt_dir); ret = snprintf(path, sizeof(path), "%s/%s", rootfs->mount, mntent->mnt_dir);
if (ret < 0 || ret >= sizeof(path)) { if (ret < 0 || (size_t)ret >= sizeof(path))
ERROR("path name too long");
return -1; return -1;
}
return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path); return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path);
} }
/* This logs a NOTICE() when a user specifies mounts that would conflict with
* devices liblxc sets up automatically.
*/
static void log_notice_on_conflict(const struct lxc_conf *conf, const char *src,
const char *dest)
{
char *clean_mnt_fsname, *clean_mnt_dir, *tmp;
bool needs_warning = false;
clean_mnt_fsname = lxc_deslashify(src);
if (!clean_mnt_fsname)
return;
clean_mnt_dir = lxc_deslashify(dest);
if (!clean_mnt_dir) {
free(clean_mnt_fsname);
return;
}
tmp = clean_mnt_dir;
if (*tmp == '/')
tmp++;
if (strncmp(src, "/dev", 4) || strncmp(tmp, "dev", 3)) {
free(clean_mnt_dir);
free(clean_mnt_fsname);
return;
}
if (!conf->autodev && !conf->pts && !conf->tty &&
(!conf->console.path || !strcmp(conf->console.path, "none"))) {
free(clean_mnt_dir);
free(clean_mnt_fsname);
return;
}
if (!strcmp(tmp, "dev") && conf->autodev > 0)
needs_warning = true;
else if (!strcmp(tmp, "dev/pts") && (conf->autodev > 0 || conf->pts > 0))
needs_warning = true;
else if (!strcmp(tmp, "dev/ptmx") && (conf->autodev > 0 || conf->pts > 0))
needs_warning = true;
else if (!strcmp(tmp, "dev/pts/ptmx") && (conf->autodev > 0 || conf->pts > 0))
needs_warning = true;
else if (!strcmp(tmp, "dev/null") && conf->autodev > 0)
needs_warning = true;
else if (!strcmp(tmp, "dev/zero") && conf->autodev > 0)
needs_warning = true;
else if (!strcmp(tmp, "dev/full") && conf->autodev > 0)
needs_warning = true;
else if (!strcmp(tmp, "dev/urandom") && conf->autodev > 0)
needs_warning = true;
else if (!strcmp(tmp, "dev/random") && conf->autodev > 0)
needs_warning = true;
else if (!strcmp(tmp, "dev/tty") && conf->autodev > 0)
needs_warning = true;
else if (!strncmp(tmp, "dev/tty", 7) && (conf->autodev > 0 || conf->tty > 0))
needs_warning = true;
if (needs_warning)
NOTICE("Requesting to mount \"%s\" on \"%s\" while requesting "
"automatic device setup under \"/dev\"",
clean_mnt_fsname, clean_mnt_dir);
free(clean_mnt_dir);
free(clean_mnt_fsname);
}
static int mount_file_entries(const struct lxc_conf *conf, static int mount_file_entries(const struct lxc_conf *conf,
const struct lxc_rootfs *rootfs, FILE *file, const struct lxc_rootfs *rootfs, FILE *file,
const char *lxc_name, const char *lxc_path) const char *lxc_name, const char *lxc_path)
{ {
struct mntent mntent;
char buf[4096]; char buf[4096];
struct mntent mntent;
int ret = -1; int ret = -1;
while (getmntent_r(file, &mntent, buf, sizeof(buf))) { while (getmntent_r(file, &mntent, buf, sizeof(buf))) {
log_notice_on_conflict(conf, mntent.mnt_fsname, mntent.mnt_dir);
if (!rootfs->path) if (!rootfs->path)
ret = mount_entry_on_systemfs(&mntent); ret = mount_entry_on_systemfs(&mntent);
else if (mntent.mnt_dir[0] != '/') else if (mntent.mnt_dir[0] != '/')
...@@ -2261,7 +2237,7 @@ static int mount_file_entries(const struct lxc_conf *conf, ...@@ -2261,7 +2237,7 @@ static int mount_file_entries(const struct lxc_conf *conf,
} }
ret = 0; ret = 0;
INFO("Set up mount entries"); INFO("Finished setting up mounts");
return ret; return ret;
} }
...@@ -2294,42 +2270,50 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount) ...@@ -2294,42 +2270,50 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount)
int ret; int ret;
char *mount_entry; char *mount_entry;
struct lxc_list *iterator; struct lxc_list *iterator;
FILE *f;
int fd = -1; int fd = -1;
fd = memfd_create("lxc_mount_file", MFD_CLOEXEC); fd = memfd_create(".lxc_mount_file", MFD_CLOEXEC);
if (fd < 0) { if (fd < 0) {
if (errno != ENOSYS) if (errno != ENOSYS)
return NULL; return NULL;
f = tmpfile(); fd = lxc_make_tmpfile((char *){P_tmpdir "/.lxc_mount_file"}, true);
TRACE("Created temporary mount file"); if (fd < 0) {
} else { SYSERROR("Could not create temporary mount file");
f = fdopen(fd, "r+"); return NULL;
TRACE("Created anonymous mount file");
} }
if (!f) { TRACE("Created temporary mount file");
SYSERROR("Could not create mount file"); }
if (fd != -1) if (fd < 0) {
close(fd); SYSERROR("Could not create temporary mount file");
return NULL; return NULL;
} }
lxc_list_for_each(iterator, mount) { lxc_list_for_each (iterator, mount) {
size_t len;
mount_entry = iterator->elem; mount_entry = iterator->elem;
ret = fprintf(f, "%s\n", mount_entry); len = strlen(mount_entry);
if (ret < strlen(mount_entry))
WARN("Could not write mount entry to mount file");
}
ret = fseek(f, 0, SEEK_SET); ret = write(fd, mount_entry, len);
if (ret < 0) { if (ret != len)
SYSERROR("Failed to seek mount file"); goto on_error;
fclose(f);
return NULL; ret = write(fd, "\n", 1);
if (ret != 1)
goto on_error;
} }
return f; ret = lseek(fd, 0, SEEK_SET);
if (ret < 0)
goto on_error;
return fdopen(fd, "r+");
on_error:
SYSERROR("Failed to write mount entry to temporary mount file");
close(fd);
return NULL;
} }
static int setup_mount_entries(const struct lxc_conf *conf, static int setup_mount_entries(const struct lxc_conf *conf,
...@@ -2337,31 +2321,30 @@ static int setup_mount_entries(const struct lxc_conf *conf, ...@@ -2337,31 +2321,30 @@ static int setup_mount_entries(const struct lxc_conf *conf,
struct lxc_list *mount, const char *lxc_name, struct lxc_list *mount, const char *lxc_name,
const char *lxc_path) const char *lxc_path)
{ {
FILE *f;
int ret; int ret;
FILE *f;
f = make_anonymous_mount_file(mount); f = make_anonymous_mount_file(mount);
if (!f) if (!f)
return -1; return -1;
ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path); ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path);
fclose(f); fclose(f);
return ret; return ret;
} }
static int parse_cap(const char *cap) static int parse_cap(const char *cap)
{ {
char *ptr = NULL;
size_t i; size_t i;
int capid = -1; int capid = -1;
size_t end = sizeof(caps_opt)/sizeof(caps_opt[0]); size_t end = sizeof(caps_opt) / sizeof(caps_opt[0]);
char *ptr = NULL;
if (!strcmp(cap, "none")) if (strcmp(cap, "none") == 0)
return -2; return -2;
for (i = 0; i < end; i++) { for (i = 0; i < end; i++) {
if (strcmp(cap, caps_opt[i].name)) if (strcmp(cap, caps_opt[i].name))
continue; continue;
...@@ -2370,9 +2353,10 @@ static int parse_cap(const char *cap) ...@@ -2370,9 +2353,10 @@ static int parse_cap(const char *cap)
} }
if (capid < 0) { if (capid < 0) {
/* try to see if it's numeric, so the user may specify /* Try to see if it's numeric, so the user may specify
* capabilities that the running kernel knows about but * capabilities that the running kernel knows about but we
* we don't */ * don't
*/
errno = 0; errno = 0;
capid = strtol(cap, &ptr, 10); capid = strtol(cap, &ptr, 10);
if (!ptr || *ptr != '\0' || errno != 0) if (!ptr || *ptr != '\0' || errno != 0)
...@@ -2389,10 +2373,10 @@ static int parse_cap(const char *cap) ...@@ -2389,10 +2373,10 @@ static int parse_cap(const char *cap)
int in_caplist(int cap, struct lxc_list *caps) int in_caplist(int cap, struct lxc_list *caps)
{ {
struct lxc_list *iterator;
int capid; int capid;
struct lxc_list *iterator;
lxc_list_for_each(iterator, caps) { lxc_list_for_each (iterator, caps) {
capid = parse_cap(iterator->elem); capid = parse_cap(iterator->elem);
if (capid == cap) if (capid == cap)
return 1; return 1;
...@@ -2403,116 +2387,121 @@ int in_caplist(int cap, struct lxc_list *caps) ...@@ -2403,116 +2387,121 @@ int in_caplist(int cap, struct lxc_list *caps)
static int setup_caps(struct lxc_list *caps) static int setup_caps(struct lxc_list *caps)
{ {
struct lxc_list *iterator;
char *drop_entry;
int capid; int capid;
char *drop_entry;
struct lxc_list *iterator;
lxc_list_for_each(iterator, caps) { lxc_list_for_each (iterator, caps) {
int ret;
drop_entry = iterator->elem; drop_entry = iterator->elem;
capid = parse_cap(drop_entry); capid = parse_cap(drop_entry);
if (capid < 0) { if (capid < 0) {
ERROR("unknown capability %s", drop_entry); ERROR("unknown capability %s", drop_entry);
return -1; return -1;
} }
DEBUG("drop capability '%s' (%d)", drop_entry, capid); ret = prctl(PR_CAPBSET_DROP, capid, 0, 0, 0);
if (ret < 0) {
if (prctl(PR_CAPBSET_DROP, capid, 0, 0, 0)) { SYSERROR("Failed to remove %s capability", drop_entry);
SYSERROR("failed to remove %s capability", drop_entry);
return -1; return -1;
} }
DEBUG("Dropped %s (%d) capability", drop_entry, capid);
} }
DEBUG("capabilities have been setup"); DEBUG("Capabilities have been setup");
return 0; return 0;
} }
static int dropcaps_except(struct lxc_list *caps) static int dropcaps_except(struct lxc_list *caps)
{ {
struct lxc_list *iterator; int i, capid, numcaps;
char *keep_entry; char *keep_entry;
int i, capid; struct lxc_list *iterator;
int numcaps = lxc_caps_last_cap() + 1;
INFO("found %d capabilities", numcaps);
numcaps = lxc_caps_last_cap() + 1;
if (numcaps <= 0 || numcaps > 200) if (numcaps <= 0 || numcaps > 200)
return -1; return -1;
TRACE("Found %d capabilities", numcaps);
/* caplist[i] is 1 if we keep capability i */ /* caplist[i] is 1 if we keep capability i */
int *caplist = alloca(numcaps * sizeof(int)); int *caplist = alloca(numcaps * sizeof(int));
memset(caplist, 0, numcaps * sizeof(int)); memset(caplist, 0, numcaps * sizeof(int));
lxc_list_for_each(iterator, caps) { lxc_list_for_each (iterator, caps) {
keep_entry = iterator->elem; keep_entry = iterator->elem;
capid = parse_cap(keep_entry); capid = parse_cap(keep_entry);
if (capid == -2) if (capid == -2)
continue; continue;
if (capid < 0) { if (capid < 0) {
ERROR("unknown capability %s", keep_entry); ERROR("Unknown capability %s", keep_entry);
return -1; return -1;
} }
DEBUG("keep capability '%s' (%d)", keep_entry, capid); DEBUG("Keep capability %s (%d)", keep_entry, capid);
caplist[capid] = 1; caplist[capid] = 1;
} }
for (i=0; i<numcaps; i++) {
for (i = 0; i < numcaps; i++) {
int ret;
if (caplist[i]) if (caplist[i])
continue; continue;
if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0)) {
SYSERROR("failed to remove capability %d", i); ret = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
if (ret < 0) {
SYSERROR("Failed to remove capability %d", i);
return -1; return -1;
} }
} }
DEBUG("capabilities have been setup"); DEBUG("Capabilities have been setup");
return 0; return 0;
} }
static int parse_resource(const char *res) { static int parse_resource(const char *res)
{
int ret;
size_t i; size_t i;
int resid = -1; int resid = -1;
for (i = 0; i < sizeof(limit_opt)/sizeof(limit_opt[0]); ++i) { for (i = 0; i < sizeof(limit_opt) / sizeof(limit_opt[0]); ++i)
if (strcmp(res, limit_opt[i].name) == 0) if (strcmp(res, limit_opt[i].name) == 0)
return limit_opt[i].value; return limit_opt[i].value;
}
/* try to see if it's numeric, so the user may specify /* Try to see if it's numeric, so the user may specify
* resources that the running kernel knows about but * resources that the running kernel knows about but
* we don't */ * we don't.
if (lxc_safe_int(res, &resid) == 0) */
return resid; ret = lxc_safe_int(res, &resid);
if (ret < 0)
return -1; return -1;
return resid;
} }
int setup_resource_limits(struct lxc_list *limits, pid_t pid) { int setup_resource_limits(struct lxc_list *limits, pid_t pid)
{
int resid;
struct lxc_list *it; struct lxc_list *it;
struct lxc_limit *lim; struct lxc_limit *lim;
int resid;
lxc_list_for_each(it, limits) { lxc_list_for_each (it, limits) {
lim = it->elem; lim = it->elem;
resid = parse_resource(lim->resource); resid = parse_resource(lim->resource);
if (resid < 0) { if (resid < 0) {
ERROR("unknown resource %s", lim->resource); ERROR("Unknown resource %s", lim->resource);
return -1; return -1;
} }
#if HAVE_PRLIMIT || HAVE_PRLIMIT64 #if HAVE_PRLIMIT || HAVE_PRLIMIT64
if (prlimit(pid, resid, &lim->limit, NULL) != 0) { if (prlimit(pid, resid, &lim->limit, NULL) != 0) {
ERROR("failed to set limit %s: %s", lim->resource, strerror(errno)); ERROR("Failed to set limit %s: %s", lim->resource,
strerror(errno));
return -1; return -1;
} }
#else #else
...@@ -2520,6 +2509,7 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) { ...@@ -2520,6 +2509,7 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
return -1; return -1;
#endif #endif
} }
return 0; return 0;
} }
...@@ -2527,11 +2517,11 @@ int setup_sysctl_parameters(struct lxc_list *sysctls) ...@@ -2527,11 +2517,11 @@ int setup_sysctl_parameters(struct lxc_list *sysctls)
{ {
struct lxc_list *it; struct lxc_list *it;
struct lxc_sysctl *elem; struct lxc_sysctl *elem;
int ret = 0;
char *tmp = NULL; char *tmp = NULL;
char filename[MAXPATHLEN] = {0}; char filename[MAXPATHLEN] = {0};
int ret = 0;
lxc_list_for_each(it, sysctls) { lxc_list_for_each (it, sysctls) {
elem = it->elem; elem = it->elem;
tmp = lxc_string_replace(".", "/", elem->key); tmp = lxc_string_replace(".", "/", elem->key);
if (!tmp) { if (!tmp) {
...@@ -2546,12 +2536,15 @@ int setup_sysctl_parameters(struct lxc_list *sysctls) ...@@ -2546,12 +2536,15 @@ int setup_sysctl_parameters(struct lxc_list *sysctls)
return -1; return -1;
} }
ret = lxc_write_to_file(filename, elem->value, strlen(elem->value), false); ret = lxc_write_to_file(filename, elem->value,
strlen(elem->value), false);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to setup sysctl parameters %s to %s", elem->key, elem->value); ERROR("Failed to setup sysctl parameters %s to %s",
elem->key, elem->value);
return -1; return -1;
} }
} }
return 0; return 0;
} }
...@@ -2559,11 +2552,11 @@ int setup_proc_filesystem(struct lxc_list *procs, pid_t pid) ...@@ -2559,11 +2552,11 @@ int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
{ {
struct lxc_list *it; struct lxc_list *it;
struct lxc_proc *elem; struct lxc_proc *elem;
int ret = 0;
char *tmp = NULL; char *tmp = NULL;
char filename[MAXPATHLEN] = {0}; char filename[MAXPATHLEN] = {0};
int ret = 0;
lxc_list_for_each(it, procs) { lxc_list_for_each (it, procs) {
elem = it->elem; elem = it->elem;
tmp = lxc_string_replace(".", "/", elem->filename); tmp = lxc_string_replace(".", "/", elem->filename);
if (!tmp) { if (!tmp) {
...@@ -2578,12 +2571,15 @@ int setup_proc_filesystem(struct lxc_list *procs, pid_t pid) ...@@ -2578,12 +2571,15 @@ int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
return -1; return -1;
} }
ret = lxc_write_to_file(filename, elem->value, strlen(elem->value), false); ret = lxc_write_to_file(filename, elem->value,
strlen(elem->value), false);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to setup proc filesystem %s to %s", elem->filename, elem->value); ERROR("Failed to setup proc filesystem %s to %s",
elem->filename, elem->value);
return -1; return -1;
} }
} }
return 0; return 0;
} }
...@@ -2591,14 +2587,12 @@ static char *default_rootfs_mount = LXCROOTFSMOUNT; ...@@ -2591,14 +2587,12 @@ static char *default_rootfs_mount = LXCROOTFSMOUNT;
struct lxc_conf *lxc_conf_init(void) struct lxc_conf *lxc_conf_init(void)
{ {
struct lxc_conf *new;
int i; int i;
struct lxc_conf *new;
new = malloc(sizeof(*new)); new = malloc(sizeof(*new));
if (!new) { if (!new)
ERROR("lxc_conf_init : %s", strerror(errno));
return NULL; return NULL;
}
memset(new, 0, sizeof(*new)); memset(new, 0, sizeof(*new));
new->loglevel = LXC_LOG_LEVEL_NOTSET; new->loglevel = LXC_LOG_LEVEL_NOTSET;
...@@ -2621,7 +2615,6 @@ struct lxc_conf *lxc_conf_init(void) ...@@ -2621,7 +2615,6 @@ struct lxc_conf *lxc_conf_init(void)
new->nbd_idx = -1; new->nbd_idx = -1;
new->rootfs.mount = strdup(default_rootfs_mount); new->rootfs.mount = strdup(default_rootfs_mount);
if (!new->rootfs.mount) { if (!new->rootfs.mount) {
ERROR("lxc_conf_init : %s", strerror(errno));
free(new); free(new);
return NULL; return NULL;
} }
...@@ -2663,17 +2656,15 @@ struct lxc_conf *lxc_conf_init(void) ...@@ -2663,17 +2656,15 @@ struct lxc_conf *lxc_conf_init(void)
int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
size_t buf_size) size_t buf_size)
{ {
char path[MAXPATHLEN];
int fd, ret; int fd, ret;
char path[MAXPATHLEN];
if (geteuid() != 0 && idtype == ID_TYPE_GID) { if (geteuid() != 0 && idtype == ID_TYPE_GID) {
size_t buflen; size_t buflen;
ret = snprintf(path, MAXPATHLEN, "/proc/%d/setgroups", pid); ret = snprintf(path, MAXPATHLEN, "/proc/%d/setgroups", pid);
if (ret < 0 || ret >= MAXPATHLEN) { if (ret < 0 || ret >= MAXPATHLEN)
ERROR("Failed to create string");
return -E2BIG; return -E2BIG;
}
fd = open(path, O_WRONLY); fd = open(path, O_WRONLY);
if (fd < 0 && errno != ENOENT) { if (fd < 0 && errno != ENOENT) {
...@@ -2686,7 +2677,8 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, ...@@ -2686,7 +2677,8 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
errno = 0; errno = 0;
ret = lxc_write_nointr(fd, "deny\n", buflen); ret = lxc_write_nointr(fd, "deny\n", buflen);
if (ret != buflen) { if (ret != buflen) {
SYSERROR("Failed to write \"deny\" to \"/proc/%d/setgroups\"", pid); SYSERROR("Failed to write \"deny\" to "
"\"/proc/%d/setgroups\"", pid);
close(fd); close(fd);
return -1; return -1;
} }
...@@ -2696,10 +2688,8 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, ...@@ -2696,10 +2688,8 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
ret = snprintf(path, MAXPATHLEN, "/proc/%d/%cid_map", pid, ret = snprintf(path, MAXPATHLEN, "/proc/%d/%cid_map", pid,
idtype == ID_TYPE_UID ? 'u' : 'g'); idtype == ID_TYPE_UID ? 'u' : 'g');
if (ret < 0 || ret >= MAXPATHLEN) { if (ret < 0 || ret >= MAXPATHLEN)
ERROR("Failed to create string");
return -E2BIG; return -E2BIG;
}
fd = open(path, O_WRONLY); fd = open(path, O_WRONLY);
if (fd < 0) { if (fd < 0) {
...@@ -2726,7 +2716,6 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, ...@@ -2726,7 +2716,6 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
* @return 0 if binary exists but is lacking privilege * @return 0 if binary exists but is lacking privilege
* @return -ENOENT if binary does not exist * @return -ENOENT if binary does not exist
* @return -EINVAL if cap to check is neither CAP_SETUID nor CAP_SETGID * @return -EINVAL if cap to check is neither CAP_SETUID nor CAP_SETGID
*
*/ */
static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap) static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
{ {
...@@ -2750,18 +2739,18 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap) ...@@ -2750,18 +2739,18 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
/* Check if the binary is setuid. */ /* Check if the binary is setuid. */
if (st.st_mode & S_ISUID) { if (st.st_mode & S_ISUID) {
DEBUG("The binary \"%s\" does have the setuid bit set.", path); DEBUG("The binary \"%s\" does have the setuid bit set", path);
fret = 1; fret = 1;
goto cleanup; goto cleanup;
} }
#if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES #if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES
/* Check if it has the CAP_SETUID capability. */ /* Check if it has the CAP_SETUID capability. */
if ((cap & CAP_SETUID) && if ((cap & CAP_SETUID) &&
lxc_file_cap_is_set(path, CAP_SETUID, CAP_EFFECTIVE) && lxc_file_cap_is_set(path, CAP_SETUID, CAP_EFFECTIVE) &&
lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED)) { lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED)) {
DEBUG("The binary \"%s\" has CAP_SETUID in its CAP_EFFECTIVE " DEBUG("The binary \"%s\" has CAP_SETUID in its CAP_EFFECTIVE "
"and CAP_PERMITTED sets.", path); "and CAP_PERMITTED sets", path);
fret = 1; fret = 1;
goto cleanup; goto cleanup;
} }
...@@ -2771,19 +2760,19 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap) ...@@ -2771,19 +2760,19 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
lxc_file_cap_is_set(path, CAP_SETGID, CAP_EFFECTIVE) && lxc_file_cap_is_set(path, CAP_SETGID, CAP_EFFECTIVE) &&
lxc_file_cap_is_set(path, CAP_SETGID, CAP_PERMITTED)) { lxc_file_cap_is_set(path, CAP_SETGID, CAP_PERMITTED)) {
DEBUG("The binary \"%s\" has CAP_SETGID in its CAP_EFFECTIVE " DEBUG("The binary \"%s\" has CAP_SETGID in its CAP_EFFECTIVE "
"and CAP_PERMITTED sets.", path); "and CAP_PERMITTED sets", path);
fret = 1; fret = 1;
goto cleanup; goto cleanup;
} }
#else #else
/* If we cannot check for file capabilities we need to give the benefit /* If we cannot check for file capabilities we need to give the benefit
* of the doubt. Otherwise we might fail even though all the necessary * of the doubt. Otherwise we might fail even though all the necessary
* file capabilities are set. * file capabilities are set.
*/ */
DEBUG("Cannot check for file capabilites as full capability support is " DEBUG("Cannot check for file capabilites as full capability support is "
"missing. Manual intervention needed."); "missing. Manual intervention needed");
fret = 1; fret = 1;
#endif #endif
cleanup: cleanup:
free(path); free(path);
...@@ -2798,13 +2787,13 @@ int lxc_map_ids_exec_wrapper(void *args) ...@@ -2798,13 +2787,13 @@ int lxc_map_ids_exec_wrapper(void *args)
int lxc_map_ids(struct lxc_list *idmap, pid_t pid) int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
{ {
struct id_map *map; int fill, left;
struct lxc_list *iterator;
enum idtype type;
char u_or_g; char u_or_g;
char *pos; char *pos;
int fill, left;
char cmd_output[MAXPATHLEN]; char cmd_output[MAXPATHLEN];
struct id_map *map;
struct lxc_list *iterator;
enum idtype type;
/* strlen("new@idmap") = 9 /* strlen("new@idmap") = 9
* + * +
* strlen(" ") = 1 * strlen(" ") = 1
...@@ -2816,9 +2805,9 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) ...@@ -2816,9 +2805,9 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
* We add some additional space to make sure that we really have * We add some additional space to make sure that we really have
* LXC_IDMAPLEN bytes available for our the {g,u]id mapping. * LXC_IDMAPLEN bytes available for our the {g,u]id mapping.
*/ */
int ret = 0, gidmap = 0, uidmap = 0;
char mapbuf[9 + 1 + LXC_NUMSTRLEN64 + 1 + LXC_IDMAPLEN] = {0}; char mapbuf[9 + 1 + LXC_NUMSTRLEN64 + 1 + LXC_IDMAPLEN] = {0};
int ret = 0, uidmap = 0, gidmap = 0; bool had_entry = false, use_shadow = false;
bool use_shadow = false, had_entry = false;
/* If new{g,u}idmap exists, that is, if shadow is handing out subuid /* If new{g,u}idmap exists, that is, if shadow is handing out subuid
* ranges, then insist that root also reserve ranges in subuid. This * ranges, then insist that root also reserve ranges in subuid. This
...@@ -2838,7 +2827,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) ...@@ -2838,7 +2827,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
WARN("newgidmap is lacking necessary privileges"); WARN("newgidmap is lacking necessary privileges");
if (uidmap > 0 && gidmap > 0) { if (uidmap > 0 && gidmap > 0) {
DEBUG("Functional newuidmap and newgidmap binary found."); DEBUG("Functional newuidmap and newgidmap binary found");
use_shadow = true; use_shadow = true;
} else { } else {
/* In case unprivileged users run application containers via /* In case unprivileged users run application containers via
...@@ -2847,7 +2836,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) ...@@ -2847,7 +2836,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
* doing so by requiring geteuid() == 0. * doing so by requiring geteuid() == 0.
*/ */
DEBUG("No newuidmap and newgidmap binary found. Trying to " DEBUG("No newuidmap and newgidmap binary found. Trying to "
"write directly with euid %d.", geteuid()); "write directly with euid %d", geteuid());
} }
for (type = ID_TYPE_UID, u_or_g = 'u'; type <= ID_TYPE_GID; for (type = ID_TYPE_UID, u_or_g = 'u'; type <= ID_TYPE_GID;
...@@ -2910,24 +2899,22 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) ...@@ -2910,24 +2899,22 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
return 0; return 0;
} }
/* /* Return the host uid/gid to which the container root is mapped in val.
* return the host uid/gid to which the container root is mapped in
* *val.
* Return true if id was found, false otherwise. * Return true if id was found, false otherwise.
*/ */
bool get_mapped_rootid(struct lxc_conf *conf, enum idtype idtype, bool get_mapped_rootid(struct lxc_conf *conf, enum idtype idtype,
unsigned long *val) unsigned long *val)
{ {
struct lxc_list *it;
struct id_map *map;
unsigned nsid; unsigned nsid;
struct id_map *map;
struct lxc_list *it;
if (idtype == ID_TYPE_UID) if (idtype == ID_TYPE_UID)
nsid = (conf->root_nsuid_map != NULL) ? 0 : conf->init_uid; nsid = (conf->root_nsuid_map != NULL) ? 0 : conf->init_uid;
else else
nsid = (conf->root_nsgid_map != NULL) ? 0 : conf->init_gid; nsid = (conf->root_nsgid_map != NULL) ? 0 : conf->init_gid;
lxc_list_for_each(it, &conf->id_map) { lxc_list_for_each (it, &conf->id_map) {
map = it->elem; map = it->elem;
if (map->idtype != idtype) if (map->idtype != idtype)
continue; continue;
...@@ -2942,33 +2929,39 @@ bool get_mapped_rootid(struct lxc_conf *conf, enum idtype idtype, ...@@ -2942,33 +2929,39 @@ bool get_mapped_rootid(struct lxc_conf *conf, enum idtype idtype,
int mapped_hostid(unsigned id, struct lxc_conf *conf, enum idtype idtype) int mapped_hostid(unsigned id, struct lxc_conf *conf, enum idtype idtype)
{ {
struct lxc_list *it;
struct id_map *map; struct id_map *map;
lxc_list_for_each(it, &conf->id_map) { struct lxc_list *it;
lxc_list_for_each (it, &conf->id_map) {
map = it->elem; map = it->elem;
if (map->idtype != idtype) if (map->idtype != idtype)
continue; continue;
if (id >= map->hostid && id < map->hostid + map->range) if (id >= map->hostid && id < map->hostid + map->range)
return (id - map->hostid) + map->nsid; return (id - map->hostid) + map->nsid;
} }
return -1; return -1;
} }
int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype) int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype)
{ {
struct lxc_list *it;
struct id_map *map; struct id_map *map;
struct lxc_list *it;
unsigned int freeid = 0; unsigned int freeid = 0;
again: again:
lxc_list_for_each(it, &conf->id_map) { lxc_list_for_each (it, &conf->id_map) {
map = it->elem; map = it->elem;
if (map->idtype != idtype) if (map->idtype != idtype)
continue; continue;
if (freeid >= map->nsid && freeid < map->nsid + map->range) { if (freeid >= map->nsid && freeid < map->nsid + map->range) {
freeid = map->nsid + map->range; freeid = map->nsid + map->range;
goto again; goto again;
} }
} }
return freeid; return freeid;
} }
...@@ -2978,8 +2971,7 @@ int chown_mapped_root_exec_wrapper(void *args) ...@@ -2978,8 +2971,7 @@ int chown_mapped_root_exec_wrapper(void *args)
return -1; return -1;
} }
/* /* chown_mapped_root: for an unprivileged user with uid/gid X to
* chown_mapped_root: for an unprivileged user with uid/gid X to
* chown a dir to subuid/subgid Y, he needs to run chown as root * chown a dir to subuid/subgid Y, he needs to run chown as root
* in a userns where nsid 0 is mapped to hostuid/hostgid Y, and * in a userns where nsid 0 is mapped to hostuid/hostgid Y, and
* nsid Y is mapped to hostuid/hostgid X. That way, the container * nsid Y is mapped to hostuid/hostgid X. That way, the container
...@@ -3019,6 +3011,7 @@ int chown_mapped_root(const char *path, struct lxc_conf *conf) ...@@ -3019,6 +3011,7 @@ int chown_mapped_root(const char *path, struct lxc_conf *conf)
return -1; return -1;
} }
rootuid = (uid_t)val; rootuid = (uid_t)val;
if (!get_mapped_rootid(conf, ID_TYPE_GID, &val)) { if (!get_mapped_rootid(conf, ID_TYPE_GID, &val)) {
ERROR("No gid mapping for container root"); ERROR("No gid mapping for container root");
return -1; return -1;
...@@ -3030,6 +3023,7 @@ int chown_mapped_root(const char *path, struct lxc_conf *conf) ...@@ -3030,6 +3023,7 @@ int chown_mapped_root(const char *path, struct lxc_conf *conf)
ERROR("Error chowning %s", path); ERROR("Error chowning %s", path);
return -1; return -1;
} }
return 0; return 0;
} }
...@@ -3125,7 +3119,7 @@ int lxc_create_tmp_proc_mount(struct lxc_conf *conf) ...@@ -3125,7 +3119,7 @@ int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
mounted = lxc_mount_proc_if_needed(conf->rootfs.path ? conf->rootfs.mount : ""); mounted = lxc_mount_proc_if_needed(conf->rootfs.path ? conf->rootfs.mount : "");
if (mounted == -1) { if (mounted == -1) {
SYSERROR("failed to mount /proc in the container"); SYSERROR("Failed to mount proc in the container");
/* continue only if there is no rootfs */ /* continue only if there is no rootfs */
if (conf->rootfs.path) if (conf->rootfs.path)
return -1; return -1;
...@@ -3138,39 +3132,47 @@ int lxc_create_tmp_proc_mount(struct lxc_conf *conf) ...@@ -3138,39 +3132,47 @@ int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
void tmp_proc_unmount(struct lxc_conf *lxc_conf) void tmp_proc_unmount(struct lxc_conf *lxc_conf)
{ {
if (lxc_conf->tmp_umount_proc == 1) { if (lxc_conf->tmp_umount_proc != 1)
return;
umount("/proc"); umount("/proc");
lxc_conf->tmp_umount_proc = 0; lxc_conf->tmp_umount_proc = 0;
}
} }
/* Walk /proc/mounts and change any shared entries to slave. */
void remount_all_slave(void) void remount_all_slave(void)
{ {
/* walk /proc/mounts and change any shared entries to slave */ FILE *f;
FILE *f = fopen("/proc/self/mountinfo", "r");
char *line = NULL;
size_t len = 0; size_t len = 0;
char *line = NULL;
f = fopen("/proc/self/mountinfo", "r");
if (!f) { if (!f) {
SYSERROR("Failed to open /proc/self/mountinfo to mark all shared"); SYSERROR("Failed to open \"/proc/self/mountinfo\" to mark all shared");
ERROR("Continuing container startup..."); ERROR("Continuing container startup...");
return; return;
} }
while (getline(&line, &len, f) != -1) { while (getline(&line, &len, f) != -1) {
char *target, *opts; int ret;
char *opts, *target;
target = get_field(line, 4); target = get_field(line, 4);
if (!target) if (!target)
continue; continue;
opts = get_field(target, 2); opts = get_field(target, 2);
if (!opts) if (!opts)
continue; continue;
null_endofword(opts); null_endofword(opts);
if (!strstr(opts, "shared")) if (!strstr(opts, "shared"))
continue; continue;
null_endofword(target); null_endofword(target);
if (mount(NULL, target, NULL, MS_SLAVE, NULL)) { ret = mount(NULL, target, NULL, MS_SLAVE, NULL);
SYSERROR("Failed to make %s rslave", target); if (ret < 0) {
SYSERROR("Failed to make \"%s\" MS_SLAVE", target);
ERROR("Continuing..."); ERROR("Continuing...");
} }
} }
...@@ -3191,24 +3193,22 @@ static int lxc_execute_bind_init(struct lxc_conf *conf) ...@@ -3191,24 +3193,22 @@ static int lxc_execute_bind_init(struct lxc_conf *conf)
} }
ret = snprintf(path, PATH_MAX, SBINDIR "/init.lxc.static"); ret = snprintf(path, PATH_MAX, SBINDIR "/init.lxc.static");
if (ret < 0 || ret >= PATH_MAX) { if (ret < 0 || ret >= PATH_MAX)
ERROR("Path name too long searching for lxc.init.static");
return -1; return -1;
}
if (!file_exists(path)) { if (!file_exists(path)) {
ERROR("%s does not exist on host", path); ERROR("The file \"%s\" does not exist on host", path);
return -1; return -1;
} }
ret = snprintf(destpath, PATH_MAX, "%s%s", conf->rootfs.mount, "/init.lxc.static"); ret = snprintf(destpath, PATH_MAX, "%s%s", conf->rootfs.mount, "/init.lxc.static");
if (ret < 0 || ret >= PATH_MAX) { if (ret < 0 || ret >= PATH_MAX)
ERROR("Path name too long for container's lxc.init.static");
return -1; return -1;
}
if (!file_exists(destpath)) { if (!file_exists(destpath)) {
FILE *pathfile = fopen(destpath, "wb"); FILE *pathfile;
pathfile = fopen(destpath, "wb");
if (!pathfile) { if (!pathfile) {
SYSERROR("Failed to create mount target \"%s\"", destpath); SYSERROR("Failed to create mount target \"%s\"", destpath);
return -1; return -1;
...@@ -3219,7 +3219,7 @@ static int lxc_execute_bind_init(struct lxc_conf *conf) ...@@ -3219,7 +3219,7 @@ static int lxc_execute_bind_init(struct lxc_conf *conf)
ret = safe_mount(path, destpath, "none", MS_BIND, NULL, conf->rootfs.mount); ret = safe_mount(path, destpath, "none", MS_BIND, NULL, conf->rootfs.mount);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to bind lxc.init.static into container"); SYSERROR("Failed to bind mount lxc.init.static into container");
return -1; return -1;
} }
...@@ -3227,34 +3227,40 @@ static int lxc_execute_bind_init(struct lxc_conf *conf) ...@@ -3227,34 +3227,40 @@ static int lxc_execute_bind_init(struct lxc_conf *conf)
return 0; return 0;
} }
/* /* This does the work of remounting / if it is shared, calling the container
* This does the work of remounting / if it is shared, calling the * pre-mount hooks, and mounting the rootfs.
* container pre-mount hooks, and mounting the rootfs.
*/ */
int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath) int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath)
{ {
int ret;
if (conf->rootfs_setup) { if (conf->rootfs_setup) {
/*
* rootfs was set up in another namespace. bind-mount it
* to give us a mount in our own ns so we can pivot_root to it
*/
const char *path = conf->rootfs.mount; const char *path = conf->rootfs.mount;
if (mount(path, path, "rootfs", MS_BIND, NULL) < 0) {
ERROR("Failed to bind-mount container / onto itself"); /* The rootfs was set up in another namespace. bind-mount it to
* give us a mount in our own ns so we can pivot_root to it
*/
ret = mount(path, path, "rootfs", MS_BIND, NULL);
if (ret < 0) {
ERROR("Failed to bind mount container / onto itself");
return -1; return -1;
} }
TRACE("Bind mounted container / onto itself");
return 0; return 0;
} }
remount_all_slave(); remount_all_slave();
if (run_lxc_hooks(name, "pre-mount", conf, NULL)) { ret = run_lxc_hooks(name, "pre-mount", conf, NULL);
ERROR("failed to run pre-mount hooks for container '%s'.", name); if (ret < 0) {
ERROR("Failed to run pre-mount hooks");
return -1; return -1;
} }
if (lxc_setup_rootfs(conf)) { ret = lxc_setup_rootfs(conf);
ERROR("failed to setup rootfs for '%s'", name); if (ret < 0) {
ERROR("Failed to setup rootfs for");
return -1; return -1;
} }
...@@ -3264,23 +3270,27 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath ...@@ -3264,23 +3270,27 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath
static bool verify_start_hooks(struct lxc_conf *conf) static bool verify_start_hooks(struct lxc_conf *conf)
{ {
struct lxc_list *it;
char path[MAXPATHLEN]; char path[MAXPATHLEN];
lxc_list_for_each(it, &conf->hooks[LXCHOOK_START]) { struct lxc_list *it;
char *hookname = it->elem;
struct stat st; lxc_list_for_each (it, &conf->hooks[LXCHOOK_START]) {
int ret; int ret;
struct stat st;
char *hookname = it->elem;
ret = snprintf(path, MAXPATHLEN, "%s%s", ret = snprintf(path, MAXPATHLEN, "%s%s",
conf->rootfs.path ? conf->rootfs.mount : "", hookname); conf->rootfs.path ? conf->rootfs.mount : "",
hookname);
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
return false; return false;
ret = stat(path, &st); ret = stat(path, &st);
if (ret) { if (ret < 0) {
SYSERROR("Start hook %s not found in container", SYSERROR("Start hook %s not found in container",
hookname); hookname);
return false; return false;
} }
return true; return true;
} }
...@@ -3290,9 +3300,8 @@ static bool verify_start_hooks(struct lxc_conf *conf) ...@@ -3290,9 +3300,8 @@ static bool verify_start_hooks(struct lxc_conf *conf)
int lxc_setup(struct lxc_handler *handler) int lxc_setup(struct lxc_handler *handler)
{ {
int ret; int ret;
const char *name = handler->name; const char *lxcpath = handler->lxcpath, *name = handler->name;
struct lxc_conf *lxc_conf = handler->conf; struct lxc_conf *lxc_conf = handler->conf;
const char *lxcpath = handler->lxcpath;
ret = do_rootfs_setup(lxc_conf, name, lxcpath); ret = do_rootfs_setup(lxc_conf, name, lxcpath);
if (ret < 0) { if (ret < 0) {
...@@ -3303,7 +3312,7 @@ int lxc_setup(struct lxc_handler *handler) ...@@ -3303,7 +3312,7 @@ int lxc_setup(struct lxc_handler *handler)
if (handler->nsfd[LXC_NS_UTS] == -1) { if (handler->nsfd[LXC_NS_UTS] == -1) {
ret = setup_utsname(lxc_conf->utsname); ret = setup_utsname(lxc_conf->utsname);
if (ret < 0) { if (ret < 0) {
ERROR("failed to setup the utsname for '%s'", name); ERROR("Failed to setup the utsname %s", name);
return -1; return -1;
} }
} }
...@@ -3498,7 +3507,7 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf, ...@@ -3498,7 +3507,7 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
else else
return -1; return -1;
lxc_list_for_each(it, &conf->hooks[which]) { lxc_list_for_each (it, &conf->hooks[which]) {
int ret; int ret;
char *hook = it->elem; char *hook = it->elem;
...@@ -3515,11 +3524,12 @@ int lxc_clear_config_caps(struct lxc_conf *c) ...@@ -3515,11 +3524,12 @@ int lxc_clear_config_caps(struct lxc_conf *c)
{ {
struct lxc_list *it, *next; struct lxc_list *it, *next;
lxc_list_for_each_safe(it, &c->caps, next) { lxc_list_for_each_safe (it, &c->caps, next) {
lxc_list_del(it); lxc_list_del(it);
free(it->elem); free(it->elem);
free(it); free(it);
} }
return 0; return 0;
} }
...@@ -3527,7 +3537,7 @@ static int lxc_free_idmap(struct lxc_list *id_map) ...@@ -3527,7 +3537,7 @@ static int lxc_free_idmap(struct lxc_list *id_map)
{ {
struct lxc_list *it, *next; struct lxc_list *it, *next;
lxc_list_for_each_safe(it, id_map, next) { lxc_list_for_each_safe (it, id_map, next) {
lxc_list_del(it); lxc_list_del(it);
free(it->elem); free(it->elem);
free(it); free(it);
...@@ -3543,13 +3553,14 @@ int lxc_clear_idmaps(struct lxc_conf *c) ...@@ -3543,13 +3553,14 @@ int lxc_clear_idmaps(struct lxc_conf *c)
int lxc_clear_config_keepcaps(struct lxc_conf *c) int lxc_clear_config_keepcaps(struct lxc_conf *c)
{ {
struct lxc_list *it,*next; struct lxc_list *it, *next;
lxc_list_for_each_safe(it, &c->keepcaps, next) { lxc_list_for_each_safe (it, &c->keepcaps, next) {
lxc_list_del(it); lxc_list_del(it);
free(it->elem); free(it->elem);
free(it); free(it);
} }
return 0; return 0;
} }
...@@ -3564,12 +3575,12 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version) ...@@ -3564,12 +3575,12 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
if (version == CGROUP2_SUPER_MAGIC) { if (version == CGROUP2_SUPER_MAGIC) {
global_token = "lxc.cgroup2"; global_token = "lxc.cgroup2";
namespaced_token = "lxc.cgroup2."; namespaced_token = "lxc.cgroup2.";
namespaced_token_len = sizeof("lxc.cgroup2.") - 1;; namespaced_token_len = sizeof("lxc.cgroup2.") - 1;
list = &c->cgroup2; list = &c->cgroup2;
} else if (version == CGROUP_SUPER_MAGIC) { } else if (version == CGROUP_SUPER_MAGIC) {
global_token = "lxc.cgroup"; global_token = "lxc.cgroup";
namespaced_token = "lxc.cgroup."; namespaced_token = "lxc.cgroup.";
namespaced_token_len = sizeof("lxc.cgroup.") - 1;; namespaced_token_len = sizeof("lxc.cgroup.") - 1;
list = &c->cgroup; list = &c->cgroup;
} else { } else {
return -EINVAL; return -EINVAL;
...@@ -3582,7 +3593,7 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version) ...@@ -3582,7 +3593,7 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
else else
return -EINVAL; return -EINVAL;
lxc_list_for_each_safe(it, list, next) { lxc_list_for_each_safe (it, list, next) {
struct lxc_cgroup *cg = it->elem; struct lxc_cgroup *cg = it->elem;
if (!all && strcmp(cg->subsystem, k) != 0) if (!all && strcmp(cg->subsystem, k) != 0)
...@@ -3601,8 +3612,8 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version) ...@@ -3601,8 +3612,8 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
int lxc_clear_limits(struct lxc_conf *c, const char *key) int lxc_clear_limits(struct lxc_conf *c, const char *key)
{ {
struct lxc_list *it, *next; struct lxc_list *it, *next;
bool all = false;
const char *k = NULL; const char *k = NULL;
bool all = false;
if (strcmp(key, "lxc.limit") == 0 || strcmp(key, "lxc.prlimit") == 0) if (strcmp(key, "lxc.limit") == 0 || strcmp(key, "lxc.prlimit") == 0)
all = true; all = true;
...@@ -3613,10 +3624,12 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key) ...@@ -3613,10 +3624,12 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key)
else else
return -1; return -1;
lxc_list_for_each_safe(it, &c->limits, next) { lxc_list_for_each_safe (it, &c->limits, next) {
struct lxc_limit *lim = it->elem; struct lxc_limit *lim = it->elem;
if (!all && strcmp(lim->resource, k) != 0) if (!all && strcmp(lim->resource, k) != 0)
continue; continue;
lxc_list_del(it); lxc_list_del(it);
free(lim->resource); free(lim->resource);
free(lim); free(lim);
...@@ -3629,8 +3642,8 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key) ...@@ -3629,8 +3642,8 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key)
int lxc_clear_sysctls(struct lxc_conf *c, const char *key) int lxc_clear_sysctls(struct lxc_conf *c, const char *key)
{ {
struct lxc_list *it, *next; struct lxc_list *it, *next;
bool all = false;
const char *k = NULL; const char *k = NULL;
bool all = false;
if (strcmp(key, "lxc.sysctl") == 0) if (strcmp(key, "lxc.sysctl") == 0)
all = true; all = true;
...@@ -3639,24 +3652,27 @@ int lxc_clear_sysctls(struct lxc_conf *c, const char *key) ...@@ -3639,24 +3652,27 @@ int lxc_clear_sysctls(struct lxc_conf *c, const char *key)
else else
return -1; return -1;
lxc_list_for_each_safe(it, &c->sysctls, next) { lxc_list_for_each_safe (it, &c->sysctls, next) {
struct lxc_sysctl *elem = it->elem; struct lxc_sysctl *elem = it->elem;
if (!all && strcmp(elem->key, k) != 0) if (!all && strcmp(elem->key, k) != 0)
continue; continue;
lxc_list_del(it); lxc_list_del(it);
free(elem->key); free(elem->key);
free(elem->value); free(elem->value);
free(elem); free(elem);
free(it); free(it);
} }
return 0; return 0;
} }
int lxc_clear_procs(struct lxc_conf *c, const char *key) int lxc_clear_procs(struct lxc_conf *c, const char *key)
{ {
struct lxc_list *it,*next; struct lxc_list *it, *next;
bool all = false;
const char *k = NULL; const char *k = NULL;
bool all = false;
if (strcmp(key, "lxc.proc") == 0) if (strcmp(key, "lxc.proc") == 0)
all = true; all = true;
...@@ -3665,10 +3681,12 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key) ...@@ -3665,10 +3681,12 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key)
else else
return -1; return -1;
lxc_list_for_each_safe(it, &c->procs, next) { lxc_list_for_each_safe (it, &c->procs, next) {
struct lxc_proc *proc = it->elem; struct lxc_proc *proc = it->elem;
if (!all && strcmp(proc->filename, k) != 0) if (!all && strcmp(proc->filename, k) != 0)
continue; continue;
lxc_list_del(it); lxc_list_del(it);
free(proc->filename); free(proc->filename);
free(proc->value); free(proc->value);
...@@ -3681,37 +3699,40 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key) ...@@ -3681,37 +3699,40 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key)
int lxc_clear_groups(struct lxc_conf *c) int lxc_clear_groups(struct lxc_conf *c)
{ {
struct lxc_list *it,*next; struct lxc_list *it, *next;
lxc_list_for_each_safe(it, &c->groups, next) { lxc_list_for_each_safe (it, &c->groups, next) {
lxc_list_del(it); lxc_list_del(it);
free(it->elem); free(it->elem);
free(it); free(it);
} }
return 0; return 0;
} }
int lxc_clear_environment(struct lxc_conf *c) int lxc_clear_environment(struct lxc_conf *c)
{ {
struct lxc_list *it,*next; struct lxc_list *it, *next;
lxc_list_for_each_safe(it, &c->environment, next) { lxc_list_for_each_safe (it, &c->environment, next) {
lxc_list_del(it); lxc_list_del(it);
free(it->elem); free(it->elem);
free(it); free(it);
} }
return 0; return 0;
} }
int lxc_clear_mount_entries(struct lxc_conf *c) int lxc_clear_mount_entries(struct lxc_conf *c)
{ {
struct lxc_list *it,*next; struct lxc_list *it, *next;
lxc_list_for_each_safe(it, &c->mount_list, next) { lxc_list_for_each_safe (it, &c->mount_list, next) {
lxc_list_del(it); lxc_list_del(it);
free(it->elem); free(it->elem);
free(it); free(it);
} }
return 0; return 0;
} }
...@@ -3723,25 +3744,26 @@ int lxc_clear_automounts(struct lxc_conf *c) ...@@ -3723,25 +3744,26 @@ int lxc_clear_automounts(struct lxc_conf *c)
int lxc_clear_hooks(struct lxc_conf *c, const char *key) int lxc_clear_hooks(struct lxc_conf *c, const char *key)
{ {
struct lxc_list *it,*next;
bool all = false, done = false;
const char *k = NULL;
int i; int i;
struct lxc_list *it, *next;
const char *k = NULL;
bool all = false, done = false;
if (strcmp(key, "lxc.hook") == 0) if (strcmp(key, "lxc.hook") == 0)
all = true; all = true;
else if (strncmp(key, "lxc.hook.", sizeof("lxc.hook.")-1) == 0) else if (strncmp(key, "lxc.hook.", sizeof("lxc.hook.") - 1) == 0)
k = key + sizeof("lxc.hook.")-1; k = key + sizeof("lxc.hook.") - 1;
else else
return -1; return -1;
for (i=0; i<NUM_LXC_HOOKS; i++) { for (i = 0; i < NUM_LXC_HOOKS; i++) {
if (all || strcmp(k, lxchook_names[i]) == 0) { if (all || strcmp(k, lxchook_names[i]) == 0) {
lxc_list_for_each_safe(it, &c->hooks[i], next) { lxc_list_for_each_safe (it, &c->hooks[i], next) {
lxc_list_del(it); lxc_list_del(it);
free(it->elem); free(it->elem);
free(it); free(it);
} }
done = true; done = true;
} }
} }
...@@ -3750,14 +3772,15 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key) ...@@ -3750,14 +3772,15 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
ERROR("Invalid hook key: %s", key); ERROR("Invalid hook key: %s", key);
return -1; return -1;
} }
return 0; return 0;
} }
static inline void lxc_clear_aliens(struct lxc_conf *conf) static inline void lxc_clear_aliens(struct lxc_conf *conf)
{ {
struct lxc_list *it,*next; struct lxc_list *it, *next;
lxc_list_for_each_safe(it, &conf->aliens, next) { lxc_list_for_each_safe (it, &conf->aliens, next) {
lxc_list_del(it); lxc_list_del(it);
free(it->elem); free(it->elem);
free(it); free(it);
...@@ -3766,9 +3789,9 @@ static inline void lxc_clear_aliens(struct lxc_conf *conf) ...@@ -3766,9 +3789,9 @@ static inline void lxc_clear_aliens(struct lxc_conf *conf)
void lxc_clear_includes(struct lxc_conf *conf) void lxc_clear_includes(struct lxc_conf *conf)
{ {
struct lxc_list *it,*next; struct lxc_list *it, *next;
lxc_list_for_each_safe(it, &conf->includes, next) { lxc_list_for_each_safe (it, &conf->includes, next) {
lxc_list_del(it); lxc_list_del(it);
free(it->elem); free(it->elem);
free(it); free(it);
...@@ -3779,6 +3802,7 @@ void lxc_conf_free(struct lxc_conf *conf) ...@@ -3779,6 +3802,7 @@ void lxc_conf_free(struct lxc_conf *conf)
{ {
if (!conf) if (!conf)
return; return;
if (current_config == conf) if (current_config == conf)
current_config = NULL; current_config = NULL;
lxc_terminal_conf_free(&conf->console); lxc_terminal_conf_free(&conf->console);
...@@ -3831,8 +3855,8 @@ struct userns_fn_data { ...@@ -3831,8 +3855,8 @@ struct userns_fn_data {
static int run_userns_fn(void *data) static int run_userns_fn(void *data)
{ {
struct userns_fn_data *d = data;
char c; char c;
struct userns_fn_data *d = data;
/* Close write end of the pipe. */ /* Close write end of the pipe. */
close(d->p[1]); close(d->p[1]);
...@@ -3848,6 +3872,7 @@ static int run_userns_fn(void *data) ...@@ -3848,6 +3872,7 @@ static int run_userns_fn(void *data)
if (d->fn_name) if (d->fn_name)
TRACE("calling function \"%s\"", d->fn_name); TRACE("calling function \"%s\"", d->fn_name);
/* Call function to run. */ /* Call function to run. */
return d->fn(d->arg); return d->fn(d->arg);
} }
...@@ -3872,11 +3897,11 @@ static struct id_map *mapped_nsid_add(struct lxc_conf *conf, unsigned id, ...@@ -3872,11 +3897,11 @@ static struct id_map *mapped_nsid_add(struct lxc_conf *conf, unsigned id,
static struct id_map *find_mapped_hostid_entry(struct lxc_conf *conf, static struct id_map *find_mapped_hostid_entry(struct lxc_conf *conf,
unsigned id, enum idtype idtype) unsigned id, enum idtype idtype)
{ {
struct lxc_list *it;
struct id_map *map; struct id_map *map;
struct lxc_list *it;
struct id_map *retmap = NULL; struct id_map *retmap = NULL;
lxc_list_for_each(it, &conf->id_map) { lxc_list_for_each (it, &conf->id_map) {
map = it->elem; map = it->elem;
if (map->idtype != idtype) if (map->idtype != idtype)
continue; continue;
...@@ -3890,11 +3915,11 @@ static struct id_map *find_mapped_hostid_entry(struct lxc_conf *conf, ...@@ -3890,11 +3915,11 @@ static struct id_map *find_mapped_hostid_entry(struct lxc_conf *conf,
return retmap; return retmap;
} }
/* /* Allocate a new {g,u}id mapping for the given {g,u}id. Re-use an already
* Allocate a new {g,u}id mapping for the given {g,u}id. Re-use an already
* existing one or establish a new one. * existing one or establish a new one.
*/ */
static struct id_map *mapped_hostid_add(struct lxc_conf *conf, uid_t id, enum idtype type) static struct id_map *mapped_hostid_add(struct lxc_conf *conf, uid_t id,
enum idtype type)
{ {
int hostid_mapped; int hostid_mapped;
struct id_map *entry = NULL, *tmp = NULL; struct id_map *entry = NULL, *tmp = NULL;
...@@ -4052,11 +4077,11 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data, ...@@ -4052,11 +4077,11 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
const char *fn_name) const char *fn_name)
{ {
pid_t pid; pid_t pid;
struct userns_fn_data d;
int p[2]; int p[2];
char c = '1'; struct userns_fn_data d;
int ret = -1, status = -1;
struct lxc_list *idmap; struct lxc_list *idmap;
int ret = -1, status = -1;
char c = '1';
idmap = get_minimal_idmap(conf); idmap = get_minimal_idmap(conf);
if (!idmap) if (!idmap)
...@@ -4076,7 +4101,7 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data, ...@@ -4076,7 +4101,7 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
/* Clone child in new user namespace. */ /* Clone child in new user namespace. */
pid = lxc_raw_clone_cb(run_userns_fn, &d, CLONE_NEWUSER); pid = lxc_raw_clone_cb(run_userns_fn, &d, CLONE_NEWUSER);
if (pid < 0) { if (pid < 0) {
ERROR("failed to clone child process in new user namespace"); ERROR("Failed to clone process in new user namespace");
goto on_error; goto on_error;
} }
...@@ -4085,23 +4110,23 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data, ...@@ -4085,23 +4110,23 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE || if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE ||
conf->loglevel == LXC_LOG_LEVEL_TRACE) { conf->loglevel == LXC_LOG_LEVEL_TRACE) {
struct lxc_list *it;
struct id_map *map; struct id_map *map;
struct lxc_list *it;
lxc_list_for_each(it, idmap) { lxc_list_for_each (it, idmap) {
map = it->elem; map = it->elem;
TRACE("Establishing %cid mapping for \"%d\" in new " TRACE("Establishing %cid mapping for \"%d\" in new "
"user namespace: nsuid %lu - hostid %lu - range " "user namespace: nsuid %lu - hostid %lu - range "
"%lu", (map->idtype == ID_TYPE_UID) ? 'u' : 'g', "%lu",
pid, map->nsid, map->hostid, map->range); (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid,
map->nsid, map->hostid, map->range);
} }
} }
/* Set up {g,u}id mapping for user namespace of child process. */ /* Set up {g,u}id mapping for user namespace of child process. */
ret = lxc_map_ids(idmap, pid); ret = lxc_map_ids(idmap, pid);
if (ret < 0) { if (ret < 0) {
ERROR("Error setting up {g,u}id mappings for child process " ERROR("Error setting up {g,u}id mappings for child process \"%d\"", pid);
"\"%d\"", pid);
goto on_error; goto on_error;
} }
...@@ -4131,12 +4156,12 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, ...@@ -4131,12 +4156,12 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
{ {
pid_t pid; pid_t pid;
uid_t euid, egid; uid_t euid, egid;
struct userns_fn_data d;
int p[2]; int p[2];
struct id_map *map; struct id_map *map;
struct lxc_list *cur; struct lxc_list *cur;
char c = '1'; struct userns_fn_data d;
int ret = -1; int ret = -1;
char c = '1';
struct lxc_list *idmap = NULL, *tmplist = NULL; struct lxc_list *idmap = NULL, *tmplist = NULL;
struct id_map *container_root_uid = NULL, *container_root_gid = NULL, struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
*host_uid_map = NULL, *host_gid_map = NULL; *host_uid_map = NULL, *host_gid_map = NULL;
...@@ -4155,7 +4180,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, ...@@ -4155,7 +4180,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
/* Clone child in new user namespace. */ /* Clone child in new user namespace. */
pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER); pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER);
if (pid < 0) { if (pid < 0) {
ERROR("failed to clone child process in new user namespace"); ERROR("Failed to clone process in new user namespace");
goto on_error; goto on_error;
} }
...@@ -4172,7 +4197,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, ...@@ -4172,7 +4197,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
lxc_list_init(idmap); lxc_list_init(idmap);
/* Find container root. */ /* Find container root. */
lxc_list_for_each(cur, &conf->id_map) { lxc_list_for_each (cur, &conf->id_map) {
struct id_map *tmpmap; struct id_map *tmpmap;
tmplist = malloc(sizeof(*tmplist)); tmplist = malloc(sizeof(*tmplist));
...@@ -4262,7 +4287,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, ...@@ -4262,7 +4287,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE || if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE ||
conf->loglevel == LXC_LOG_LEVEL_TRACE) { conf->loglevel == LXC_LOG_LEVEL_TRACE) {
lxc_list_for_each(cur, idmap) { lxc_list_for_each (cur, idmap) {
map = cur->elem; map = cur->elem;
TRACE("establishing %cid mapping for \"%d\" in new " TRACE("establishing %cid mapping for \"%d\" in new "
"user namespace: nsuid %lu - hostid %lu - range " "user namespace: nsuid %lu - hostid %lu - range "
...@@ -4275,14 +4300,13 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, ...@@ -4275,14 +4300,13 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
/* Set up {g,u}id mapping for user namespace of child process. */ /* Set up {g,u}id mapping for user namespace of child process. */
ret = lxc_map_ids(idmap, pid); ret = lxc_map_ids(idmap, pid);
if (ret < 0) { if (ret < 0) {
ERROR("error setting up {g,u}id mappings for child process " ERROR("error setting up {g,u}id mappings for child process \"%d\"", pid);
"\"%d\"", pid);
goto on_error; goto on_error;
} }
/* Tell child to proceed. */ /* Tell child to proceed. */
if (write(p[1], &c, 1) != 1) { if (write(p[1], &c, 1) != 1) {
SYSERROR("failed telling child process \"%d\" to proceed", pid); SYSERROR("Failed telling child process \"%d\" to proceed", pid);
goto on_error; goto on_error;
} }
...@@ -4306,7 +4330,7 @@ on_error: ...@@ -4306,7 +4330,7 @@ on_error:
} }
/* not thread-safe, do not use from api without first forking */ /* not thread-safe, do not use from api without first forking */
static char* getuname(void) static char *getuname(void)
{ {
struct passwd *result; struct passwd *result;
...@@ -4332,16 +4356,18 @@ static char *getgname(void) ...@@ -4332,16 +4356,18 @@ static char *getgname(void)
/* not thread-safe, do not use from api without first forking */ /* not thread-safe, do not use from api without first forking */
void suggest_default_idmap(void) void suggest_default_idmap(void)
{ {
char *uname, *gname;
FILE *f; FILE *f;
unsigned int uid = 0, urange = 0, gid = 0, grange = 0; unsigned int uid = 0, urange = 0, gid = 0, grange = 0;
char *line = NULL;
char *uname, *gname;
size_t len = 0; size_t len = 0;
char *line = NULL;
if (!(uname = getuname())) uname = getuname();
if (!uname)
return; return;
if (!(gname = getgname())) { gname = getgname();
if (!gname) {
free(uname); free(uname);
return; return;
} }
...@@ -4353,17 +4379,22 @@ void suggest_default_idmap(void) ...@@ -4353,17 +4379,22 @@ void suggest_default_idmap(void)
free(uname); free(uname);
return; return;
} }
while (getline(&line, &len, f) != -1) { while (getline(&line, &len, f) != -1) {
char *p, *p2;
size_t no_newline = 0; size_t no_newline = 0;
char *p = strchr(line, ':'), *p2;
p = strchr(line, ':');
if (*line == '#') if (*line == '#')
continue; continue;
if (!p) if (!p)
continue; continue;
*p = '\0'; *p = '\0';
p++; p++;
if (strcmp(line, uname)) if (strcmp(line, uname))
continue; continue;
p2 = strchr(p, ':'); p2 = strchr(p, ':');
if (!p2) if (!p2)
continue; continue;
...@@ -4375,9 +4406,9 @@ void suggest_default_idmap(void) ...@@ -4375,9 +4406,9 @@ void suggest_default_idmap(void)
p2[no_newline] = '\0'; p2[no_newline] = '\0';
if (lxc_safe_uint(p, &uid) < 0) if (lxc_safe_uint(p, &uid) < 0)
WARN("Could not parse UID."); WARN("Could not parse UID");
if (lxc_safe_uint(p2, &urange) < 0) if (lxc_safe_uint(p2, &urange) < 0)
WARN("Could not parse UID range."); WARN("Could not parse UID range");
} }
fclose(f); fclose(f);
...@@ -4388,17 +4419,22 @@ void suggest_default_idmap(void) ...@@ -4388,17 +4419,22 @@ void suggest_default_idmap(void)
free(uname); free(uname);
return; return;
} }
while (getline(&line, &len, f) != -1) { while (getline(&line, &len, f) != -1) {
char *p, *p2;
size_t no_newline = 0; size_t no_newline = 0;
char *p = strchr(line, ':'), *p2;
p = strchr(line, ':');
if (*line == '#') if (*line == '#')
continue; continue;
if (!p) if (!p)
continue; continue;
*p = '\0'; *p = '\0';
p++; p++;
if (strcmp(line, uname)) if (strcmp(line, uname))
continue; continue;
p2 = strchr(p, ':'); p2 = strchr(p, ':');
if (!p2) if (!p2)
continue; continue;
...@@ -4410,9 +4446,9 @@ void suggest_default_idmap(void) ...@@ -4410,9 +4446,9 @@ void suggest_default_idmap(void)
p2[no_newline] = '\0'; p2[no_newline] = '\0';
if (lxc_safe_uint(p, &gid) < 0) if (lxc_safe_uint(p, &gid) < 0)
WARN("Could not parse GID."); WARN("Could not parse GID");
if (lxc_safe_uint(p2, &grange) < 0) if (lxc_safe_uint(p2, &grange) < 0)
WARN("Could not parse GID range."); WARN("Could not parse GID range");
} }
fclose(f); fclose(f);
...@@ -4439,48 +4475,45 @@ static void free_cgroup_settings(struct lxc_list *result) ...@@ -4439,48 +4475,45 @@ static void free_cgroup_settings(struct lxc_list *result)
{ {
struct lxc_list *iterator, *next; struct lxc_list *iterator, *next;
lxc_list_for_each_safe(iterator, result, next) { lxc_list_for_each_safe (iterator, result, next) {
lxc_list_del(iterator); lxc_list_del(iterator);
free(iterator); free(iterator);
} }
free(result); free(result);
} }
/* /* Return the list of cgroup_settings sorted according to the following rules
* Return the list of cgroup_settings sorted according to the following rules
* 1. Put memory.limit_in_bytes before memory.memsw.limit_in_bytes * 1. Put memory.limit_in_bytes before memory.memsw.limit_in_bytes
*/ */
struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings) struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings)
{ {
struct lxc_list *result; struct lxc_list *result;
struct lxc_list *memsw_limit = NULL;
struct lxc_list *it = NULL;
struct lxc_cgroup *cg = NULL; struct lxc_cgroup *cg = NULL;
struct lxc_list *item = NULL; struct lxc_list *it = NULL, *item = NULL, *memsw_limit = NULL;
result = malloc(sizeof(*result)); result = malloc(sizeof(*result));
if (!result) { if (!result)
ERROR("failed to allocate memory to sort cgroup settings");
return NULL; return NULL;
}
lxc_list_init(result); lxc_list_init(result);
/*Iterate over the cgroup settings and copy them to the output list*/ /* Iterate over the cgroup settings and copy them to the output list. */
lxc_list_for_each(it, cgroup_settings) { lxc_list_for_each (it, cgroup_settings) {
item = malloc(sizeof(*item)); item = malloc(sizeof(*item));
if (!item) { if (!item) {
ERROR("failed to allocate memory to sort cgroup settings");
free_cgroup_settings(result); free_cgroup_settings(result);
return NULL; return NULL;
} }
item->elem = it->elem; item->elem = it->elem;
cg = it->elem; cg = it->elem;
if (strcmp(cg->subsystem, "memory.memsw.limit_in_bytes") == 0) { if (strcmp(cg->subsystem, "memory.memsw.limit_in_bytes") == 0) {
/* Store the memsw_limit location */ /* Store the memsw_limit location */
memsw_limit = item; memsw_limit = item;
} else if (strcmp(cg->subsystem, "memory.limit_in_bytes") == 0 && memsw_limit != NULL) { } else if (strcmp(cg->subsystem, "memory.limit_in_bytes") == 0 &&
/* lxc.cgroup.memory.memsw.limit_in_bytes is found before memsw_limit != NULL) {
* lxc.cgroup.memory.limit_in_bytes, swap these two items */ /* lxc.cgroup.memory.memsw.limit_in_bytes is found
* before lxc.cgroup.memory.limit_in_bytes, swap these
* two items */
item->elem = memsw_limit->elem; item->elem = memsw_limit->elem;
memsw_limit->elem = it->elem; memsw_limit->elem = it->elem;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment