#include <../include/openpty.h>
#endif
-#ifdef HAVE_LINUX_MEMFD_H
-#include <linux/memfd.h>
-#endif
-
#include "af_unix.h"
#include "caps.h" /* for lxc_caps_last_cap() */
#include "cgroup.h"
#include "namespace.h"
#include "network.h"
#include "parse.h"
+#include "ringbuf.h"
#include "storage.h"
#include "storage/aufs.h"
#include "storage/overlay.h"
#if IS_BIONIC
#include <../include/lxcmntent.h>
-#ifndef HAVE_PRLIMIT
-#include <../include/prlimit.h>
-#endif
#else
#include <mntent.h>
#endif
-lxc_log_define(lxc_conf, lxc);
-
-#if HAVE_LIBCAP
-#ifndef CAP_SETFCAP
-#define CAP_SETFCAP 31
-#endif
-
-#ifndef CAP_MAC_OVERRIDE
-#define CAP_MAC_OVERRIDE 32
-#endif
-
-#ifndef CAP_MAC_ADMIN
-#define CAP_MAC_ADMIN 33
-#endif
-#endif
-
-#ifndef PR_CAPBSET_DROP
-#define PR_CAPBSET_DROP 24
-#endif
-
-#ifndef LO_FLAGS_AUTOCLEAR
-#define LO_FLAGS_AUTOCLEAR 4
-#endif
-
-#ifndef CAP_SETUID
-#define CAP_SETUID 7
-#endif
-
-#ifndef CAP_SETGID
-#define CAP_SETGID 6
+#if !defined(HAVE_PRLIMIT) && defined(HAVE_PRLIMIT64)
+#include <../include/prlimit.h>
#endif
-/* needed for cgroup automount checks, regardless of whether we
- * have included linux/capability.h or not */
-#ifndef CAP_SYS_ADMIN
-#define CAP_SYS_ADMIN 21
-#endif
+lxc_log_define(lxc_conf, lxc);
/* Define pivot_root() if missing from the C library */
#ifndef HAVE_PIVOT_ROOT
extern int pivot_root(const char * new_root, const char * put_old);
#endif
-/* Define sethostname() if missing from the C library */
-#ifndef HAVE_SETHOSTNAME
-static int sethostname(const char * name, size_t len)
-{
-#ifdef __NR_sethostname
- return syscall(__NR_sethostname, name, len);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-#endif
-
#ifndef MS_PRIVATE
#define MS_PRIVATE (1<<18)
#endif
#define MS_LAZYTIME (1<<25)
#endif
-/* memfd_create() */
-#ifndef MFD_CLOEXEC
-#define MFD_CLOEXEC 0x0001U
-#endif
-
-#ifndef MFD_ALLOW_SEALING
-#define MFD_ALLOW_SEALING 0x0002U
-#endif
-
-#ifndef HAVE_MEMFD_CREATE
-static int memfd_create(const char *name, unsigned int flags) {
- #ifndef __NR_memfd_create
- #if defined __i386__
- #define __NR_memfd_create 356
- #elif defined __x86_64__
- #define __NR_memfd_create 319
- #elif defined __arm__
- #define __NR_memfd_create 385
- #elif defined __aarch64__
- #define __NR_memfd_create 279
- #elif defined __s390__
- #define __NR_memfd_create 350
- #elif defined __powerpc__
- #define __NR_memfd_create 360
- #elif defined __sparc__
- #define __NR_memfd_create 348
- #elif defined __blackfin__
- #define __NR_memfd_create 390
- #elif defined __ia64__
- #define __NR_memfd_create 1340
- #elif defined _MIPS_SIM
- #if _MIPS_SIM == _MIPS_SIM_ABI32
- #define __NR_memfd_create 4354
- #endif
- #if _MIPS_SIM == _MIPS_SIM_NABI32
- #define __NR_memfd_create 6318
- #endif
- #if _MIPS_SIM == _MIPS_SIM_ABI64
- #define __NR_memfd_create 5314
- #endif
- #endif
- #endif
- #ifdef __NR_memfd_create
- return syscall(__NR_memfd_create, name, flags);
- #else
- errno = ENOSYS;
- return -1;
- #endif
-}
-#else
-extern int memfd_create(const char *name, unsigned int flags);
-#endif
-
char *lxchook_names[NUM_LXC_HOOKS] = {"pre-start", "pre-mount", "mount",
"autodev", "start", "stop",
- "post-stop", "clone", "destroy"};
+ "post-stop", "clone", "destroy",
+ "start-host"};
struct mount_opt {
char *name;
struct lxc_conf *current_config;
#endif
-/* Declare this here, since we don't want to reshuffle the whole file. */
-static int in_caplist(int cap, struct lxc_list *caps);
-
static struct mount_opt mount_opt[] = {
{ "async", 1, MS_SYNCHRONOUS },
{ "atime", 1, MS_NOATIME },
{"/proc/self/fd/2", "stderr"},
};
-static int setup_dev_symlinks(const struct lxc_rootfs *rootfs)
+static int lxc_setup_dev_symlinks(const struct lxc_rootfs *rootfs)
{
char path[MAXPATHLEN];
int ret,i;
return 0;
}
-/*
- * Build a space-separate list of ptys to pass to systemd.
- */
+/* Build a space-separate list of ptys to pass to systemd. */
static bool append_ptyname(char **pp, char *name)
{
char *p;
return true;
}
-static int lxc_setup_tty(struct lxc_conf *conf)
+static int lxc_setup_ttys(struct lxc_conf *conf)
{
int i, ret;
const struct lxc_tty_info *tty_info = &conf->tty_info;
struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
ret = snprintf(path, sizeof(path), "/dev/tty%d", i + 1);
- if (ret < 0 || (size_t)ret >= sizeof(path)) {
- ERROR("pathname too long for ttys");
+ if (ret < 0 || (size_t)ret >= sizeof(path))
return -1;
- }
if (ttydir) {
/* create dev/lxc/tty%d" */
ret = snprintf(lxcpath, sizeof(lxcpath),
"/dev/%s/tty%d", ttydir, i + 1);
- if (ret < 0 || (size_t)ret >= sizeof(lxcpath)) {
- ERROR("pathname too long for ttys");
+ if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
return -1;
- }
ret = creat(lxcpath, 0660);
if (ret < 0 && errno != EEXIST) {
- SYSERROR("failed to create \"%s\"", lxcpath);
+ SYSERROR("Failed to create \"%s\"", lxcpath);
return -1;
}
if (ret >= 0)
ret = unlink(path);
if (ret < 0 && errno != ENOENT) {
- SYSERROR("failed to unlink \"%s\"", path);
+ SYSERROR("Failed to unlink \"%s\"", path);
return -1;
}
ret = mount(pty_info->name, lxcpath, "none", MS_BIND, 0);
if (ret < 0) {
- WARN("failed to bind mount \"%s\" onto \"%s\"",
+ WARN("Failed to bind mount \"%s\" onto \"%s\"",
pty_info->name, path);
continue;
}
ret = snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d",
ttydir, i + 1);
- if (ret < 0 || (size_t)ret >= sizeof(lxcpath)) {
- ERROR("tty pathname too long");
+ if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
return -1;
- }
ret = symlink(lxcpath, path);
if (ret < 0) {
- SYSERROR("failed to create symlink \"%s\" -> \"%s\"",
+ SYSERROR("Failed to create symlink \"%s\" -> \"%s\"",
path, lxcpath);
return -1;
}
if (ret < 0) {
ret = creat(path, 0660);
if (ret < 0) {
- SYSERROR("failed to create \"%s\"", path);
+ SYSERROR("Failed to create \"%s\"", path);
/* this isn't fatal, continue */
} else {
close(ret);
ret = mount(pty_info->name, path, "none", MS_BIND, 0);
if (ret < 0) {
- SYSERROR("failed to mount '%s'->'%s'", pty_info->name, path);
+ SYSERROR("Failed to mount '%s'->'%s'", pty_info->name, path);
continue;
}
- DEBUG("bind mounted \"%s\" onto \"%s\"", pty_info->name,
+ DEBUG("Bind mounted \"%s\" onto \"%s\"", pty_info->name,
path);
}
}
}
- INFO("finished setting up %d /dev/tty<N> device(s)", tty_info->nbtty);
+ INFO("Finished setting up %d /dev/tty<N> device(s)", tty_info->nbtty);
+ return 0;
+}
+
+int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
+{
+ struct lxc_tty_info *tty_info = &conf->tty_info;
+ int i, ret;
+
+ /* no tty in the configuration */
+ if (!conf->tty)
+ return 0;
+
+ tty_info->pty_info = malloc(sizeof(*tty_info->pty_info) * conf->tty);
+ if (!tty_info->pty_info) {
+ SYSERROR("failed to allocate struct *pty_info");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < conf->tty; i++) {
+ struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+ process_lock();
+ ret = openpty(&pty_info->master, &pty_info->slave,
+ pty_info->name, NULL, NULL);
+ process_unlock();
+ if (ret) {
+ SYSERROR("failed to create pty device number %d", i);
+ tty_info->nbtty = i;
+ lxc_delete_tty(tty_info);
+ return -ENOTTY;
+ }
+
+ DEBUG("allocated pty \"%s\" with master fd %d and slave fd %d",
+ pty_info->name, pty_info->master, pty_info->slave);
+
+ /* Prevent leaking the file descriptors to the container */
+ ret = fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
+ if (ret < 0)
+ WARN("failed to set FD_CLOEXEC flag on master fd %d of "
+ "pty device \"%s\": %s",
+ pty_info->master, pty_info->name, strerror(errno));
+
+ ret = fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
+ if (ret < 0)
+ WARN("failed to set FD_CLOEXEC flag on slave fd %d of "
+ "pty device \"%s\": %s",
+ pty_info->slave, pty_info->name, strerror(errno));
+
+ pty_info->busy = 0;
+ }
+
+ tty_info->nbtty = conf->tty;
+
+ INFO("finished allocating %d pts devices", conf->tty);
return 0;
}
+void lxc_delete_tty(struct lxc_tty_info *tty_info)
+{
+ int i;
+
+ for (i = 0; i < tty_info->nbtty; i++) {
+ struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+ close(pty_info->master);
+ close(pty_info->slave);
+ }
+
+ free(tty_info->pty_info);
+ tty_info->pty_info = NULL;
+ tty_info->nbtty = 0;
+}
+
+static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
+{
+ int i;
+ struct lxc_conf *conf = handler->conf;
+ struct lxc_tty_info *tty_info = &conf->tty_info;
+ int sock = handler->data_sock[0];
+ int ret = -1;
+
+ if (!conf->tty)
+ return 0;
+
+ for (i = 0; i < conf->tty; i++) {
+ int ttyfds[2];
+ struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+ ttyfds[0] = pty_info->master;
+ ttyfds[1] = pty_info->slave;
+
+ ret = lxc_abstract_unix_send_fds(sock, ttyfds, 2, NULL, 0);
+ if (ret < 0)
+ break;
+
+ TRACE("Send pty \"%s\" with master fd %d and slave fd %d to "
+ "parent", pty_info->name, pty_info->master, pty_info->slave);
+ }
+
+ if (ret < 0)
+ ERROR("Failed to send %d ttys to parent: %s", conf->tty,
+ strerror(errno));
+ else
+ TRACE("Sent %d ttys to parent", conf->tty);
+
+ return ret;
+}
+
+static int lxc_create_ttys(struct lxc_handler *handler)
+{
+ int ret = -1;
+ struct lxc_conf *conf = handler->conf;
+
+ ret = lxc_allocate_ttys(handler->name, conf);
+ if (ret < 0) {
+ ERROR("Failed to allocate ttys");
+ goto on_error;
+ }
+
+ ret = lxc_send_ttys_to_parent(handler);
+ if (ret < 0) {
+ ERROR("Failed to send ttys to parent");
+ goto on_error;
+ }
+
+ if (!conf->is_execute) {
+ ret = lxc_setup_ttys(conf);
+ if (ret < 0) {
+ ERROR("Failed to setup ttys");
+ goto on_error;
+ }
+ }
+
+ if (conf->pty_names) {
+ ret = setenv("container_ttys", conf->pty_names, 1);
+ if (ret < 0)
+ SYSERROR("Failed to set \"container_ttys=%s\"", conf->pty_names);
+ }
+
+ ret = 0;
+
+on_error:
+ lxc_delete_tty(&conf->tty_info);
+
+ return ret;
+}
+
static int setup_rootfs_pivot_root(const char *rootfs)
{
int oldroot = -1, newroot = -1;
return -1;
}
+#if HAVE_PRLIMIT || HAVE_PRLIMIT64
if (prlimit(pid, resid, &lim->limit, NULL) != 0) {
ERROR("failed to set limit %s: %s", lim->resource, strerror(errno));
return -1;
}
+#else
+ ERROR("Cannot set limit %s as prlimit is missing", lim->resource);
+ return -1;
+#endif
}
return 0;
}
new->loglevel = LXC_LOG_LEVEL_NOTSET;
new->personality = -1;
new->autodev = 1;
+ new->console.buffer_log_file = NULL;
+ new->console.buffer_log_file_fd = -1;
+ new->console.buffer_size = 0;
new->console.log_path = NULL;
new->console.log_fd = -1;
new->console.path = NULL;
new->console.master = -1;
new->console.slave = -1;
new->console.name[0] = '\0';
+ memset(&new->console.ringbuf, 0, sizeof(struct lxc_ringbuf));
new->maincmd_fd = -1;
new->nbd_idx = -1;
new->rootfs.mount = strdup(default_rootfs_mount);
lxc_list_init(&new->aliens);
lxc_list_init(&new->environment);
lxc_list_init(&new->limits);
- for (i=0; i<NUM_LXC_HOOKS; i++)
+ for (i = 0; i < NUM_LXC_HOOKS; i++)
lxc_list_init(&new->hooks[i]);
lxc_list_init(&new->groups);
new->lsm_aa_profile = NULL;
new->lsm_se_context = NULL;
new->tmp_umount_proc = 0;
- for (i = 0; i < LXC_NS_MAX; i++)
- new->inherit_ns_fd[i] = -1;
-
/* if running in a new user namespace, init and COMMAND
* default to running as UID/GID 0 when using lxc-execute */
new->init_uid = 0;
new->init_gid = 0;
memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
+ memset(&new->inherit_ns, 0, sizeof(char *) * LXC_NS_MAX);
return new;
}
pos += sprintf(mapbuf, "new%cidmap %d", u_or_g, pid);
lxc_list_for_each(iterator, idmap) {
- /* The kernel only takes <= 4k for writes to
- * /proc/<nr>/[ug]id_map
- */
map = iterator->elem;
if (map->idtype != type)
continue;
use_shadow ? " " : "", map->nsid,
map->hostid, map->range,
use_shadow ? "" : "\n");
- if (fill <= 0 || fill >= left)
- SYSERROR("Too many {g,u}id mappings defined.");
+ if (fill <= 0 || fill >= left) {
+ /* The kernel only takes <= 4k for writes to
+ * /proc/<pid>/{g,u}id_map
+ */
+ SYSERROR("Too many %cid mappings defined", u_or_g);
+ return -1;
+ }
pos += fill;
}
lxc_map_ids_exec_wrapper,
(void *)mapbuf);
if (ret < 0) {
- ERROR("new%cidmap failed to write mapping: %s",
- u_or_g, cmd_output);
+ ERROR("new%cidmap failed to write mapping \"%s\": %s",
+ u_or_g, cmd_output, mapbuf);
return -1;
}
+ TRACE("new%cidmap wrote mapping \"%s\"", u_or_g, mapbuf);
} else {
ret = write_id_mapping(type, pid, mapbuf, pos - mapbuf);
- if (ret < 0)
+ if (ret < 0) {
+ ERROR("Failed to write mapping: %s", mapbuf);
return -1;
+ }
+ TRACE("Wrote mapping \"%s\"", mapbuf);
}
memset(mapbuf, 0, sizeof(mapbuf));
return freeid;
}
-int lxc_create_tty(const char *name, struct lxc_conf *conf)
-{
- struct lxc_tty_info *tty_info = &conf->tty_info;
- int i, ret;
-
- /* no tty in the configuration */
- if (!conf->tty)
- return 0;
-
- tty_info->pty_info = malloc(sizeof(*tty_info->pty_info) * conf->tty);
- if (!tty_info->pty_info) {
- SYSERROR("failed to allocate struct *pty_info");
- return -ENOMEM;
- }
-
- for (i = 0; i < conf->tty; i++) {
- struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
-
- process_lock();
- ret = openpty(&pty_info->master, &pty_info->slave,
- pty_info->name, NULL, NULL);
- process_unlock();
- if (ret) {
- SYSERROR("failed to create pty device number %d", i);
- tty_info->nbtty = i;
- lxc_delete_tty(tty_info);
- return -ENOTTY;
- }
-
- DEBUG("allocated pty \"%s\" with master fd %d and slave fd %d",
- pty_info->name, pty_info->master, pty_info->slave);
-
- /* Prevent leaking the file descriptors to the container */
- ret = fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
- if (ret < 0)
- WARN("failed to set FD_CLOEXEC flag on master fd %d of "
- "pty device \"%s\": %s",
- pty_info->master, pty_info->name, strerror(errno));
-
- ret = fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
- if (ret < 0)
- WARN("failed to set FD_CLOEXEC flag on slave fd %d of "
- "pty device \"%s\": %s",
- pty_info->slave, pty_info->name, strerror(errno));
-
- pty_info->busy = 0;
- }
-
- tty_info->nbtty = conf->tty;
-
- INFO("finished allocating %d pts devices", conf->tty);
- return 0;
-}
-
-void lxc_delete_tty(struct lxc_tty_info *tty_info)
-{
- int i;
-
- for (i = 0; i < tty_info->nbtty; i++) {
- struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
-
- close(pty_info->master);
- close(pty_info->slave);
- }
-
- free(tty_info->pty_info);
- tty_info->pty_info = NULL;
- tty_info->nbtty = 0;
-}
-
-
int chown_mapped_root_exec_wrapper(void *args)
{
execvp("lxc-usernsexec", args);
return true;
}
-static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
-{
- int i;
- int *ttyfds;
- struct lxc_pty_info *pty_info;
- struct lxc_conf *conf = handler->conf;
- const struct lxc_tty_info *tty_info = &conf->tty_info;
- int sock = handler->data_sock[0];
- int ret = -1;
- size_t num_ttyfds = (2 * conf->tty);
-
- ttyfds = malloc(num_ttyfds * sizeof(int));
- if (!ttyfds)
- return -1;
-
- for (i = 0; i < num_ttyfds; i++) {
- pty_info = &tty_info->pty_info[i / 2];
- ttyfds[i++] = pty_info->slave;
- ttyfds[i] = pty_info->master;
- TRACE("send pty \"%s\" with master fd %d and slave fd %d to "
- "parent",
- pty_info->name, pty_info->master, pty_info->slave);
- }
-
- ret = lxc_abstract_unix_send_fds(sock, ttyfds, num_ttyfds, NULL, 0);
- if (ret < 0)
- ERROR("failed to send %d ttys to parent: %s", conf->tty,
- strerror(errno));
- else
- TRACE("sent %d ttys to parent", conf->tty);
-
- close(handler->data_sock[0]);
- close(handler->data_sock[1]);
-
- for (i = 0; i < num_ttyfds; i++)
- close(ttyfds[i]);
-
- free(ttyfds);
-
- return ret;
-}
-
int lxc_setup(struct lxc_handler *handler)
{
+ int ret;
const char *name = handler->name;
struct lxc_conf *lxc_conf = handler->conf;
const char *lxcpath = handler->lxcpath;
return -1;
}
- if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) {
+ if (handler->nsfd[LXC_NS_UTS] == -1) {
if (setup_utsname(lxc_conf->utsname)) {
ERROR("failed to setup the utsname for '%s'", name);
return -1;
}
}
- if (!lxc_conf->is_execute && lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
- ERROR("failed to setup the console for '%s'", name);
+ ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console,
+ lxc_conf->ttydir);
+ if (ret < 0) {
+ ERROR("Failed to setup console");
return -1;
}
- if (!lxc_conf->is_execute && setup_dev_symlinks(&lxc_conf->rootfs)) {
- ERROR("failed to setup /dev symlinks for '%s'", name);
+ ret = lxc_setup_dev_symlinks(&lxc_conf->rootfs);
+ if (ret < 0) {
+ ERROR("Failed to setup /dev symlinks");
return -1;
}
return -1;
}
- if (lxc_create_tty(name, lxc_conf)) {
- ERROR("failed to create the ttys");
- return -1;
- }
-
- if (lxc_send_ttys_to_parent(handler) < 0) {
- ERROR("failure sending console info to parent");
- return -1;
- }
-
- if (!lxc_conf->is_execute && lxc_setup_tty(lxc_conf)) {
- ERROR("failed to setup the ttys for '%s'", name);
+ ret = lxc_create_ttys(handler);
+ if (ret < 0)
return -1;
- }
-
- if (lxc_conf->pty_names && setenv("container_ttys", lxc_conf->pty_names, 1))
- SYSERROR("failed to set environment variable for container ptys");
-
if (setup_personality(lxc_conf->personality)) {
ERROR("failed to setup personality");
if (strcmp(hook, "pre-start") == 0)
which = LXCHOOK_PRESTART;
+ else if (strcmp(hook, "start-host") == 0)
+ which = LXCHOOK_START_HOST;
else if (strcmp(hook, "pre-mount") == 0)
which = LXCHOOK_PREMOUNT;
else if (strcmp(hook, "mount") == 0)
return;
if (current_config == conf)
current_config = NULL;
+ free(conf->console.buffer_log_file);
free(conf->console.log_path);
free(conf->console.path);
+ if (conf->console.buffer_size > 0 && conf->console.ringbuf.addr)
+ lxc_ringbuf_release(&conf->console.ringbuf);
free(conf->rootfs.mount);
free(conf->rootfs.bdev_type);
free(conf->rootfs.options);
free(conf->ttydir);
free(conf->fstab);
free(conf->rcfile);
+ free(conf->execute_cmd);
free(conf->init_cmd);
+ free(conf->init_cwd);
free(conf->unexpanded_config);
free(conf->pty_names);
free(conf->syslog);
struct lxc_list *it;
struct id_map *map;
char c = '1';
- int ret = -1;
+ int ret = -1, status = -1;
struct lxc_list *idmap = NULL, *tmplist = NULL;
struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
*host_uid_map = NULL, *host_gid_map = NULL;
close(p[0]);
p[0] = -1;
+ euid = geteuid();
+ egid = getegid();
+
/* Find container root. */
lxc_list_for_each(it, &conf->id_map) {
map = it->elem;
container_root_uid->hostid = map->hostid;
container_root_uid->nsid = 0;
container_root_uid->range = map->range;
+
+ /* Check if container root mapping contains a mapping
+ * for user's uid.
+ */
+ if (euid >= map->hostid && euid < map->hostid + map->range)
+ host_uid_map = container_root_uid;
} else if (map->idtype == ID_TYPE_GID && container_root_gid == NULL) {
container_root_gid = malloc(sizeof(*container_root_gid));
if (!container_root_gid)
container_root_gid->hostid = map->hostid;
container_root_gid->nsid = 0;
container_root_gid->range = map->range;
+
+ /* Check if container root mapping contains a mapping
+ * for user's gid.
+ */
+ if (egid >= map->hostid && egid < map->hostid + map->range)
+ host_gid_map = container_root_gid;
}
/* Found container root. */
goto on_error;
}
- host_uid_map = container_root_uid;
- host_gid_map = container_root_gid;
-
/* Check whether the {g,u}id of the user has a mapping. */
- euid = geteuid();
- egid = getegid();
- if (euid != container_root_uid->hostid)
+ if (!host_uid_map)
host_uid_map = idmap_add(conf, euid, ID_TYPE_UID);
- if (egid != container_root_gid->hostid)
+ if (!host_gid_map)
host_gid_map = idmap_add(conf, egid, ID_TYPE_GID);
if (!host_uid_map) {
ret = lxc_map_ids(idmap, pid);
if (ret < 0) {
ERROR("error setting up {g,u}id mappings for child process "
- "\"%d\"",
- pid);
+ "\"%d\"", pid);
goto on_error;
}
goto on_error;
}
+on_error:
/* Wait for child to finish. */
- ret = wait_for_pid(pid);
+ if (pid > 0)
+ status = wait_for_pid(pid);
-on_error:
if (idmap)
lxc_free_idmap(idmap);
if (container_root_uid)
close(p[0]);
close(p[1]);
+ if (status < 0)
+ ret = -1;
+
+ return ret;
+}
+
+int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
+ const char *fn_name)
+{
+ pid_t pid;
+ uid_t euid, egid;
+ struct userns_fn_data d;
+ int p[2];
+ struct id_map *map;
+ struct lxc_list *cur;
+ char c = '1';
+ int ret = -1;
+ struct lxc_list *idmap = NULL, *tmplist = NULL;
+ struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
+ *host_uid_map = NULL, *host_gid_map = NULL;
+
+ ret = pipe(p);
+ if (ret < 0) {
+ SYSERROR("opening pipe");
+ return -1;
+ }
+ d.fn = fn;
+ d.fn_name = fn_name;
+ d.arg = data;
+ d.p[0] = p[0];
+ d.p[1] = p[1];
+
+ /* Clone child in new user namespace. */
+ pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER);
+ if (pid < 0) {
+ ERROR("failed to clone child process in new user namespace");
+ goto on_error;
+ }
+
+ close(p[0]);
+ p[0] = -1;
+
+ euid = geteuid();
+ egid = getegid();
+
+ /* Allocate new {g,u}id map list. */
+ idmap = malloc(sizeof(*idmap));
+ if (!idmap)
+ goto on_error;
+ lxc_list_init(idmap);
+
+ /* Find container root. */
+ lxc_list_for_each(cur, &conf->id_map) {
+ struct id_map *tmpmap;
+
+ tmplist = malloc(sizeof(*tmplist));
+ if (!tmplist)
+ goto on_error;
+
+ tmpmap = malloc(sizeof(*tmpmap));
+ if (!tmpmap) {
+ free(tmplist);
+ goto on_error;
+ }
+
+ memset(tmpmap, 0, sizeof(*tmpmap));
+ memcpy(tmpmap, cur->elem, sizeof(*tmpmap));
+ tmplist->elem = tmpmap;
+
+ lxc_list_add_tail(idmap, tmplist);
+
+ map = cur->elem;
+
+ if (map->idtype == ID_TYPE_UID)
+ if (euid >= map->hostid && euid < map->hostid + map->range)
+ host_uid_map = map;
+
+ if (map->idtype == ID_TYPE_GID)
+ if (egid >= map->hostid && egid < map->hostid + map->range)
+ host_gid_map = map;
+
+ if (map->nsid != 0)
+ continue;
+
+ if (map->idtype == ID_TYPE_UID)
+ if (container_root_uid == NULL)
+ container_root_uid = map;
+
+ if (map->idtype == ID_TYPE_GID)
+ if (container_root_gid == NULL)
+ container_root_gid = map;
+ }
+
+ if (!container_root_uid || !container_root_gid) {
+ ERROR("No mapping for container root found");
+ goto on_error;
+ }
+
+ /* Check whether the {g,u}id of the user has a mapping. */
+ if (!host_uid_map)
+ host_uid_map = idmap_add(conf, euid, ID_TYPE_UID);
+ else
+ host_uid_map = container_root_uid;
+
+ if (!host_gid_map)
+ host_gid_map = idmap_add(conf, egid, ID_TYPE_GID);
+ else
+ host_gid_map = container_root_gid;
+
+ if (!host_uid_map) {
+ DEBUG("Failed to find mapping for uid %d", euid);
+ goto on_error;
+ }
+
+ if (!host_gid_map) {
+ DEBUG("Failed to find mapping for gid %d", egid);
+ goto on_error;
+ }
+
+ if (host_uid_map && (host_uid_map != container_root_uid)) {
+ /* Add container root to the map. */
+ tmplist = malloc(sizeof(*tmplist));
+ if (!tmplist)
+ goto on_error;
+ lxc_list_add_elem(tmplist, host_uid_map);
+ lxc_list_add_tail(idmap, tmplist);
+ }
+ /* idmap will now keep track of that memory. */
+ host_uid_map = NULL;
+
+ if (host_gid_map && (host_gid_map != container_root_gid)) {
+ tmplist = malloc(sizeof(*tmplist));
+ if (!tmplist)
+ goto on_error;
+ lxc_list_add_elem(tmplist, host_gid_map);
+ lxc_list_add_tail(idmap, tmplist);
+ }
+ /* idmap will now keep track of that memory. */
+ host_gid_map = NULL;
+
+ if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE ||
+ conf->loglevel == LXC_LOG_LEVEL_TRACE) {
+ lxc_list_for_each(cur, idmap) {
+ map = cur->elem;
+ TRACE("establishing %cid mapping for \"%d\" in new "
+ "user namespace: nsuid %lu - hostid %lu - range "
+ "%lu",
+ (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. */
+ ret = lxc_map_ids(idmap, pid);
+ if (ret < 0) {
+ ERROR("error setting up {g,u}id mappings for child process "
+ "\"%d\"", pid);
+ goto on_error;
+ }
+
+ /* Tell child to proceed. */
+ if (write(p[1], &c, 1) != 1) {
+ SYSERROR("failed telling child process \"%d\" to proceed", pid);
+ goto on_error;
+ }
+
+on_error:
+ /* Wait for child to finish. */
+ if (pid > 0)
+ ret = wait_for_pid(pid);
+
+ if (idmap)
+ lxc_free_idmap(idmap);
+ if (host_uid_map && (host_uid_map != container_root_uid))
+ free(host_uid_map);
+ if (host_gid_map && (host_gid_map != container_root_gid))
+ free(host_gid_map);
+
+ if (p[0] != -1)
+ close(p[0]);
+ close(p[1]);
+
return ret;
}
ERROR("To pass uid mappings to lxc-create, you could create");
ERROR("~/.config/lxc/default.conf:");
ERROR("lxc.include = %s", LXC_DEFAULT_CONFIG);
- ERROR("lxc.id_map = u 0 %u %u", uid, urange);
- ERROR("lxc.id_map = g 0 %u %u", gid, grange);
+ ERROR("lxc.idmap = u 0 %u %u", uid, urange);
+ ERROR("lxc.idmap = g 0 %u %u", gid, grange);
free(gname);
free(uname);