]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/conf.c
Fix strlcat's return value checks
[mirror_lxc.git] / src / lxc / conf.c
index b11737bdbcac9b673b2fac625cd524942dce1034..d2ab8ceda20aa11038aff356c5b142f1cf06483f 100644 (file)
@@ -1,8 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
+#include "config.h"
+
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <errno.h>
 #include <time.h>
 #include <unistd.h>
 
+#include "conf.h"
 #include "af_unix.h"
 #include "caps.h"
 #include "cgroups/cgroup.h"
 #include "compiler.h"
-#include "conf.h"
-#include "config.h"
 #include "confile.h"
 #include "confile_utils.h"
 #include "error.h"
@@ -52,6 +50,7 @@
 #include "mount_utils.h"
 #include "namespace.h"
 #include "network.h"
+#include "open_utils.h"
 #include "parse.h"
 #include "process_utils.h"
 #include "ringbuf.h"
 #if HAVE_OPENPTY
 #include <pty.h>
 #else
-#include <../include/openpty.h>
+#include "openpty.h"
 #endif
 
 #if HAVE_LIBCAP
 #include <sys/capability.h>
 #endif
 
-#ifndef HAVE_STRLCAT
-#include "include/strlcat.h"
+#if !HAVE_STRLCAT
+#include "strlcat.h"
 #endif
 
 #if IS_BIONIC
-#include <../include/lxcmntent.h>
+#include "lxcmntent.h"
 #else
 #include <mntent.h>
 #endif
 
-#if !defined(HAVE_PRLIMIT) && defined(HAVE_PRLIMIT64)
-#include <../include/prlimit.h>
+#if !HAVE_PRLIMIT && HAVE_PRLIMIT64
+#include "prlimit.h"
 #endif
 
-#ifndef HAVE_STRLCPY
-#include "include/strlcpy.h"
+#if !HAVE_STRLCPY
+#include "strlcpy.h"
 #endif
 
-#ifndef HAVE_STRCHRNUL
-#include "include/strchrnul.h"
+#if !HAVE_STRCHRNUL
+#include "strchrnul.h"
 #endif
 
 lxc_log_define(conf, lxc);
@@ -135,7 +134,7 @@ struct mount_opt {
 
 struct caps_opt {
        char *name;
-       int value;
+       __u32 value;
 };
 
 struct limit_opt {
@@ -185,7 +184,7 @@ static struct mount_opt propagation_opt[] = {
        { "rshared",     0, true,  MS_SHARED,     MS_SHARED | MS_REC     },
        { "rslave",      0, true,  MS_SLAVE,      MS_SLAVE | MS_REC      },
        { "runbindable", 0, true,  MS_UNBINDABLE, MS_UNBINDABLE | MS_REC },
-       { NULL,          0, 0                                            },
+       { NULL,          0, false, 0,             0                     },
 };
 
 static struct caps_opt caps_opt[] = {
@@ -512,7 +511,7 @@ int lxc_storage_prepare(struct lxc_conf *conf)
        if (!rootfs->storage)
                return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
                                 rootfs->path, rootfs->mount,
-                                rootfs->options ? rootfs->options : "(null)");
+                                rootfs->mnt_opts.raw_options ? rootfs->mnt_opts.raw_options : "(null)");
 
        return 0;
 }
@@ -581,9 +580,8 @@ int lxc_rootfs_init(struct lxc_conf *conf, bool userns)
                         PROTECT_LOOKUP_BENEATH,
                         S_IWUSR | S_IRUSR);
        if (fd_pin < 0) {
-               if (errno == EROFS) {
+               if (errno == EROFS)
                        return log_trace_errno(0, EROFS, "Not pinning on read-only filesystem");
-               }
                return syserror("Failed to pin rootfs");
        }
 
@@ -619,7 +617,7 @@ int lxc_rootfs_prepare_parent(struct lxc_handler *handler)
        int ret;
        const char *path_source;
 
-       if (lxc_list_empty(&handler->conf->id_map))
+       if (list_empty(&handler->conf->id_map))
                return 0;
 
        if (is_empty_string(rootfs->mnt_opts.userns_path))
@@ -711,9 +709,11 @@ static int lxc_mount_auto_mounts(struct lxc_handler *handler, int flags)
                { LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW,    "proc",                                           "%r/proc",                    "proc",  MS_NODEV|MS_NOEXEC|MS_NOSUID,                    NULL, false },
                { LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RW,     "sysfs",                                          "%r/sys",                     "sysfs", 0,                                               NULL, false },
                { LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_RO,     "sysfs",                                          "%r/sys",                     "sysfs", MS_RDONLY,                                       NULL, false },
+               /* /proc/sys is used as a temporary staging directory for the read-write sysfs mount and unmounted after binding net */
+               { LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                          "%r/proc/sys",                "sysfs", MS_NOSUID|MS_NODEV|MS_NOEXEC,                    NULL, false },
                { LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "sysfs",                                          "%r/sys",                     "sysfs", MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC,          NULL, false },
-               { LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/sys/devices/virtual/net",                     "%r/sys/devices/virtual/net",  NULL,   MS_BIND,                                         NULL, false },
-               { LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  NULL,                                             "%r/sys/devices/virtual/net",  NULL,   MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_NOEXEC,         NULL, false },
+               { LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/proc/sys/devices/virtual/net",                "%r/sys/devices/virtual/net", NULL,    MS_BIND,                                         NULL, false },
+               { LXC_AUTO_SYS_MASK,  LXC_AUTO_SYS_MIXED,  "%r/proc/sys",                                    NULL,                         NULL,    0,                                               NULL, false },
                { 0,                  0,                   NULL,                                             NULL,                         NULL,    0,                                               NULL, false }
        };
        struct lxc_conf *conf = handler->conf;
@@ -781,14 +781,21 @@ static int lxc_mount_auto_mounts(struct lxc_handler *handler, int flags)
                                return syserror_set(-ENOMEM, "Failed to create source path");
                }
 
-               if (!default_mounts[i].destination)
-                       return syserror_set(-EINVAL, "BUG: auto mounts destination %d was NULL", i);
-
                if (!has_cap_net_admin && default_mounts[i].requires_cap_net_admin) {
                        TRACE("Container does not have CAP_NET_ADMIN. Skipping \"%s\" mount", default_mounts[i].source ?: "(null)");
                        continue;
                }
 
+               if (!default_mounts[i].destination) {
+                       ret = umount2(source, MNT_DETACH);
+                       if (ret < 0)
+                               return log_error_errno(-1, errno,
+                                                      "Failed to unmount \"%s\"",
+                                                      source);
+                       TRACE("Unmounted automount \"%s\"", source);
+                       continue;
+               }
+
                /* will act like strdup if %r is not present */
                destination = lxc_string_replace("%r", rootfs->path ? rootfs->mount : "", default_mounts[i].destination);
                if (!destination)
@@ -828,17 +835,14 @@ static int lxc_mount_auto_mounts(struct lxc_handler *handler, int flags)
                 * container can't remount it read-write.
                 */
                if ((cg_flags == LXC_AUTO_CGROUP_NOSPEC) || (cg_flags == LXC_AUTO_CGROUP_FULL_NOSPEC)) {
-                       int has_sys_admin = 0;
-
-                       if (!lxc_list_empty(&conf->keepcaps))
-                               has_sys_admin = in_caplist(CAP_SYS_ADMIN, &conf->keepcaps);
-                       else
-                               has_sys_admin = !in_caplist(CAP_SYS_ADMIN, &conf->caps);
-
                        if (cg_flags == LXC_AUTO_CGROUP_NOSPEC)
-                               cg_flags = has_sys_admin ? LXC_AUTO_CGROUP_RW : LXC_AUTO_CGROUP_MIXED;
+                               cg_flags = has_cap(CAP_SYS_ADMIN, conf)
+                                              ? LXC_AUTO_CGROUP_RW
+                                              : LXC_AUTO_CGROUP_MIXED;
                        else
-                               cg_flags = has_sys_admin ? LXC_AUTO_CGROUP_FULL_RW : LXC_AUTO_CGROUP_FULL_MIXED;
+                               cg_flags = has_cap(CAP_SYS_ADMIN, conf)
+                                              ? LXC_AUTO_CGROUP_FULL_RW
+                                              : LXC_AUTO_CGROUP_FULL_MIXED;
                }
 
                if (flags & LXC_AUTO_CGROUP_FORCE)
@@ -888,7 +892,7 @@ static const struct dev_symlinks dev_symlinks[] = {
 
 static int lxc_setup_dev_symlinks(const struct lxc_rootfs *rootfs)
 {
-       for (int i = 0; i < sizeof(dev_symlinks) / sizeof(dev_symlinks[0]); i++) {
+       for (size_t i = 0; i < sizeof(dev_symlinks) / sizeof(dev_symlinks[0]); i++) {
                int ret;
                struct stat s;
                const struct dev_symlinks *d = &dev_symlinks[i];
@@ -919,29 +923,29 @@ static int lxc_setup_dev_symlinks(const struct lxc_rootfs *rootfs)
 }
 
 /* Build a space-separate list of ptys to pass to systemd. */
-static bool append_ttyname(char **pp, char *name)
+static bool append_ttyname(struct lxc_tty_info *ttys, char *tty_name)
 {
-       char *p;
+       char *tty_names, *buf;
        size_t size;
 
-       if (!*pp) {
-               *pp = zalloc(strlen(name) + strlen("container_ttys=") + 1);
-               if (!*pp)
-                       return false;
+       if (!tty_name)
+               return false;
 
-               sprintf(*pp, "container_ttys=%s", name);
-               return true;
-       }
+       size = strlen(tty_name) + 1;
+       if (ttys->tty_names)
+               size += strlen(ttys->tty_names) + 1;
 
-       size = strlen(*pp) + strlen(name) + 2;
-       p = realloc(*pp, size);
-       if (!p)
+       buf = realloc(ttys->tty_names, size);
+       if (!buf)
                return false;
+       tty_names = buf;
 
-       *pp = p;
-       (void)strlcat(p, " ", size);
-       (void)strlcat(p, name, size);
-
+       if (ttys->tty_names)
+               (void)strlcat(buf, " ", size);
+       else
+               buf[0] = '\0';
+       (void)strlcat(buf, tty_name, size);
+       ttys->tty_names = tty_names;
        return true;
 }
 
@@ -954,7 +958,7 @@ static int open_ttymnt_at(int dfd, const char *path)
                     PROTECT_LOOKUP_BENEATH,
                     0);
        if (fd < 0) {
-               if (!IN_SET(errno, ENXIO, EEXIST))
+               if (errno != ENXIO && errno != EEXIST)
                        return syserror("Failed to create \"%d/\%s\"", dfd, path);
 
                SYSINFO("Failed to create \"%d/\%s\"", dfd, path);
@@ -977,7 +981,7 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
        if (!conf->rootfs.path)
                return 0;
 
-       for (int i = 0; i < ttys->max; i++) {
+       for (size_t i = 0; i < ttys->max; i++) {
                __do_close int fd_to = -EBADF;
                struct lxc_terminal_info *tty = &ttys->tty[i];
 
@@ -985,7 +989,7 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
                        char *tty_name, *tty_path;
 
                        ret = strnprintf(rootfs->buf, sizeof(rootfs->buf),
-                                      "/dev/%s/tty%d", ttydir, i + 1);
+                                      "/dev/%s/tty%zu", ttydir, i + 1);
                        if (ret < 0)
                                return ret_errno(-EIO);
 
@@ -1031,7 +1035,7 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
                                                       rootfs->dfd_dev, tty_name,
                                                       rootfs->dfd_dev, tty_path);
                } else {
-                       ret = strnprintf(rootfs->buf, sizeof(rootfs->buf), "tty%d", i + 1);
+                       ret = strnprintf(rootfs->buf, sizeof(rootfs->buf), "tty%zu", i + 1);
                        if (ret < 0)
                                return ret_errno(-EIO);
 
@@ -1062,7 +1066,7 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
                        DEBUG("Bind mounted \"%s\" onto \"%s\"", tty->name, rootfs->buf);
                }
 
-               if (!append_ttyname(&conf->ttys.tty_names, tty->name))
+               if (!append_ttyname(&conf->ttys, tty->name))
                        return log_error(-1, "Error setting up container_ttys string");
        }
 
@@ -1086,17 +1090,20 @@ static int lxc_allocate_ttys(struct lxc_conf *conf)
                return -ENOMEM;
 
        for (size_t i = 0; i < conf->ttys.max; i++) {
-               int pty_nr = -1;
                struct lxc_terminal_info *tty = &ttys->tty[i];
 
                ret = lxc_devpts_terminal(conf->devpts_fd, &tty->ptx,
-                                         &tty->pty, &pty_nr, false);
+                                         &tty->pty, &tty->pty_nr, false);
                if (ret < 0) {
                        conf->ttys.max = i;
                        return syserror_set(-ENOTTY, "Failed to create tty %zu", i);
                }
+               ret = strnprintf(tty->name, sizeof(tty->name), "pts/%d", tty->pty_nr);
+               if (ret < 0)
+                       return syserror("Failed to create tty %zu", i);
+
                DEBUG("Created tty with ptx fd %d and pty fd %d and index %d",
-                     tty->ptx, tty->pty, pty_nr);
+                     tty->ptx, tty->pty, tty->pty_nr);
                tty->busy = -1;
        }
 
@@ -1110,7 +1117,7 @@ void lxc_delete_tty(struct lxc_tty_info *ttys)
        if (!ttys || !ttys->tty)
                return;
 
-       for (int i = 0; i < ttys->max; i++) {
+       for (size_t i = 0; i < ttys->max; i++) {
                struct lxc_terminal_info *tty = &ttys->tty[i];
                close_prot_errno_disarm(tty->ptx);
                close_prot_errno_disarm(tty->pty);
@@ -1121,7 +1128,6 @@ void lxc_delete_tty(struct lxc_tty_info *ttys)
 
 static int __lxc_send_ttys_to_parent(struct lxc_handler *handler)
 {
-       int i;
        int ret = -1;
        struct lxc_conf *conf = handler->conf;
        struct lxc_tty_info *ttys = &conf->ttys;
@@ -1130,7 +1136,7 @@ static int __lxc_send_ttys_to_parent(struct lxc_handler *handler)
        if (ttys->max == 0)
                return 0;
 
-       for (i = 0; i < ttys->max; i++) {
+       for (size_t i = 0; i < ttys->max; i++) {
                int ttyfds[2];
                struct lxc_terminal_info *tty = &ttys->tty[i];
 
@@ -1178,6 +1184,7 @@ static int lxc_create_ttys(struct lxc_handler *handler)
                        SYSERROR("Failed to set \"container_ttys=%s\"", conf->ttys.tty_names);
                        goto on_error;
                }
+               TRACE("Set \"container_ttys=%s\"", conf->ttys.tty_names);
        }
 
        return 0;
@@ -1301,7 +1308,7 @@ enum {
 
 static int lxc_fill_autodev(struct lxc_rootfs *rootfs)
 {
-       int i, ret;
+       int ret;
        mode_t cmask;
        int use_mknod = LXC_DEVNODE_MKNOD;
 
@@ -1311,7 +1318,7 @@ static int lxc_fill_autodev(struct lxc_rootfs *rootfs)
        INFO("Populating \"/dev\"");
 
        cmask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
-       for (i = 0; i < sizeof(lxc_devices) / sizeof(lxc_devices[0]); i++) {
+       for (size_t i = 0; i < sizeof(lxc_devices) / sizeof(lxc_devices[0]); i++) {
                const struct lxc_device_node *device = &lxc_devices[i];
 
                if (use_mknod >= LXC_DEVNODE_MKNOD) {
@@ -1425,11 +1432,11 @@ static int lxc_mount_rootfs(struct lxc_rootfs *rootfs)
        if (ret < 0)
                return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"",
                                 rootfs->path, rootfs->mount,
-                                rootfs->options ? rootfs->options : "(null)");
+                                rootfs->mnt_opts.raw_options ? rootfs->mnt_opts.raw_options : "(null)");
 
        DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\"",
              rootfs->path, rootfs->mount,
-             rootfs->options ? rootfs->options : "(null)");
+             rootfs->mnt_opts.raw_options ? rootfs->mnt_opts.raw_options : "(null)");
 
        rootfs->dfd_mnt = open_at(-EBADF, rootfs->mount, PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE_XDEV, 0);
        if (rootfs->dfd_mnt < 0)
@@ -1438,6 +1445,23 @@ static int lxc_mount_rootfs(struct lxc_rootfs *rootfs)
        return log_trace(0, "Container uses separate rootfs. Opened container's rootfs");
 }
 
+static bool lxc_rootfs_overmounted(struct lxc_rootfs *rootfs)
+{
+       __do_close int fd_rootfs = -EBADF;
+
+       if (!rootfs->path)
+               fd_rootfs = open_at(-EBADF, "/", PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE, 0);
+       else
+               fd_rootfs = open_at(-EBADF, rootfs->mount, PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE_XDEV, 0);
+       if (fd_rootfs < 0)
+               return true;
+
+       if (!same_file_lax(rootfs->dfd_mnt, fd_rootfs))
+               return syswarn_ret(true, "Rootfs seems to have changed after setting up mounts");
+
+       return false;
+}
+
 static int lxc_chroot(const struct lxc_rootfs *rootfs)
 {
        __do_free char *nroot = NULL;
@@ -1582,8 +1606,11 @@ static int lxc_pivot_root(const struct lxc_rootfs *rootfs)
                return log_error_errno(-errno, errno, "Failed to enter old root directory");
 
        /*
-        * Make fd_oldroot a depedent mount to make sure our umounts don't
-        * propagate to the host.
+        * Unprivileged containers will have had all their mounts turned into
+        * dependent mounts when the container was created. But for privileged
+        * containers we need to turn the old root mount tree into a dependent
+        * mount tree to prevent propagating mounts and umounts into the host
+        * mount namespace.
         */
        ret = mount("", ".", "", MS_SLAVE | MS_REC, NULL);
        if (ret < 0)
@@ -1597,6 +1624,31 @@ static int lxc_pivot_root(const struct lxc_rootfs *rootfs)
        if (ret < 0)
                return log_error_errno(-errno, errno, "Failed to re-enter new root directory \"%s\"", rootfs->mount);
 
+       /*
+        * Finally, we turn the rootfs into a shared mount. Note, that this
+        * doesn't reestablish mount propagation with the hosts mount
+        * namespace. Instead we'll create a new peer group.
+        *
+        * We're doing this because most workloads do rely on the rootfs being
+        * a shared mount. For example, systemd daemon like sytemd-udevd run in
+        * their own mount namespace. Their mount namespace has been made a
+        * dependent mount (MS_SLAVE) with the host rootfs as it's dominating
+        * mount. This means new mounts on the host propagate into the
+        * respective services.
+        *
+        * This is broken if we leave the container's rootfs a dependent mount.
+        * In which case both the container's rootfs and the service's rootfs
+        * will be dependent mounts with the host's rootfs as their dominating
+        * mount. So if you were to mount over the rootfs from the host it
+        * would not just propagate into the container's mount namespace it
+        * would also propagate into the service. That's nonsense semantics for
+        * nearly all relevant use-cases. Instead, establish the container's
+        * rootfs as a separate peer group mirroring the behavior on the host.
+        */
+       ret = mount("", ".", "", MS_SHARED | MS_REC, NULL);
+       if (ret < 0)
+               return log_error_errno(-errno, errno, "Failed to turn new root mount tree into shared mount tree");
+
        TRACE("Changed into new rootfs \"%s\"", rootfs->mount);
        return 0;
 }
@@ -1616,7 +1668,6 @@ static const struct id_map *find_mapped_nsid_entry(const struct lxc_conf *conf,
                                                   unsigned id,
                                                   enum idtype idtype)
 {
-       struct lxc_list *it;
        struct id_map *map;
        struct id_map *retmap = NULL;
 
@@ -1629,8 +1680,7 @@ static const struct id_map *find_mapped_nsid_entry(const struct lxc_conf *conf,
                        return conf->root_nsgid_map;
        }
 
-       lxc_list_for_each(it, &conf->id_map) {
-               map = it->elem;
+       list_for_each_entry(map, &conf->id_map, head) {
                if (map->idtype != idtype)
                        continue;
 
@@ -1860,7 +1910,8 @@ static int lxc_finish_devpts_child(struct lxc_handler *handler)
                return syserror("Failed to create path");
 
        close_prot_errno_disarm(conf->devpts_fd);
-       return umount2(rootfs->buf, MNT_DETACH);
+       (void)umount2(rootfs->buf, MNT_DETACH);
+       return 0;
 }
 
 static int lxc_send_devpts_to_parent(struct lxc_handler *handler)
@@ -2161,7 +2212,7 @@ static int lxc_setup_console(const struct lxc_handler *handler,
 
 static int parse_mntopt(char *opt, unsigned long *flags, char **data, size_t size)
 {
-       ssize_t ret;
+       size_t ret;
 
        /* If '=' is contained in opt, the option must go into data. */
        if (!strchr(opt, '=')) {
@@ -2185,12 +2236,12 @@ static int parse_mntopt(char *opt, unsigned long *flags, char **data, size_t siz
 
        if (strlen(*data)) {
                ret = strlcat(*data, ",", size);
-               if (ret < 0)
+               if (ret >= size)
                        return log_error_errno(ret, errno, "Failed to append \",\" to %s", *data);
        }
 
        ret = strlcat(*data, opt, size);
-       if (ret < 0)
+       if (ret >= size)
                return log_error_errno(ret, errno, "Failed to append \"%s\" to %s", opt, *data);
 
        return 0;
@@ -2239,7 +2290,7 @@ static int parse_vfs_attr(struct lxc_mount_options *opts, char *opt, size_t size
 
                /* This is a recursive bind-mount. */
                if (strequal(mo->name, "rbind")) {
-                       opts->recursive = 1;
+                       opts->bind_recursively = 1;
                        opts->bind = 1;
                        opts->mnt_flags |= mo->legacy_flag; /* MS_BIND | MS_REC */
                        return 0;
@@ -2252,7 +2303,7 @@ static int parse_vfs_attr(struct lxc_mount_options *opts, char *opt, size_t size
                        return 0;
                }
 
-               if (mo->flag == ~0)
+               if (mo->flag == (__u64)~0)
                        return log_info(0, "Ignoring %s mount option", mo->name);
 
                if (mo->clear) {
@@ -2272,9 +2323,14 @@ static int parse_vfs_attr(struct lxc_mount_options *opts, char *opt, size_t size
                if (!strnequal(opt, mo->name, strlen(mo->name)))
                        continue;
 
-               /* TODO: Handle recursive propagation requests. */
+               if (strequal(mo->name, "rslave") ||
+                   strequal(mo->name, "rshared") ||
+                   strequal(mo->name, "runbindable") ||
+                   strequal(mo->name, "rprivate"))
+                       opts->propagate_recursively = 1;
+
                opts->attr.propagation = mo->flag;
-               opts->mnt_flags |= mo->legacy_flag;
+               opts->prop_flags |= mo->legacy_flag;
                return 0;
        }
 
@@ -2328,43 +2384,6 @@ int parse_mount_attrs(struct lxc_mount_options *opts, const char *mntopts)
        return 0;
 }
 
-static void parse_propagationopt(char *opt, unsigned long *flags)
-{
-       struct mount_opt *mo;
-
-       /* If opt is found in propagation_opt, set or clear flags. */
-       for (mo = &propagation_opt[0]; mo->name != NULL; mo++) {
-               if (!strnequal(opt, mo->name, strlen(mo->name)))
-                       continue;
-
-               if (mo->clear)
-                       *flags &= ~mo->legacy_flag;
-               else
-                       *flags |= mo->legacy_flag;
-
-               return;
-       }
-}
-
-int parse_propagationopts(const char *mntopts, unsigned long *pflags)
-{
-       __do_free char *s = NULL;
-       char *p;
-
-       if (!mntopts)
-               return 0;
-
-       s = strdup(mntopts);
-       if (!s)
-               return log_error_errno(-ENOMEM, errno, "Failed to allocate memory");
-
-       *pflags = 0L;
-       lxc_iterate_parts(p, s, ",")
-               parse_propagationopt(p, pflags);
-
-       return 0;
-}
-
 static void null_endofword(char *word)
 {
        while (*word && *word != ' ' && *word != '\t')
@@ -2616,7 +2635,6 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
                                         const char *lxc_path)
 {
        __do_free char *mntdata = NULL;
-       unsigned long mntflags = 0, pflags = 0;
        char *rootfs_path = NULL;
        int ret;
        bool dev, optional, relative;
@@ -2652,16 +2670,20 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
        if (!is_empty_string(opts.userns_path))
                return systrace_ret(0, "Skipping idmapped mount entry");
 
-       ret = parse_propagationopts(mntent->mnt_opts, &pflags);
+       ret = parse_mount_attrs(&opts, mntent->mnt_opts);
        if (ret < 0)
                return -1;
 
-       ret = parse_mntopts_legacy(mntent->mnt_opts, &mntflags, &mntdata);
-       if (ret < 0)
-               return ret;
-
-       ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags,
-                         pflags, mntdata, optional, dev, relative, rootfs_path);
+       ret = mount_entry(mntent->mnt_fsname,
+                         path,
+                         mntent->mnt_type,
+                         opts.mnt_flags,
+                         opts.prop_flags,
+                         opts.data,
+                         optional,
+                         dev,
+                         relative,
+                         rootfs_path);
 
        return ret;
 }
@@ -2809,14 +2831,13 @@ static const char nesting_helpers[] =
 "proc dev/.lxc/proc proc create=dir,optional 0 0\n"
 "sys dev/.lxc/sys sysfs create=dir,optional 0 0\n";
 
-FILE *make_anonymous_mount_file(struct lxc_list *mount,
+FILE *make_anonymous_mount_file(const struct list_head *mount_entries,
                                bool include_nesting_helpers)
 {
        __do_close int fd = -EBADF;
        FILE *f;
        int ret;
-       char *mount_entry;
-       struct lxc_list *iterator;
+       struct string_entry *entry;
 
        fd = memfd_create(".lxc_mount_file", MFD_CLOEXEC);
        if (fd < 0) {
@@ -2832,14 +2853,13 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount,
                TRACE("Created temporary mount file");
        }
 
-       lxc_list_for_each (iterator, mount) {
+       list_for_each_entry(entry, mount_entries, head) {
                size_t len;
 
-               mount_entry = iterator->elem;
-               len = strlen(mount_entry);
+               len = strlen(entry->val);
 
-               ret = lxc_write_nointr(fd, mount_entry, len);
-               if (ret != len)
+               ret = lxc_write_nointr(fd, entry->val, len);
+               if (ret < 0 || (size_t)ret != len)
                        return NULL;
 
                ret = lxc_write_nointr(fd, "\n", 1);
@@ -2865,12 +2885,12 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount,
 }
 
 static int setup_mount_entries(const struct lxc_conf *conf,
-                              struct lxc_rootfs *rootfs, struct lxc_list *mount,
+                              struct lxc_rootfs *rootfs,
                               const char *lxc_name, const char *lxc_path)
 {
        __do_fclose FILE *f = NULL;
 
-       f = make_anonymous_mount_file(mount, conf->lsm_aa_allow_nesting);
+       f = make_anonymous_mount_file(&conf->mount_entries, conf->lsm_aa_allow_nesting);
        if (!f)
                return -1;
 
@@ -2894,6 +2914,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f)
                struct lxc_mount_options opts = {};
                int dfd_from;
                const char *source_relative, *target_relative;
+               struct mount_attr attr = {};
 
                ret = parse_lxc_mount_attrs(&opts, mntent.mnt_opts);
                if (ret < 0)
@@ -2935,10 +2956,10 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f)
                        dfd_from = rootfs->dfd_host;
                fd_from = open_tree(dfd_from, source_relative,
                                    OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC |
-                                   (opts.recursive ? AT_RECURSIVE : 0));
+                                   (opts.bind_recursively ? AT_RECURSIVE : 0));
                if (fd_from < 0)
                        return syserror("Failed to create detached %smount of %d/%s",
-                                       opts.recursive ? "recursive " : "",
+                                       opts.bind_recursively ? "recursive " : "",
                                        dfd_from, source_relative);
 
                if (strequal(opts.userns_path, "container"))
@@ -2953,7 +2974,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f)
                        }
 
                        return syserror("Failed to open user namespace \"%s\" for detached %smount of %d/%s",
-                                       opts.userns_path, opts.recursive ? "recursive " : "",
+                                       opts.userns_path, opts.bind_recursively ? "recursive " : "",
                                        dfd_from, source_relative);
                }
 
@@ -2967,7 +2988,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f)
                        }
 
                        return syserror("Failed to send file descriptor %d for detached %smount of %d/%s and file descriptor %d of user namespace \"%s\" to parent",
-                                       fd_from, opts.recursive ? "recursive " : "",
+                                       fd_from, opts.bind_recursively ? "recursive " : "",
                                        dfd_from, source_relative, fd_userns,
                                        opts.userns_path);
                }
@@ -2982,7 +3003,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f)
                        }
 
                        return syserror("Failed to receive notification that parent idmapped detached %smount %d/%s to user namespace %d",
-                                       opts.recursive ? "recursive " : "",
+                                       opts.bind_recursively ? "recursive " : "",
                                        dfd_from, source_relative, fd_userns);
                }
 
@@ -2991,21 +3012,51 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f)
                                        mnt_seq, cur_mnt_seq);
                mnt_seq++;
 
-               /* Set remaining mount options. */
-               ret = mount_setattr(fd_from, "", AT_EMPTY_PATH |
-                                   (opts.recursive ? AT_RECURSIVE : 0),
-                                   &opts.attr, sizeof(opts.attr));
+               /* Set regular mount options. */
+               attr = opts.attr;
+               attr.propagation = 0;
+               ret = mount_setattr(fd_from,
+                                   "",
+                                   AT_EMPTY_PATH |
+                                   (opts.bind_recursively ? AT_RECURSIVE : 0),
+                                   &attr,
+                                   sizeof(attr));
                if (ret < 0) {
                        if (opts.optional) {
                                TRACE("Skipping optional idmapped mount");
                                continue;
                        }
 
-                       return syserror("Failed to receive notification that parent idmapped detached %smount %d/%s to user namespace %d",
-                                       opts.recursive ? "recursive " : "",
-                                       dfd_from, source_relative, fd_userns);
+                       return syserror("Failed to set %smount options on detached %d/%s",
+                                       opts.bind_recursively ? "recursive " : "",
+                                       dfd_from, source_relative);
+               }
+
+               /* Set propagation mount options. */
+               if (opts.attr.propagation) {
+                       attr = (struct mount_attr) {
+                               .propagation = opts.attr.propagation,
+                       };
+
+                       ret = mount_setattr(fd_from,
+                                       "",
+                                       AT_EMPTY_PATH |
+                                       (opts.propagate_recursively ? AT_RECURSIVE : 0),
+                                       &attr,
+                                       sizeof(attr));
+                       if (ret < 0) {
+                               if (opts.optional) {
+                                       TRACE("Skipping optional idmapped mount");
+                                       continue;
+                               }
+
+                               return syserror("Failed to set %spropagation mount options on detached %d/%s",
+                                               opts.bind_recursively ? "recursive " : "",
+                                               dfd_from, source_relative);
+                       }
                }
 
+
                /*
                 * In contrast to the legacy mount codepath we will simplify
                 * our lifes and just always treat the target mountpoint to be
@@ -3018,7 +3069,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f)
                        dfd_from = rootfs->dfd_mnt;
                else
                        dfd_from = rootfs->dfd_host;
-               fd_to = open_at(dfd_from, target_relative, PROTECT_OPATH_FILE, PROTECT_LOOKUP_BENEATH_WITH_SYMLINKS, 0);
+               fd_to = open_at(dfd_from, target_relative, PROTECT_OPATH_FILE, PROTECT_LOOKUP_BENEATH_XDEV, 0);
                if (fd_to < 0) {
                        if (opts.optional) {
                                TRACE("Skipping optional idmapped mount");
@@ -3027,7 +3078,7 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f)
 
                        return syserror("Failed to open target mountpoint %d/%s for detached idmapped %smount %d:%d/%s",
                                        dfd_from, target_relative,
-                                       opts.recursive ? "recursive " : "",
+                                       opts.bind_recursively ? "recursive " : "",
                                        fd_userns, dfd_from, source_relative);
                }
 
@@ -3039,12 +3090,12 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f)
                        }
 
                        return syserror("Failed to attach detached idmapped %smount %d:%d/%s to target mountpoint %d/%s",
-                                       opts.recursive ? "recursive " : "",
+                                       opts.bind_recursively ? "recursive " : "",
                                        fd_userns, dfd_from, source_relative, dfd_from, target_relative);
                }
 
                TRACE("Attached detached idmapped %smount %d:%d/%s to target mountpoint %d/%s",
-                     opts.recursive ? "recursive " : "", fd_userns, dfd_from,
+                     opts.bind_recursively ? "recursive " : "", fd_userns, dfd_from,
                      source_relative, dfd_from, target_relative);
        }
 
@@ -3060,10 +3111,10 @@ static int lxc_idmapped_mounts_child(struct lxc_handler *handler)
        int fret = -1;
        struct lxc_conf *conf = handler->conf;
        const char *fstab = conf->fstab;
-       struct lxc_list *mount = &conf->mount_list;
        int ret;
 
-       f_entries = make_anonymous_mount_file(mount, conf->lsm_aa_allow_nesting);
+       f_entries = make_anonymous_mount_file(&conf->mount_entries,
+                                             conf->lsm_aa_allow_nesting);
        if (!f_entries) {
                SYSERROR("Failed to create anonymous mount file");
                goto out;
@@ -3105,123 +3156,119 @@ out:
        return fret;
 }
 
-static int parse_cap(const char *cap)
+int parse_cap(const char *cap_name, __u32 *cap)
 {
-       size_t i;
-       int capid = -1;
        size_t end = sizeof(caps_opt) / sizeof(caps_opt[0]);
-       char *ptr = NULL;
+       int ret;
+       unsigned int res;
+       __u32 last_cap;
 
-       if (strequal(cap, "none"))
+       if (strequal(cap_name, "none"))
                return -2;
 
-       for (i = 0; i < end; i++) {
-               if (!strequal(cap, caps_opt[i].name))
+       for (size_t i = 0; i < end; i++) {
+               if (!strequal(cap_name, caps_opt[i].name))
                        continue;
 
-               capid = caps_opt[i].value;
-               break;
+               *cap = caps_opt[i].value;
+               return 0;
        }
 
-       if (capid < 0) {
-               /* Try to see if it's numeric, so the user may specify
-                * capabilities that the running kernel knows about but we
-                * don't
-                */
-               errno = 0;
-               capid = strtol(cap, &ptr, 10);
-               if (!ptr || *ptr != '\0' || errno != 0)
-                       /* not a valid number */
-                       capid = -1;
-               else if (capid > lxc_caps_last_cap())
-                       /* we have a number but it's not a valid
-                        * capability */
-                       capid = -1;
-       }
-
-       return capid;
+       /*
+        * Try to see if it's numeric, so the user may specify
+        * capabilities that the running kernel knows about but we
+        * don't.
+        */
+       ret = lxc_safe_uint(cap_name, &res);
+       if (ret < 0)
+               return -1;
+
+       ret = lxc_caps_last_cap(&last_cap);
+       if (ret)
+               return -1;
+
+       if ((__u32)res > last_cap)
+               return -1;
+
+       *cap = (__u32)res;
+       return 0;
 }
 
-int in_caplist(int cap, struct lxc_list *caps)
+bool has_cap(__u32 cap, struct lxc_conf *conf)
 {
-       int capid;
-       struct lxc_list *iterator;
+       bool cap_in_list = false;
+       struct cap_entry *cap_entry;
+
+       list_for_each_entry(cap_entry, &conf->caps.list, head) {
+               if (cap_entry->cap != cap)
+                       continue;
 
-       lxc_list_for_each (iterator, caps) {
-               capid = parse_cap(iterator->elem);
-               if (capid == cap)
-                       return 1;
+               cap_in_list = true;
        }
 
-       return 0;
+       /* The capability is kept. */
+       if (conf->caps.keep)
+               return cap_in_list;
+
+       /* The capability is not dropped. */
+       return !cap_in_list;
 }
 
-static int setup_caps(struct lxc_list *caps)
+static int capabilities_deny(struct lxc_conf *conf)
 {
-       int capid;
-       char *drop_entry;
-       struct lxc_list *iterator;
+       struct cap_entry *cap;
 
-       lxc_list_for_each (iterator, caps) {
+       list_for_each_entry(cap, &conf->caps.list, head) {
                int ret;
 
-               drop_entry = iterator->elem;
-
-               capid = parse_cap(drop_entry);
-               if (capid < 0)
-                       return log_error(-1, "unknown capability %s", drop_entry);
-
-               ret = prctl(PR_CAPBSET_DROP, prctl_arg(capid), prctl_arg(0),
+               ret = prctl(PR_CAPBSET_DROP, prctl_arg(cap->cap), prctl_arg(0),
                            prctl_arg(0), prctl_arg(0));
                if (ret < 0)
-                       return log_error_errno(-1, errno, "Failed to remove %s capability", drop_entry);
-               DEBUG("Dropped %s (%d) capability", drop_entry, capid);
+                       return syserror("Failed to remove %s capability", cap->cap_name);
+
+               DEBUG("Dropped %s (%d) capability", cap->cap_name, cap->cap);
        }
 
        DEBUG("Capabilities have been setup");
        return 0;
 }
 
-static int dropcaps_except(struct lxc_list *caps)
+static int capabilities_allow(struct lxc_conf *conf)
 {
-       __do_free int *caplist = NULL;
-       int i, capid, numcaps;
-       char *keep_entry;
-       struct lxc_list *iterator;
+       __do_free __u32 *keep_bits = NULL;
+       int ret;
+       struct cap_entry *cap;
+       __u32 last_cap, nr_u32;
 
-       numcaps = lxc_caps_last_cap() + 1;
-       if (numcaps <= 0 || numcaps > 200)
-               return -1;
-       TRACE("Found %d capabilities", numcaps);
+       ret = lxc_caps_last_cap(&last_cap);
+       if (ret || last_cap > 200)
+               return ret_errno(EINVAL);
 
-       /* caplist[i] is 1 if we keep capability i */
-       caplist = must_realloc(NULL, numcaps * sizeof(int));
-       memset(caplist, 0, numcaps * sizeof(int));
+       TRACE("Found %d capabilities", last_cap);
 
-       lxc_list_for_each (iterator, caps) {
-               keep_entry = iterator->elem;
+       nr_u32 = BITS_TO_LONGS(last_cap);
+       keep_bits = zalloc(nr_u32 * sizeof(__u32));
+       if (!keep_bits)
+               return ret_errno(ENOMEM);
 
-               capid = parse_cap(keep_entry);
-               if (capid == -2)
+       list_for_each_entry(cap, &conf->caps.list, head) {
+               if (cap->cap > last_cap)
                        continue;
 
-               if (capid < 0)
-                       return log_error(-1, "Unknown capability %s", keep_entry);
-
-               DEBUG("Keep capability %s (%d)", keep_entry, capid);
-               caplist[capid] = 1;
+               set_bit(cap->cap, keep_bits);
+               DEBUG("Keeping %s (%d) capability", cap->cap_name, cap->cap);
        }
 
-       for (i = 0; i < numcaps; i++) {
-               int ret;
-
-               if (caplist[i])
+       for (__u32 cap_bit = 0; cap_bit <= last_cap; cap_bit++) {
+               if (is_set(cap_bit, keep_bits))
                        continue;
 
-               ret = prctl(PR_CAPBSET_DROP, prctl_arg(i), prctl_arg(0),
+               ret = prctl(PR_CAPBSET_DROP, prctl_arg(cap_bit), prctl_arg(0),
                            prctl_arg(0), prctl_arg(0));
                if (ret < 0)
-                       return log_error_errno(-1, errno, "Failed to remove capability %d", i);
+                       return syserror("Failed to remove capability %d", cap_bit);
+
+               TRACE("Dropped capability %d", cap_bit);
        }
 
        DEBUG("Capabilities have been setup");
@@ -3249,15 +3296,15 @@ static int parse_resource(const char *res)
        return resid;
 }
 
-int setup_resource_limits(struct lxc_list *limits, pid_t pid)
+int setup_resource_limits(struct lxc_conf *conf, pid_t pid)
 {
        int resid;
-       struct lxc_list *it;
        struct lxc_limit *lim;
 
-       lxc_list_for_each (it, limits) {
-               lim = it->elem;
+       if (list_empty(&conf->limits))
+               return 0;
 
+       list_for_each_entry(lim, &conf->limits, head) {
                resid = parse_resource(lim->resource);
                if (resid < 0)
                        return log_error(-1, "Unknown resource %s", lim->resource);
@@ -3272,61 +3319,71 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid)
 #endif
        }
 
+       TRACE("Setup resource limits");
        return 0;
 }
 
-int setup_sysctl_parameters(struct lxc_list *sysctls)
+int setup_sysctl_parameters(struct lxc_conf *conf)
 {
        __do_free char *tmp = NULL;
-       struct lxc_list *it;
-       struct lxc_sysctl *elem;
        int ret = 0;
        char filename[PATH_MAX] = {0};
+       struct lxc_sysctl *sysctl, *nsysctl;
+
+       if (list_empty(&conf->sysctls))
+               return 0;
 
-       lxc_list_for_each (it, sysctls) {
-               elem = it->elem;
-               tmp = lxc_string_replace(".", "/", elem->key);
+       list_for_each_entry_safe(sysctl, nsysctl, &conf->sysctls, head) {
+               tmp = lxc_string_replace(".", "/", sysctl->key);
                if (!tmp)
-                       return log_error(-1, "Failed to replace key %s", elem->key);
+                       return log_error(-1, "Failed to replace key %s", sysctl->key);
 
                ret = strnprintf(filename, sizeof(filename), "/proc/sys/%s", tmp);
                if (ret < 0)
                        return log_error(-1, "Error setting up sysctl parameters path");
 
-               ret = lxc_write_to_file(filename, elem->value,
-                                       strlen(elem->value), false, 0666);
+               ret = lxc_write_to_file(filename, sysctl->value,
+                                       strlen(sysctl->value), false, 0666);
                if (ret < 0)
                        return log_error_errno(-1, errno, "Failed to setup sysctl parameters %s to %s",
-                                              elem->key, elem->value);
+                                              sysctl->key, sysctl->value);
+
+               TRACE("Setting %s to %s", filename, sysctl->value);
        }
 
+       TRACE("Setup /proc/sys settings");
        return 0;
 }
 
-int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
+int setup_proc_filesystem(struct lxc_conf *conf, pid_t pid)
 {
        __do_free char *tmp = NULL;
-       struct lxc_list *it;
-       struct lxc_proc *elem;
        int ret = 0;
        char filename[PATH_MAX] = {0};
+       struct lxc_proc *proc;
 
-       lxc_list_for_each (it, procs) {
-               elem = it->elem;
-               tmp = lxc_string_replace(".", "/", elem->filename);
+       if (list_empty(&conf->procs))
+               return 0;
+
+       list_for_each_entry(proc, &conf->procs, head) {
+               tmp = lxc_string_replace(".", "/", proc->filename);
                if (!tmp)
-                       return log_error(-1, "Failed to replace key %s", elem->filename);
+                       return log_error(-1, "Failed to replace key %s", proc->filename);
 
                ret = strnprintf(filename, sizeof(filename), "/proc/%d/%s", pid, tmp);
                if (ret < 0)
                        return log_error(-1, "Error setting up proc filesystem path");
 
-               ret = lxc_write_to_file(filename, elem->value,
-                                       strlen(elem->value), false, 0666);
+               ret = lxc_write_to_file(filename, proc->value,
+                                       strlen(proc->value), false, 0666);
                if (ret < 0)
-                       return log_error_errno(-1, errno, "Failed to setup proc filesystem %s to %s", elem->filename, elem->value);
+                       return log_error_errno(-1, errno, "Failed to setup proc filesystem %s to %s",
+                                              proc->filename, proc->value);
+
+               TRACE("Setting %s to %s", filename, proc->value);
        }
 
+       TRACE("Setup /proc/%d settings", pid);
        return 0;
 }
 
@@ -3374,37 +3431,35 @@ struct lxc_conf *lxc_conf_init(void)
        new->rootfs.fd_path_pin = -EBADF;
        new->rootfs.dfd_idmapped = -EBADF;
        new->logfd = -1;
-       lxc_list_init(&new->cgroup);
-       lxc_list_init(&new->cgroup2);
+       INIT_LIST_HEAD(&new->cgroup);
+       INIT_LIST_HEAD(&new->cgroup2);
        /* Block ("allowlist") all devices by default. */
        new->bpf_devices.list_type = LXC_BPF_DEVICE_CGROUP_ALLOWLIST;
-       lxc_list_init(&(new->bpf_devices).device_item);
-       lxc_list_init(&new->network);
-       lxc_list_init(&new->mount_list);
-       lxc_list_init(&new->caps);
-       lxc_list_init(&new->keepcaps);
-       lxc_list_init(&new->id_map);
+       INIT_LIST_HEAD(&(new->bpf_devices).devices);
+       INIT_LIST_HEAD(&new->mount_entries);
+       INIT_LIST_HEAD(&new->caps.list);
+       INIT_LIST_HEAD(&new->id_map);
        new->root_nsuid_map = NULL;
        new->root_nsgid_map = NULL;
-       lxc_list_init(&new->includes);
-       lxc_list_init(&new->aliens);
-       lxc_list_init(&new->environment);
-       lxc_list_init(&new->limits);
-       lxc_list_init(&new->sysctls);
-       lxc_list_init(&new->procs);
+       INIT_LIST_HEAD(&new->environment);
+       INIT_LIST_HEAD(&new->limits);
+       INIT_LIST_HEAD(&new->sysctls);
+       INIT_LIST_HEAD(&new->procs);
        new->hooks_version = 0;
        for (i = 0; i < NUM_LXC_HOOKS; i++)
-               lxc_list_init(&new->hooks[i]);
-       lxc_list_init(&new->groups);
-       lxc_list_init(&new->state_clients);
+               INIT_LIST_HEAD(&new->hooks[i]);
+       INIT_LIST_HEAD(&new->groups);
+       INIT_LIST_HEAD(&new->state_clients);
        new->lsm_aa_profile = NULL;
-       lxc_list_init(&new->lsm_aa_raw);
+       INIT_LIST_HEAD(&new->lsm_aa_raw);
        new->lsm_se_context = NULL;
        new->lsm_se_keyring_context = NULL;
        new->keyring_disable_session = false;
        new->transient_procfs_mnt = false;
        new->shmount.path_host = NULL;
        new->shmount.path_cont = NULL;
+       new->sched_core = false;
+       new->sched_core_cookie = INVALID_SCHED_CORE_COOKIE;
 
        /* if running in a new user namespace, init and COMMAND
         * default to running as UID/GID 0 when using lxc-execute */
@@ -3416,6 +3471,8 @@ struct lxc_conf *lxc_conf_init(void)
        memset(&new->timens, 0, sizeof(struct timens_offsets));
        seccomp_conf_init(new);
 
+       INIT_LIST_HEAD(&new->netdevs);
+
        return new;
 }
 
@@ -3456,7 +3513,7 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
                return log_error_errno(-1, errno, "Failed to open \"%s\"", path);
 
        ret = lxc_write_nointr(fd, buf, buf_size);
-       if (ret != buf_size)
+       if (ret < 0 || (size_t)ret != buf_size)
                return log_error_errno(-1, errno, "Failed to write %cid mapping to \"%s\"",
                                       idtype == ID_TYPE_UID ? 'u' : 'g', path);
 
@@ -3522,24 +3579,24 @@ static int lxc_map_ids_exec_wrapper(void *args)
        return -1;
 }
 
-static struct id_map *find_mapped_hostid_entry(const struct lxc_list *idmap,
+static struct id_map *find_mapped_hostid_entry(const struct list_head *idmap,
                                               unsigned id, enum idtype idtype);
 
-int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
+int lxc_map_ids(struct list_head *idmap, pid_t pid)
 {
        int fill, left;
+       uid_t hostuid;
+       gid_t hostgid;
        char u_or_g;
        char *pos;
        char cmd_output[PATH_MAX];
        struct id_map *map;
-       struct lxc_list *iterator;
        enum idtype type;
        int ret = 0, gidmap = 0, uidmap = 0;
        char mapbuf[STRLITERALLEN("new@idmap") + STRLITERALLEN(" ") +
                    INTTYPE_TO_STRLEN(pid_t) + STRLITERALLEN(" ") +
                    LXC_IDMAPLEN] = {0};
        bool had_entry = false, maps_host_root = false, use_shadow = false;
-       int hostuid, hostgid;
 
        hostuid = geteuid();
        hostgid = getegid();
@@ -3589,10 +3646,9 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
        /* Check if we really need to use newuidmap and newgidmap.
        * If the user is only remapping their own {g,u}id, we don't need it.
        */
-       if (use_shadow && lxc_list_len(idmap) == 2) {
+       if (use_shadow && list_len(map, idmap, head) == 2) {
                use_shadow = false;
-               lxc_list_for_each(iterator, idmap) {
-                       map = iterator->elem;
+               list_for_each_entry(map, idmap, head) {
                        if (map->idtype == ID_TYPE_UID && map->range == 1 &&
                            map->nsid == hostuid && map->hostid == hostuid)
                                continue;
@@ -3611,8 +3667,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
                if (use_shadow)
                        pos += sprintf(mapbuf, "new%cidmap %d", u_or_g, pid);
 
-               lxc_list_for_each(iterator, idmap) {
-                       map = iterator->elem;
+               list_for_each_entry(map, idmap, head) {
                        if (map->idtype != type)
                                continue;
 
@@ -3666,15 +3721,13 @@ static id_t get_mapped_rootid(const struct lxc_conf *conf, enum idtype idtype)
 {
        unsigned nsid;
        struct id_map *map;
-       struct lxc_list *it;
 
        if (idtype == ID_TYPE_UID)
                nsid = (conf->root_nsuid_map != NULL) ? 0 : conf->init_uid;
        else
                nsid = (conf->root_nsgid_map != NULL) ? 0 : conf->init_gid;
 
-       lxc_list_for_each (it, &conf->id_map) {
-               map = it->elem;
+       list_for_each_entry (map, &conf->id_map, head) {
                if (map->idtype != idtype)
                        continue;
                if (map->nsid != nsid)
@@ -3691,10 +3744,8 @@ static id_t get_mapped_rootid(const struct lxc_conf *conf, enum idtype idtype)
 int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype)
 {
        struct id_map *map;
-       struct lxc_list *it;
 
-       lxc_list_for_each (it, &conf->id_map) {
-               map = it->elem;
+       list_for_each_entry(map, &conf->id_map, head) {
                if (map->idtype != idtype)
                        continue;
 
@@ -3708,12 +3759,10 @@ int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype)
 int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype)
 {
        struct id_map *map;
-       struct lxc_list *it;
        unsigned int freeid = 0;
 
 again:
-       lxc_list_for_each (it, &conf->id_map) {
-               map = it->elem;
+       list_for_each_entry(map, &conf->id_map, head) {
                if (map->idtype != idtype)
                        continue;
 
@@ -3746,7 +3795,7 @@ static int lxc_transient_proc(struct lxc_rootfs *rootfs)
                        return log_error_errno(-errno, errno, "Failed to create %d(proc)", rootfs->dfd_mnt);
 
                goto domount;
-       } else if (link_len >= sizeof(link)) {
+       } else if ((size_t)link_len >= sizeof(link)) {
                return log_error_errno(-EIO, EIO, "Truncated link target");
        }
        link[link_len] = '\0';
@@ -3950,11 +3999,11 @@ int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name,
 static bool verify_start_hooks(struct lxc_conf *conf)
 {
        char path[PATH_MAX];
-       struct lxc_list *it;
+       struct string_entry *hook;
 
-       lxc_list_for_each (it, &conf->hooks[LXCHOOK_START]) {
+       list_for_each_entry(hook, &conf->hooks[LXCHOOK_START], head) {
                int ret;
-               char *hookname = it->elem;
+               char *hookname = hook->val;
 
                ret = strnprintf(path, sizeof(path), "%s%s",
                               conf->rootfs.path ? conf->rootfs.mount : "",
@@ -4065,7 +4114,7 @@ static int lxc_rootfs_prepare_child(struct lxc_handler *handler)
        int dfd_idmapped = -EBADF;
        int ret;
 
-       if (lxc_list_empty(&handler->conf->id_map))
+       if (list_empty(&handler->conf->id_map))
                return 0;
 
        if (is_empty_string(rootfs->mnt_opts.userns_path))
@@ -4089,7 +4138,7 @@ int lxc_idmapped_mounts_parent(struct lxc_handler *handler)
 
        for (;;) {
                __do_close int fd_from = -EBADF, fd_userns = -EBADF;
-               struct lxc_mount_attr attr = {};
+               struct mount_attr attr = {};
                struct lxc_mount_options opts = {};
                ssize_t ret;
 
@@ -4100,17 +4149,17 @@ int lxc_idmapped_mounts_parent(struct lxc_handler *handler)
                        return syserror("Failed to receive idmapped mount file descriptors from child");
 
                if (fd_from < 0 || fd_userns < 0)
-                       return log_trace(0, "Finished receiving idmapped mount file descriptors from child");
+                       return log_trace(0, "Finished receiving idmapped mount file descriptors (%d | %d) from child", fd_from, fd_userns);
 
                attr.attr_set   = MOUNT_ATTR_IDMAP;
                attr.userns_fd  = fd_userns;
                ret = mount_setattr(fd_from, "",
                                    AT_EMPTY_PATH |
-                                   (opts.recursive ? AT_RECURSIVE : 0),
+                                   (opts.bind_recursively ? AT_RECURSIVE : 0),
                                    &attr, sizeof(attr));
                if (ret)
                        return syserror("Failed to idmap detached %smount %d to %d",
-                                       opts.recursive ? "recursive " : "",
+                                       opts.bind_recursively ? "recursive " : "",
                                        fd_from, fd_userns);
 
                ret = lxc_abstract_unix_send_credential(handler->data_sock[1],
@@ -4118,11 +4167,11 @@ int lxc_idmapped_mounts_parent(struct lxc_handler *handler)
                                                        sizeof(mnt_seq));
                if (ret < 0)
                        return syserror("Parent failed to notify child that detached %smount %d was idmapped to user namespace %d",
-                                       opts.recursive ? "recursive " : "",
+                                       opts.bind_recursively ? "recursive " : "",
                                        fd_from, fd_userns);
 
                TRACE("Parent idmapped detached %smount %d to user namespace %d",
-                     opts.recursive ? "recursive " : "", fd_from, fd_userns);
+                     opts.bind_recursively ? "recursive " : "", fd_from, fd_userns);
                mnt_seq++;
        }
 }
@@ -4144,14 +4193,15 @@ static int lxc_recv_ttys_from_child(struct lxc_handler *handler)
        if (!info_new->tty)
                return ret_errno(ENOMEM);
 
-       for (int i = 0; i < ttys_max; i++) {
+       for (size_t i = 0; i < ttys_max; i++) {
                terminal_info = &info_new->tty[i];
                terminal_info->busy = -1;
+               terminal_info->pty_nr = -1;
                terminal_info->ptx = -EBADF;
                terminal_info->pty = -EBADF;
        }
 
-       for (int i = 0; i < ttys_max; i++) {
+       for (size_t i = 0; i < ttys_max; i++) {
                int ptx = -EBADF, pty = -EBADF;
 
                ret = lxc_abstract_unix_recv_two_fds(sock, &ptx, &pty);
@@ -4281,6 +4331,28 @@ int lxc_sync_fds_child(struct lxc_handler *handler)
        return 0;
 }
 
+static int setup_capabilities(struct lxc_conf *conf)
+{
+       int ret;
+
+       if (conf->caps.keep)
+               ret = capabilities_allow(conf);
+       else
+               ret = capabilities_deny(conf);
+       if (ret < 0)
+               return syserror_ret(ret, "Failed to %s capabilities", conf->caps.keep ? "allow" : "deny");
+
+       return 0;
+}
+
+static int make_shmount_dependent_mount(const struct lxc_conf *conf)
+{
+       if (!(conf->auto_mounts & LXC_AUTO_SHMOUNTS_MASK))
+               return 0;
+
+       return mount(NULL, conf->shmount.path_cont, NULL, MS_REC | MS_SLAVE, 0);
+}
+
 int lxc_setup(struct lxc_handler *handler)
 {
        int ret;
@@ -4312,8 +4384,7 @@ int lxc_setup(struct lxc_handler *handler)
                if (ret < 0)
                        return log_error(-1, "Failed to receive veth names from parent");
 
-               ret = lxc_setup_network_in_child_namespaces(lxc_conf,
-                                                           &lxc_conf->network);
+               ret = lxc_setup_network_in_child_namespaces(lxc_conf);
                if (ret < 0)
                        return log_error(-1, "Failed to setup network");
        }
@@ -4335,9 +4406,8 @@ int lxc_setup(struct lxc_handler *handler)
        if (ret < 0)
                return log_error(-1, "Failed to setup mounts");
 
-       if (!lxc_list_empty(&lxc_conf->mount_list)) {
-               ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs,
-                                         &lxc_conf->mount_list, name, lxcpath);
+       if (!list_empty(&lxc_conf->mount_entries)) {
+               ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs, name, lxcpath);
                if (ret < 0)
                        return log_error(-1, "Failed to setup mount entries");
        }
@@ -4366,6 +4436,9 @@ int lxc_setup(struct lxc_handler *handler)
        if (ret < 0)
                return log_error(-1, "Failed to run mount hooks");
 
+       if (lxc_rootfs_overmounted(&lxc_conf->rootfs))
+               return log_error(-1, "Rootfs overmounted");
+
        if (lxc_conf->autodev > 0) {
                ret = run_lxc_hooks(name, "autodev", lxc_conf, NULL);
                if (ret < 0)
@@ -4409,6 +4482,11 @@ int lxc_setup(struct lxc_handler *handler)
        if (ret < 0)
                return log_error(-1, "Failed to pivot root into rootfs");
 
+       ret = make_shmount_dependent_mount(lxc_conf);
+       if (ret < 0)
+               return log_error(-1, "Failed to turn mount tunnel \"%s\" into dependent mount",
+                                lxc_conf->shmount.path_cont);
+
        /* Setting the boot-id is best-effort for now. */
        if (lxc_conf->autodev > 0)
                (void)lxc_setup_boot_id();
@@ -4421,21 +4499,13 @@ int lxc_setup(struct lxc_handler *handler)
         * key. For e.g. net.ipv4.ip_forward translated to
         * /proc/sys/net/ipv4/ip_forward.
         */
-       if (!lxc_list_empty(&lxc_conf->sysctls)) {
-               ret = setup_sysctl_parameters(&lxc_conf->sysctls);
-               if (ret < 0)
-                       return log_error(-1, "Failed to setup sysctl parameters");
-       }
-
-       if (!lxc_list_empty(&lxc_conf->keepcaps)) {
-               if (!lxc_list_empty(&lxc_conf->caps))
-                       return log_error(-1, "Container requests lxc.cap.drop and lxc.cap.keep: either use lxc.cap.drop or lxc.cap.keep, not both");
+       ret = setup_sysctl_parameters(lxc_conf);
+       if (ret < 0)
+               return log_error(-1, "Failed to setup sysctl parameters");
 
-               if (dropcaps_except(&lxc_conf->keepcaps))
-                       return log_error(-1, "Failed to keep capabilities");
-       } else if (setup_caps(&lxc_conf->caps)) {
-               return log_error(-1, "Failed to drop capabilities");
-       }
+       ret = setup_capabilities(lxc_conf);
+       if (ret < 0)
+               return log_error(-1, "Failed to setup capabilities");
 
        put_lxc_rootfs(&handler->conf->rootfs, true);
        NOTICE("The container \"%s\" is set up", name);
@@ -4446,8 +4516,8 @@ int lxc_setup(struct lxc_handler *handler)
 int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
                  char *argv[])
 {
-       struct lxc_list *it;
        int which;
+       struct string_entry *entry;
 
        for (which = 0; which < NUM_LXC_HOOKS; which ++) {
                if (strequal(hookname, lxchook_names[which]))
@@ -4457,9 +4527,9 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
        if (which >= NUM_LXC_HOOKS)
                return -1;
 
-       lxc_list_for_each (it, &conf->hooks[which]) {
+       list_for_each_entry(entry, &conf->hooks[which], head) {
                int ret;
-               char *hook = it->elem;
+               char *hook = entry->val;
 
                ret = run_script_argv(name, conf->hooks_version, "lxc", hook,
                                      hookname, argv);
@@ -4472,59 +4542,44 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
 
 int lxc_clear_config_caps(struct lxc_conf *c)
 {
-       struct lxc_list *it, *next;
+       struct cap_entry *cap, *ncap;
 
-       lxc_list_for_each_safe (it, &c->caps, next) {
-               lxc_list_del(it);
-               free(it->elem);
-               free(it);
+       list_for_each_entry_safe(cap, ncap, &c->caps.list, head) {
+               list_del(&cap->head);
+               free(cap->cap_name);
+               free(cap);
        }
 
-       lxc_list_init(&c->caps);
+       c->caps.keep = false;
+       INIT_LIST_HEAD(&c->caps.list);
        return 0;
 }
 
-static int lxc_free_idmap(struct lxc_list *id_map)
+static int lxc_free_idmap(struct list_head *id_map)
 {
-       struct lxc_list *it, *next;
+       struct id_map *map, *nmap;
 
-       lxc_list_for_each_safe(it, id_map, next) {
-               lxc_list_del(it);
-               free(it->elem);
-               free(it);
+       list_for_each_entry_safe(map, nmap, id_map, head) {
+               list_del(&map->head);
+               free(map);
        }
 
-       lxc_list_init(id_map);
+       INIT_LIST_HEAD(id_map);
        return 0;
 }
 
-static int __lxc_free_idmap(struct lxc_list *id_map)
+static int __lxc_free_idmap(struct list_head *id_map)
 {
        lxc_free_idmap(id_map);
-       free(id_map);
        return 0;
 }
-define_cleanup_function(struct lxc_list *, __lxc_free_idmap);
+define_cleanup_function(struct list_head *, __lxc_free_idmap);
 
 int lxc_clear_idmaps(struct lxc_conf *c)
 {
        return lxc_free_idmap(&c->id_map);
 }
 
-int lxc_clear_config_keepcaps(struct lxc_conf *c)
-{
-       struct lxc_list *it, *next;
-
-       lxc_list_for_each_safe (it, &c->keepcaps, next) {
-               lxc_list_del(it);
-               free(it->elem);
-               free(it);
-       }
-
-       lxc_list_init(&c->keepcaps);
-       return 0;
-}
-
 int lxc_clear_namespace(struct lxc_conf *c)
 {
        for (int i = 0; i < LXC_NS_MAX; i++)
@@ -4535,11 +4590,12 @@ int lxc_clear_namespace(struct lxc_conf *c)
 
 int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
 {
-       char *global_token, *namespaced_token;
-       size_t namespaced_token_len;
-       struct lxc_list *it, *next, *list;
        const char *k = key;
        bool all = false;
+       char *global_token, *namespaced_token;
+       size_t namespaced_token_len;
+       struct list_head *list;
+       struct lxc_cgroup *cgroup, *ncgroup;
 
        if (version == CGROUP2_SUPER_MAGIC) {
                global_token            = "lxc.cgroup2";
@@ -4562,21 +4618,18 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
        else
                return ret_errno(EINVAL);
 
-       lxc_list_for_each_safe(it, list, next) {
-               struct lxc_cgroup *cg = it->elem;
-
-               if (!all && !strequal(cg->subsystem, k))
+       list_for_each_entry_safe(cgroup, ncgroup, list, head) {
+               if (!all && !strequal(cgroup->subsystem, k))
                        continue;
 
-               lxc_list_del(it);
-               free(cg->subsystem);
-               free(cg->value);
-               free(cg);
-               free(it);
+               list_del(&cgroup->head);
+               free(cgroup->subsystem);
+               free(cgroup->value);
+               free(cgroup);
        }
 
        if (all)
-               lxc_list_init(list);
+               INIT_LIST_HEAD(list);
 
        return 0;
 }
@@ -4588,9 +4641,9 @@ static inline void lxc_clear_cgroups_devices(struct lxc_conf *conf)
 
 int lxc_clear_limits(struct lxc_conf *c, const char *key)
 {
-       struct lxc_list *it, *next;
        const char *k = NULL;
        bool all = false;
+       struct lxc_limit *lim, *nlim;
 
        if (strequal(key, "lxc.limit") || strequal(key, "lxc.prlimit"))
                all = true;
@@ -4601,30 +4654,26 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key)
        else
                return ret_errno(EINVAL);
 
-       lxc_list_for_each_safe (it, &c->limits, next) {
-               struct lxc_limit *lim = it->elem;
-
+       list_for_each_entry_safe(lim, nlim, &c->limits, head) {
                if (!all && !strequal(lim->resource, k))
                        continue;
 
-               lxc_list_del(it);
-
+               list_del(&lim->head);
                free_disarm(lim->resource);
                free(lim);
-               free(it);
        }
 
        if (all)
-               lxc_list_init(&c->limits);
+               INIT_LIST_HEAD(&c->limits);
 
        return 0;
 }
 
 int lxc_clear_sysctls(struct lxc_conf *c, const char *key)
 {
-       struct lxc_list *it, *next;
        const char *k = NULL;
        bool all = false;
+       struct lxc_sysctl *sysctl, *nsysctl;
 
        if (strequal(key, "lxc.sysctl"))
                all = true;
@@ -4633,30 +4682,27 @@ int lxc_clear_sysctls(struct lxc_conf *c, const char *key)
        else
                return -1;
 
-       lxc_list_for_each_safe(it, &c->sysctls, next) {
-               struct lxc_sysctl *elem = it->elem;
-
-               if (!all && !strequal(elem->key, k))
+       list_for_each_entry_safe(sysctl, nsysctl, &c->sysctls, head) {
+               if (!all && !strequal(sysctl->key, k))
                        continue;
 
-               lxc_list_del(it);
-               free(elem->key);
-               free(elem->value);
-               free(elem);
-               free(it);
+               list_del(&sysctl->head);
+               free(sysctl->key);
+               free(sysctl->value);
+               free(sysctl);
        }
 
        if (all)
-               lxc_list_init(&c->sysctls);
+               INIT_LIST_HEAD(&c->sysctls);
 
        return 0;
 }
 
 int lxc_clear_procs(struct lxc_conf *c, const char *key)
 {
-       struct lxc_list *it, *next;
        const char *k = NULL;
        bool all = false;
+       struct lxc_proc *proc, *nproc;
 
        if (strequal(key, "lxc.proc"))
                all = true;
@@ -4665,64 +4711,62 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key)
        else
                return -1;
 
-       lxc_list_for_each_safe(it, &c->procs, next) {
-               struct lxc_proc *proc = it->elem;
-
+       list_for_each_entry_safe(proc, nproc, &c->procs, head) {
                if (!all && !strequal(proc->filename, k))
                        continue;
 
-               lxc_list_del(it);
+               list_del(&proc->head);
                free(proc->filename);
                free(proc->value);
                free(proc);
-               free(it);
        }
 
        if (all)
-               lxc_list_init(&c->procs);
+               INIT_LIST_HEAD(&c->procs);
 
        return 0;
 }
 
 int lxc_clear_groups(struct lxc_conf *c)
 {
-       struct lxc_list *it, *next;
+       struct string_entry *entry, *nentry;
 
-       lxc_list_for_each_safe (it, &c->groups, next) {
-               lxc_list_del(it);
-               free(it->elem);
-               free(it);
+       list_for_each_entry_safe(entry, nentry, &c->groups, head) {
+               list_del(&entry->head);
+               free(entry->val);
+               free(entry);
        }
 
-       lxc_list_init(&c->groups);
+       INIT_LIST_HEAD(&c->groups);
        return 0;
 }
 
 int lxc_clear_environment(struct lxc_conf *c)
 {
-       struct lxc_list *it, *next;
+       struct environment_entry *env, *nenv;
 
-       lxc_list_for_each_safe (it, &c->environment, next) {
-               lxc_list_del(it);
-               free(it->elem);
-               free(it);
+       list_for_each_entry_safe(env, nenv, &c->environment, head) {
+               list_del(&env->head);
+               free(env->key);
+               free(env->val);
+               free(env);
        }
 
-       lxc_list_init(&c->environment);
+       INIT_LIST_HEAD(&c->environment);
        return 0;
 }
 
 int lxc_clear_mount_entries(struct lxc_conf *c)
 {
-       struct lxc_list *it, *next;
+       struct string_entry *entry, *nentry;
 
-       lxc_list_for_each_safe (it, &c->mount_list, next) {
-               lxc_list_del(it);
-               free(it->elem);
-               free(it);
+       list_for_each_entry_safe(entry, nentry, &c->mount_entries, head) {
+               list_del(&entry->head);
+               free(entry->val);
+               free(entry);
        }
 
-       lxc_list_init(&c->mount_list);
+       INIT_LIST_HEAD(&c->mount_entries);
        return 0;
 }
 
@@ -4734,9 +4778,9 @@ int lxc_clear_automounts(struct lxc_conf *c)
 
 int lxc_clear_hooks(struct lxc_conf *c, const char *key)
 {
-       struct lxc_list *it, *next;
        const char *k = NULL;
        bool all = false, done = false;
+       struct string_entry *entry, *nentry;
 
        if (strequal(key, "lxc.hook"))
                all = true;
@@ -4747,13 +4791,12 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
 
        for (int i = 0; i < NUM_LXC_HOOKS; i++) {
                if (all || strequal(k, lxchook_names[i])) {
-                       lxc_list_for_each_safe (it, &c->hooks[i], next) {
-                               lxc_list_del(it);
-                               free(it->elem);
-                               free(it);
+                       list_for_each_entry_safe(entry, nentry, &c->hooks[i], head) {
+                               list_del(&entry->head);
+                               free(entry->val);
+                               free(entry);
                        }
-                       lxc_list_init(&c->hooks[i]);
-
+                       INIT_LIST_HEAD(&c->hooks[i]);
                        done = true;
                }
        }
@@ -4764,43 +4807,17 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
        return 0;
 }
 
-static inline void lxc_clear_aliens(struct lxc_conf *conf)
-{
-       struct lxc_list *it, *next;
-
-       lxc_list_for_each_safe (it, &conf->aliens, next) {
-               lxc_list_del(it);
-               free(it->elem);
-               free(it);
-       }
-
-       lxc_list_init(&conf->aliens);
-}
-
-void lxc_clear_includes(struct lxc_conf *conf)
-{
-       struct lxc_list *it, *next;
-
-       lxc_list_for_each_safe(it, &conf->includes, next) {
-               lxc_list_del(it);
-               free(it->elem);
-               free(it);
-       }
-
-       lxc_list_init(&conf->includes);
-}
-
 int lxc_clear_apparmor_raw(struct lxc_conf *c)
 {
-       struct lxc_list *it, *next;
+       struct string_entry *entry, *nentry;
 
-       lxc_list_for_each_safe (it, &c->lsm_aa_raw, next) {
-               lxc_list_del(it);
-               free(it->elem);
-               free(it);
+       list_for_each_entry_safe(entry, nentry, &c->lsm_aa_raw, head) {
+               list_del(&entry->head);
+               free(entry->val);
+               free(entry);
        }
 
-       lxc_list_init(&c->lsm_aa_raw);
+       INIT_LIST_HEAD(&c->lsm_aa_raw);
        return 0;
 }
 
@@ -4814,7 +4831,6 @@ void lxc_conf_free(struct lxc_conf *conf)
        lxc_terminal_conf_free(&conf->console);
        free(conf->rootfs.mount);
        free(conf->rootfs.bdev_type);
-       free(conf->rootfs.options);
        free(conf->rootfs.path);
        put_lxc_rootfs(&conf->rootfs, true);
        free(conf->logfile);
@@ -4831,14 +4847,13 @@ void lxc_conf_free(struct lxc_conf *conf)
        free(conf->init_cwd);
        free(conf->unexpanded_config);
        free(conf->syslog);
-       lxc_free_networks(&conf->network);
+       lxc_free_networks(conf);
        free(conf->lsm_aa_profile);
        free(conf->lsm_aa_profile_computed);
        free(conf->lsm_se_context);
        free(conf->lsm_se_keyring_context);
        lxc_seccomp_free(&conf->seccomp);
        lxc_clear_config_caps(conf);
-       lxc_clear_config_keepcaps(conf);
        lxc_clear_cgroups(conf, "lxc.cgroup", CGROUP_SUPER_MAGIC);
        lxc_clear_cgroups(conf, "lxc.cgroup2", CGROUP2_SUPER_MAGIC);
        lxc_clear_cgroups_devices(conf);
@@ -4846,8 +4861,6 @@ void lxc_conf_free(struct lxc_conf *conf)
        lxc_clear_mount_entries(conf);
        lxc_clear_idmaps(conf);
        lxc_clear_groups(conf);
-       lxc_clear_includes(conf);
-       lxc_clear_aliens(conf);
        lxc_clear_environment(conf);
        lxc_clear_limits(conf, "lxc.prlimit");
        lxc_clear_sysctls(conf, "lxc.sysctl");
@@ -4860,6 +4873,7 @@ void lxc_conf_free(struct lxc_conf *conf)
        free(conf->cgroup_meta.container_dir);
        free(conf->cgroup_meta.namespace_dir);
        free(conf->cgroup_meta.controllers);
+       free(conf->cgroup_meta.systemd_scope);
        free(conf->shmount.path_host);
        free(conf->shmount.path_cont);
        free(conf);
@@ -4914,15 +4928,13 @@ static struct id_map *mapped_nsid_add(const struct lxc_conf *conf, unsigned id,
        return retmap;
 }
 
-static struct id_map *find_mapped_hostid_entry(const struct lxc_list *idmap,
+static struct id_map *find_mapped_hostid_entry(const struct list_head *idmap,
                                               unsigned id, enum idtype idtype)
 {
-       struct id_map *map;
-       struct lxc_list *it;
        struct id_map *retmap = NULL;
+       struct id_map *map;
 
-       lxc_list_for_each (it, idmap) {
-               map = it->elem;
+       list_for_each_entry(map, idmap, head) {
                if (map->idtype != idtype)
                        continue;
 
@@ -4968,22 +4980,20 @@ static struct id_map *mapped_hostid_add(const struct lxc_conf *conf, uid_t id,
        return move_ptr(entry);
 }
 
-static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf,
-                                         uid_t *resuid, gid_t *resgid)
+static int get_minimal_idmap(const struct lxc_conf *conf, uid_t *resuid,
+                            gid_t *resgid, struct list_head *head_ret)
 {
        __do_free struct id_map *container_root_uid = NULL,
                                *container_root_gid = NULL,
                                *host_uid_map = NULL, *host_gid_map = NULL;
-       __do_free struct lxc_list *idmap = NULL;
        uid_t euid, egid;
        uid_t nsuid = (conf->root_nsuid_map != NULL) ? 0 : conf->init_uid;
        gid_t nsgid = (conf->root_nsgid_map != NULL) ? 0 : conf->init_gid;
-       struct lxc_list *tmplist = NULL;
 
        /* Find container root mappings. */
        container_root_uid = mapped_nsid_add(conf, nsuid, ID_TYPE_UID);
        if (!container_root_uid)
-               return log_debug(NULL, "Failed to find mapping for namespace uid %d", 0);
+               return sysdebug("Failed to find mapping for namespace uid %d", 0);
        euid = geteuid();
        if (euid >= container_root_uid->hostid &&
            euid < (container_root_uid->hostid + container_root_uid->range))
@@ -4991,7 +5001,7 @@ static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf,
 
        container_root_gid = mapped_nsid_add(conf, nsgid, ID_TYPE_GID);
        if (!container_root_gid)
-               return log_debug(NULL, "Failed to find mapping for namespace gid %d", 0);
+               return sysdebug("Failed to find mapping for namespace gid %d", 0);
        egid = getegid();
        if (egid >= container_root_gid->hostid &&
            egid < (container_root_gid->hostid + container_root_gid->range))
@@ -5001,50 +5011,31 @@ static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf,
        if (!host_uid_map)
                host_uid_map = mapped_hostid_add(conf, euid, ID_TYPE_UID);
        if (!host_uid_map)
-               return log_debug(NULL, "Failed to find mapping for uid %d", euid);
+               return sysdebug("Failed to find mapping for uid %d", euid);
 
        if (!host_gid_map)
                host_gid_map = mapped_hostid_add(conf, egid, ID_TYPE_GID);
        if (!host_gid_map)
-               return log_debug(NULL, "Failed to find mapping for gid %d", egid);
+               return sysdebug("Failed to find mapping for gid %d", egid);
 
-       /* Allocate new {g,u}id map list. */
-       idmap = lxc_list_new();
-       if (!idmap)
-               return NULL;
-
-       /* Add container root to the map. */
-       tmplist = lxc_list_new();
-       if (!tmplist)
-               return NULL;
        /* idmap will now keep track of that memory. */
-       lxc_list_add_elem(tmplist, move_ptr(host_uid_map));
-       lxc_list_add_tail(idmap, tmplist);
+       list_add_tail(&host_uid_map->head, head_ret);
+       move_ptr(host_uid_map);
 
        if (container_root_uid) {
-               /* Add container root to the map. */
-               tmplist = lxc_list_new();
-               if (!tmplist)
-                       return NULL;
                /* idmap will now keep track of that memory. */
-               lxc_list_add_elem(tmplist, move_ptr(container_root_uid));
-               lxc_list_add_tail(idmap, tmplist);
+               list_add_tail(&container_root_uid->head, head_ret);
+               move_ptr(container_root_uid);
        }
 
-       tmplist = lxc_list_new();
-       if (!tmplist)
-               return NULL;
        /* idmap will now keep track of that memory. */
-       lxc_list_add_elem(tmplist, move_ptr(host_gid_map));
-       lxc_list_add_tail(idmap, tmplist);
+       list_add_tail(&host_gid_map->head, head_ret);
+       move_ptr(host_gid_map);
 
        if (container_root_gid) {
-               tmplist = lxc_list_new();
-               if (!tmplist)
-                       return NULL;
                /* idmap will now keep track of that memory. */
-               lxc_list_add_elem(tmplist, move_ptr(container_root_gid));
-               lxc_list_add_tail(idmap, tmplist);
+               list_add_tail(&container_root_gid->head, head_ret);
+               move_ptr(container_root_gid);
        }
 
        TRACE("Allocated minimal idmapping for ns uid %d and ns gid %d", nsuid, nsgid);
@@ -5053,7 +5044,8 @@ static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf,
                *resuid = nsuid;
        if (resgid)
                *resgid = nsgid;
-       return move_ptr(idmap);
+
+       return 0;
 }
 
 /*
@@ -5071,7 +5063,8 @@ static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf,
 int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data,
                  const char *fn_name)
 {
-       call_cleaner(__lxc_free_idmap) struct lxc_list *idmap = NULL;
+       LIST_HEAD(minimal_idmap);
+       call_cleaner(__lxc_free_idmap) struct list_head *idmap = &minimal_idmap;
        int ret = -1, status = -1;
        char c = '1';
        struct userns_fn_data d = {
@@ -5085,8 +5078,8 @@ int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data,
        if (!conf)
                return -EINVAL;
 
-       idmap = get_minimal_idmap(conf, NULL, NULL);
-       if (!idmap)
+       ret = get_minimal_idmap(conf, NULL, NULL, idmap);
+       if (ret)
                return ret_errno(ENOENT);
 
        ret = pipe2(pipe_fds, O_CLOEXEC);
@@ -5107,13 +5100,10 @@ int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data,
 
        if (lxc_log_trace()) {
                struct id_map *map;
-               struct lxc_list *it;
 
-               lxc_list_for_each(it, idmap) {
-                       map = it->elem;
+               list_for_each_entry(map, idmap, head)
                        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. */
@@ -5147,7 +5137,8 @@ int userns_exec_minimal(const struct lxc_conf *conf,
                        int (*fn_parent)(void *), void *fn_parent_data,
                        int (*fn_child)(void *), void *fn_child_data)
 {
-       call_cleaner(__lxc_free_idmap) struct lxc_list *idmap = NULL;
+       LIST_HEAD(minimal_idmap);
+       call_cleaner(__lxc_free_idmap) struct list_head *idmap = &minimal_idmap;
        uid_t resuid = LXC_INVALID_UID;
        gid_t resgid = LXC_INVALID_GID;
        char c = '1';
@@ -5158,8 +5149,8 @@ int userns_exec_minimal(const struct lxc_conf *conf,
        if (!conf || !fn_child)
                return ret_errno(EINVAL);
 
-       idmap = get_minimal_idmap(conf, &resuid, &resgid);
-       if (!idmap)
+       ret = get_minimal_idmap(conf, &resuid, &resgid, idmap);
+       if (ret)
                return ret_errno(ENOENT);
 
        ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sock_fds);
@@ -5221,13 +5212,10 @@ int userns_exec_minimal(const struct lxc_conf *conf,
 
        if (lxc_log_trace()) {
                struct id_map *map;
-               struct lxc_list *it;
 
-               lxc_list_for_each(it, idmap) {
-                       map = it->elem;
+               list_for_each_entry(map, idmap, head)
                        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);
-               }
        }
 
        ret = lxc_read_nointr(sock_fds[1], &c, 1);
@@ -5269,26 +5257,24 @@ on_error:
 int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
                     const char *fn_name)
 {
+       LIST_HEAD(full_idmap);
+       int ret = -1;
+       char c = '1';
+       struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
+                     *host_uid_map = NULL, *host_gid_map = NULL;
        pid_t pid;
        uid_t euid, egid;
        int p[2];
        struct id_map *map;
-       struct lxc_list *cur;
        struct userns_fn_data d;
-       int ret = -1;
-       char c = '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;
 
        if (!conf)
                return -EINVAL;
 
        ret = pipe2(p, O_CLOEXEC);
-       if (ret < 0) {
-               SYSERROR("opening pipe");
-               return -1;
-       }
+       if (ret < 0)
+               return -errno;
+
        d.fn = fn;
        d.fn_name = fn_name;
        d.arg = data;
@@ -5308,32 +5294,16 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
        euid = geteuid();
        egid = getegid();
 
-       /* Allocate new {g,u}id map list. */
-       idmap = lxc_list_new();
-       if (!idmap)
-               goto on_error;
-
        /* Find container root. */
-       lxc_list_for_each (cur, &conf->id_map) {
-               struct id_map *tmpmap;
-
-               tmplist = lxc_list_new();
-               if (!tmplist)
-                       goto on_error;
+       list_for_each_entry(map, &conf->id_map, head) {
+               __do_free struct id_map *dup_map = NULL;
 
-               tmpmap = zalloc(sizeof(*tmpmap));
-               if (!tmpmap) {
-                       free(tmplist);
+               dup_map = memdup(map, sizeof(struct id_map));
+               if (!dup_map)
                        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;
+               list_add_tail(&dup_map->head, &full_idmap);
+               move_ptr(dup_map);
 
                if (map->idtype == ID_TYPE_UID)
                        if (euid >= map->hostid && euid < map->hostid + map->range)
@@ -5382,39 +5352,27 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
        }
 
        if (host_uid_map && (host_uid_map != container_root_uid)) {
-               /* Add container root to the map. */
-               tmplist = lxc_list_new();
-               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. */
+               list_add_tail(&host_uid_map->head, &full_idmap);
+               move_ptr(host_uid_map);
        }
-       /* idmap will now keep track of that memory. */
-       host_uid_map = NULL;
 
        if (host_gid_map && (host_gid_map != container_root_gid)) {
-               tmplist = lxc_list_new();
-               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. */
+               list_add_tail(&host_gid_map->head, &full_idmap);
+               move_ptr(host_gid_map);
        }
-       /* idmap will now keep track of that memory. */
-       host_gid_map = NULL;
 
        if (lxc_log_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",
+               list_for_each_entry(map, &full_idmap, head) {
+                       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);
+       ret = lxc_map_ids(&full_idmap, pid);
        if (ret < 0) {
                ERROR("error setting up {g,u}id mappings for child process \"%d\"", pid);
                goto on_error;
@@ -5435,8 +5393,7 @@ on_error:
        if (pid > 0)
                ret = wait_for_pid(pid);
 
-       if (idmap)
-               __lxc_free_idmap(idmap);
+       __lxc_free_idmap(&full_idmap);
 
        if (host_uid_map && (host_uid_map != container_root_uid))
                free(host_uid_map);
@@ -5446,12 +5403,11 @@ on_error:
        return ret;
 }
 
-static int add_idmap_entry(struct lxc_list *idmap, enum idtype idtype,
+static int add_idmap_entry(struct list_head *idmap_list, enum idtype idtype,
                           unsigned long nsid, unsigned long hostid,
                           unsigned long range)
 {
        __do_free struct id_map *new_idmap = NULL;
-       __do_free struct lxc_list *new_list = NULL;
 
        new_idmap = zalloc(sizeof(*new_idmap));
        if (!new_idmap)
@@ -5462,12 +5418,8 @@ static int add_idmap_entry(struct lxc_list *idmap, enum idtype idtype,
        new_idmap->nsid = nsid;
        new_idmap->range = range;
 
-       new_list = zalloc(sizeof(*new_list));
-       if (!new_list)
-               return ret_errno(ENOMEM);
-
-       new_list->elem = move_ptr(new_idmap);
-       lxc_list_add_tail(idmap, move_ptr(new_list));
+       list_add_tail(&new_idmap->head, idmap_list);
+       move_ptr(new_idmap);
 
        INFO("Adding id map: type %c nsid %lu hostid %lu range %lu",
             idtype == ID_TYPE_UID ? 'u' : 'g', nsid, hostid, range);
@@ -5477,7 +5429,8 @@ static int add_idmap_entry(struct lxc_list *idmap, enum idtype idtype,
 int userns_exec_mapped_root(const char *path, int path_fd,
                            const struct lxc_conf *conf)
 {
-       call_cleaner(__lxc_free_idmap) struct lxc_list *idmap = NULL;
+       LIST_HEAD(idmap_list);
+       call_cleaner(__lxc_free_idmap) struct list_head *idmap = &idmap_list;
        __do_close int fd = -EBADF;
        int target_fd = -EBADF;
        char c = '1';
@@ -5543,10 +5496,6 @@ int userns_exec_mapped_root(const char *path, int path_fd,
                TRACE("Chowned %d(%s) to -1:%d", target_fd, path, hostgid);
        }
 
-       idmap = lxc_list_new();
-       if (!idmap)
-               return -ENOMEM;
-
        /* "u:0:rootuid:1" */
        ret = add_idmap_entry(idmap, ID_TYPE_UID, 0, container_host_uid, 1);
        if (ret < 0)
@@ -5604,11 +5553,20 @@ int userns_exec_mapped_root(const char *path, int path_fd,
 
                close_prot_errno_disarm(sock_fds[0]);
 
-               if (!lxc_switch_uid_gid(0, 0))
+               if (!lxc_drop_groups() && errno != EPERM)
+                       _exit(EXIT_FAILURE);
+
+               ret = setresgid(0, 0, 0);
+               if (ret < 0) {
+                       SYSERROR("Failed to setresgid(0, 0, 0)");
                        _exit(EXIT_FAILURE);
+               }
 
-               if (!lxc_drop_groups())
+               ret = setresuid(0, 0, 0);
+               if (ret < 0) {
+                       SYSERROR("Failed to setresuid(0, 0, 0)");
                        _exit(EXIT_FAILURE);
+               }
 
                ret = fchown(target_fd, 0, st.st_gid);
                if (ret) {
@@ -5624,13 +5582,10 @@ int userns_exec_mapped_root(const char *path, int path_fd,
 
        if (lxc_log_trace()) {
                struct id_map *map;
-               struct lxc_list *it;
 
-               lxc_list_for_each(it, idmap) {
-                       map = it->elem;
+               list_for_each_entry(map, idmap, head)
                        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);
-               }
        }
 
        ret = lxc_read_nointr(sock_fds[1], &c, 1);
@@ -5659,9 +5614,12 @@ on_error:
 
        /* Wait for child to finish. */
        if (pid < 0)
+               return log_error(-1, "Failed to create child process");
+
+       if (!wait_exited(pid))
                return -1;
 
-       return wait_for_pid(pid);
+       return 0;
 }
 
 /* not thread-safe, do not use from api without first forking */
@@ -5670,11 +5628,11 @@ static char *getuname(void)
        __do_free char *buf = NULL;
        struct passwd pwent;
        struct passwd *pwentp = NULL;
-       size_t bufsize;
+       ssize_t bufsize;
        int ret;
 
        bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
-       if (bufsize == -1)
+       if (bufsize < 0)
                bufsize = 1024;
 
        buf = zalloc(bufsize);
@@ -5698,11 +5656,11 @@ static char *getgname(void)
        __do_free char *buf = NULL;
        struct group grent;
        struct group *grentp = NULL;
-       size_t bufsize;
+       ssize_t bufsize;
        int ret;
 
        bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
-       if (bufsize == -1)
+       if (bufsize < 0)
                bufsize = 1024;
 
        buf = zalloc(bufsize);
@@ -5824,54 +5782,19 @@ void suggest_default_idmap(void)
        ERROR("lxc.idmap = g 0 %u %u", gid, grange);
 }
 
-static void free_cgroup_settings(struct lxc_list *result)
-{
-       struct lxc_list *iterator, *next;
-
-       lxc_list_for_each_safe (iterator, result, next) {
-               lxc_list_del(iterator);
-               free_disarm(iterator);
-       }
-       free_disarm(result);
-}
-
-/* Return the list of cgroup_settings sorted according to the following rules
- * 1. Put memory.limit_in_bytes before memory.memsw.limit_in_bytes
- */
-struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings)
+int lxc_set_environment(const struct lxc_conf *conf)
 {
-       struct lxc_list *result;
-       struct lxc_cgroup *cg = NULL;
-       struct lxc_list *it = NULL, *item = NULL, *memsw_limit = NULL;
+       struct environment_entry *env;
 
-       result = lxc_list_new();
-       if (!result)
-               return NULL;
-       lxc_list_init(result);
-
-       /* Iterate over the cgroup settings and copy them to the output list. */
-       lxc_list_for_each (it, cgroup_settings) {
-               item = zalloc(sizeof(*item));
-               if (!item) {
-                       free_cgroup_settings(result);
-                       return NULL;
-               }
+       list_for_each_entry(env, &conf->environment, head) {
+               int ret;
 
-               item->elem = it->elem;
-               cg = it->elem;
-               if (strequal(cg->subsystem, "memory.memsw.limit_in_bytes")) {
-                       /* Store the memsw_limit location */
-                       memsw_limit = item;
-               } else if (strequal(cg->subsystem, "memory.limit_in_bytes") &&
-                          memsw_limit != NULL) {
-                       /* 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;
-                       memsw_limit->elem = it->elem;
-               }
-               lxc_list_add_tail(result, item);
+               ret = setenv(env->key, env->val, 1);
+               if (ret < 0)
+                       return syserror("Failed to set environment variable: %s=%s",
+                                       env->key, env->val);
+               TRACE("Set environment variable: %s=%s", env->key, env->val);
        }
 
-       return result;
+       return 0;
 }