]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/lxccontainer.c
Merge pull request #3059 from brauner/2019-06-21/seccomp_notify
[mirror_lxc.git] / src / lxc / lxccontainer.c
index 412fe0456c5920701fed8a90b4e2cd3eb081e36f..57a7adeced730cd4281a60ca2673a9a2940f53d8 100644 (file)
@@ -18,7 +18,9 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <errno.h>
@@ -41,6 +43,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include "../include/netns_ifaddrs.h"
 #include "af_unix.h"
 #include "api_extensions.h"
 #include "attach.h"
 #include "confile_utils.h"
 #include "criu.h"
 #include "error.h"
-#include <../include/netns_ifaddrs.h>
 #include "initutils.h"
 #include "log.h"
 #include "lxc.h"
 #include "lxccontainer.h"
 #include "lxclock.h"
+#include "memory_utils.h"
 #include "monitor.h"
 #include "namespace.h"
 #include "network.h"
 #include "parse.h"
+#include "raw_syscalls.h"
 #include "start.h"
 #include "state.h"
 #include "storage.h"
 #include "storage/overlay.h"
 #include "storage_utils.h"
 #include "sync.h"
+#include "syscall_wrappers.h"
 #include "terminal.h"
 #include "utils.h"
 #include "version.h"
 
+#if HAVE_OPENSSL
+#include <openssl/evp.h>
+#endif
+
 /* major()/minor() */
 #ifdef MAJOR_IN_MKDEV
 #include <sys/mkdev.h>
@@ -116,13 +125,13 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file)
 
 static bool config_file_exists(const char *lxcpath, const char *cname)
 {
+       __do_free char *fname = NULL;
        int ret;
        size_t len;
-       char *fname;
 
        /* $lxcpath + '/' + $cname + '/config' + \0 */
        len = strlen(lxcpath) + strlen(cname) + 9;
-       fname = alloca(len);
+       fname = must_realloc(NULL, len);
        ret = snprintf(fname, len, "%s/%s/config", lxcpath, cname);
        if (ret < 0 || (size_t)ret >= len)
                return false;
@@ -130,7 +139,8 @@ static bool config_file_exists(const char *lxcpath, const char *cname)
        return file_exists(fname);
 }
 
-/* A few functions to help detect when a container creation failed. If a
+/*
+ * A few functions to help detect when a container creation failed. If a
  * container creation was killed partway through, then trying to actually start
  * that container could harm the host. We detect this by creating a 'partial'
  * file under the container directory, and keeping an advisory lock. When
@@ -138,30 +148,39 @@ static bool config_file_exists(const char *lxcpath, const char *cname)
  * start a container, if we find that file, without a flock, we remove the
  * container.
  */
+enum {
+       LXC_CREATE_FAILED = -1,
+       LXC_CREATE_SUCCESS = 0,
+       LXC_CREATE_ONGOING = 1,
+       LXC_CREATE_INCOMPLETE = 2,
+};
+
 static int ongoing_create(struct lxc_container *c)
 {
-       int fd, ret;
-       size_t len;
-       char *path;
+       __do_close_prot_errno int fd = -EBADF;
+       __do_free char *path = NULL;
        struct flock lk = {0};
+       int ret;
+       size_t len;
 
        len = strlen(c->config_path) + strlen(c->name) + 10;
-       path = alloca(len);
+       path = must_realloc(NULL, len);
        ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
        if (ret < 0 || (size_t)ret >= len)
-               return -1;
+               return LXC_CREATE_FAILED;
 
        fd = open(path, O_RDWR | O_CLOEXEC);
        if (fd < 0) {
                if (errno != ENOENT)
-                       return -1;
+                       return LXC_CREATE_FAILED;
 
-               return 0;
+               return LXC_CREATE_SUCCESS;
        }
 
        lk.l_type = F_WRLCK;
        lk.l_whence = SEEK_SET;
-       /* F_OFD_GETLK requires that l_pid be set to 0 otherwise the kernel
+       /*
+        * F_OFD_GETLK requires that l_pid be set to 0 otherwise the kernel
         * will EINVAL us.
         */
        lk.l_pid = 0;
@@ -173,27 +192,25 @@ static int ongoing_create(struct lxc_container *c)
                        ret = 0;
        }
 
-       close(fd);
-
        /* F_OFD_GETLK will not send us back a pid so don't check it. */
        if (ret == 0)
                /* Create is still ongoing. */
-               return 1;
+               return LXC_CREATE_ONGOING;
 
        /* Create completed but partial is still there. */
-       return 2;
+       return LXC_CREATE_INCOMPLETE;
 }
 
 static int create_partial(struct lxc_container *c)
 {
+       __do_free char *path = NULL;
        int fd, ret;
        size_t len;
-       char *path;
        struct flock lk = {0};
 
        /* $lxcpath + '/' + $name + '/partial' + \0 */
        len = strlen(c->config_path) + strlen(c->name) + 10;
-       path = alloca(len);
+       path = must_realloc(NULL, len);
        ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
        if (ret < 0 || (size_t)ret >= len)
                return -1;
@@ -223,15 +240,15 @@ static int create_partial(struct lxc_container *c)
 
 static void remove_partial(struct lxc_container *c, int fd)
 {
+       __do_free char *path = NULL;
        int ret;
        size_t len;
-       char *path;
 
        close(fd);
 
        /* $lxcpath + '/' + $name + '/partial' + \0 */
        len = strlen(c->config_path) + strlen(c->name) + 10;
-       path = alloca(len);
+       path = must_realloc(NULL, len);
        ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
        if (ret < 0 || (size_t)ret >= len)
                return;
@@ -520,14 +537,14 @@ WRAP_API(bool, lxcapi_is_running)
 
 static bool do_lxcapi_freeze(struct lxc_container *c)
 {
-       int ret;
+       lxc_state_t s;
 
-       if (!c)
+       if (!c || !c->lxc_conf)
                return false;
 
-       ret = lxc_freeze(c->lxc_conf, c->name, c->config_path);
-       if (ret < 0)
-               return false;
+       s = lxc_getstate(c->name, c->config_path);
+       if (s != FROZEN)
+               return lxc_freeze(c->lxc_conf, c->name, c->config_path) == 0;
 
        return true;
 }
@@ -536,14 +553,14 @@ WRAP_API(bool, lxcapi_freeze)
 
 static bool do_lxcapi_unfreeze(struct lxc_container *c)
 {
-       int ret;
+       lxc_state_t s;
 
-       if (!c)
+       if (!c || !c->lxc_conf)
                return false;
 
-       ret = lxc_unfreeze(c->lxc_conf, c->name, c->config_path);
-       if (ret < 0)
-               return false;
+       s = lxc_getstate(c->name, c->config_path);
+       if (s == FROZEN)
+               return lxc_unfreeze(c->lxc_conf, c->name, c->config_path) == 0;
 
        return true;
 }
@@ -762,26 +779,22 @@ static void push_arg(char ***argp, char *arg, int *nargs)
 
 static char **split_init_cmd(const char *incmd)
 {
-       size_t len, retlen;
-       char *copy, *p;
+       __do_free char *copy = NULL;
+       char *p;
        char **argv;
        int nargs = 0;
 
        if (!incmd)
                return NULL;
 
-       len = strlen(incmd) + 1;
-       copy = alloca(len);
-       retlen = strlcpy(copy, incmd, len);
-       if (retlen >= len)
-               return NULL;
+       copy = must_copy_string(incmd);
 
        do {
                argv = malloc(sizeof(char *));
        } while (!argv);
 
        argv[0] = NULL;
-       lxc_iterate_parts(p, copy, " ")
+       lxc_iterate_parts (p, copy, " ")
                push_arg(&argv, p, &nargs);
 
        if (nargs == 0) {
@@ -890,13 +903,14 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
                return false;
 
        ret = ongoing_create(c);
-       if (ret < 0) {
+       switch (ret) {
+       case LXC_CREATE_FAILED:
                ERROR("Failed checking for incomplete container creation");
                return false;
-       } else if (ret == 1) {
+       case LXC_CREATE_ONGOING:
                ERROR("Ongoing container creation detected");
                return false;
-       } else if (ret == 2) {
+       case LXC_CREATE_INCOMPLETE:
                ERROR("Failed to create container");
                do_lxcapi_destroy(c);
                return false;
@@ -1035,7 +1049,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
         * right PID.
         */
        if (c->pidfile) {
-               int ret, w;
+               int w;
                char pidstr[INTTYPE_TO_STRLEN(pid_t)];
 
                w = snprintf(pidstr, sizeof(pidstr), "%d", lxc_raw_getpid());
@@ -1203,9 +1217,8 @@ WRAP_API(bool, lxcapi_stop)
 
 static int do_create_container_dir(const char *path, struct lxc_conf *conf)
 {
+       __do_free char *p = NULL;
        int lasterr;
-       size_t len;
-       char *p;
        int ret = -1;
 
        mode_t mask = umask(0002);
@@ -1220,9 +1233,7 @@ static int do_create_container_dir(const char *path, struct lxc_conf *conf)
                ret = 0;
        }
 
-       len = strlen(path);
-       p = alloca(len + 1);
-       (void)strlcpy(p, path, len + 1);
+       p = must_copy_string(path);
 
        if (!lxc_list_empty(&conf->id_map)) {
                ret = chown_mapped_root(p, conf);
@@ -1264,9 +1275,9 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
                                             const char *type,
                                             struct bdev_specs *specs)
 {
+       __do_free char *dest = NULL;
        int ret;
        size_t len;
-       char *dest;
        struct lxc_storage *bdev;
 
        /* rootfs.path or lxcpath/lxcname/rootfs */
@@ -1274,12 +1285,12 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
            (access(c->lxc_conf->rootfs.path, F_OK) == 0)) {
                const char *rpath = c->lxc_conf->rootfs.path;
                len = strlen(rpath) + 1;
-               dest = alloca(len);
+               dest = must_realloc(NULL, len);
                ret = snprintf(dest, len, "%s", rpath);
        } else {
                const char *lxcpath = do_lxcapi_get_config_path(c);
                len = strlen(c->name) + strlen(lxcpath) + 9;
-               dest = alloca(len);
+               dest = must_realloc(NULL, len);
                ret = snprintf(dest, len, "%s/%s/rootfs", lxcpath, c->name);
        }
        if (ret < 0 || (size_t)ret >= len)
@@ -1293,6 +1304,7 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
 
        if (!c->set_config_item(c, "lxc.rootfs.path", bdev->src)) {
                ERROR("Failed to set \"lxc.rootfs.path = %s\"", bdev->src);
+               storage_put(bdev);
                return NULL;
        }
 
@@ -1313,12 +1325,13 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
        return bdev;
 }
 
-static char *lxcbasename(char *path)
+/* Strip path and return name of file for argv[0] passed to execvp */
+static char *lxctemplatefilename(char *tpath)
 {
        char *p;
 
-       p = path + strlen(path) - 1;
-       while (*p != '/' && p > path)
+       p = tpath + strlen(tpath) - 1;
+       while ( (p-1) >= tpath && *(p-1) != '/')
                p--;
 
        return p;
@@ -1444,7 +1457,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath,
                newargv = malloc(nargs * sizeof(*newargv));
                if (!newargv)
                        _exit(EXIT_FAILURE);
-               newargv[0] = lxcbasename(tpath);
+               newargv[0] = lxctemplatefilename(tpath);
 
                /* --path */
                len = strlen(c->config_path) + strlen(c->name) + strlen("--path=") + 2;
@@ -1646,9 +1659,9 @@ static bool prepend_lxc_header(char *path, const char *t, char *const argv[])
        char *contents;
        FILE *f;
        int ret = -1;
-#if HAVE_LIBGNUTLS
-       int i;
-       unsigned char md_value[SHA_DIGEST_LENGTH];
+#if HAVE_OPENSSL
+       int i, md_len = 0;
+       unsigned char md_value[EVP_MAX_MD_SIZE];
        char *tpath;
 #endif
 
@@ -1689,14 +1702,14 @@ static bool prepend_lxc_header(char *path, const char *t, char *const argv[])
        if (ret < 0)
                goto out_free_contents;
 
-#if HAVE_LIBGNUTLS
+#if HAVE_OPENSSL
        tpath = get_template_path(t);
        if (!tpath) {
                ERROR("Invalid template \"%s\" specified", t);
                goto out_free_contents;
        }
 
-       ret = sha1sum_file(tpath, md_value);
+       ret = sha1sum_file(tpath, md_value, &md_len);
        if (ret < 0) {
                ERROR("Failed to get sha1sum of %s", tpath);
                free(tpath);
@@ -1722,9 +1735,9 @@ static bool prepend_lxc_header(char *path, const char *t, char *const argv[])
                fprintf(f, "\n");
        }
 
-#if HAVE_LIBGNUTLS
+#if HAVE_OPENSSL
        fprintf(f, "# Template script checksum (SHA-1): ");
-       for (i=0; i<SHA_DIGEST_LENGTH; i++)
+       for (i=0; i<md_len; i++)
                fprintf(f, "%02x", md_value[i]);
        fprintf(f, "\n");
 #endif
@@ -1792,7 +1805,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
        int partial_fd;
        mode_t mask;
        pid_t pid;
-       bool ret = false;
+       bool ret = false, rootfs_managed = true;
        char *tpath = NULL;
 
        if (!c)
@@ -1828,6 +1841,9 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
        if (!create_container_dir(c))
                goto free_tpath;
 
+       if (c->lxc_conf->rootfs.path)
+               rootfs_managed = false;
+
        /* If both template and rootfs.path are set, template is setup as
         * rootfs.path. The container is already created if we have a config and
         * rootfs.path is accessible
@@ -1931,12 +1947,21 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
 
 out_unlock:
        umask(mask);
-       if (partial_fd >= 0)
-               remove_partial(c, partial_fd);
+       remove_partial(c, partial_fd);
 
 out:
-       if (!ret)
+       if (!ret) {
+               bool reset_managed = c->lxc_conf->rootfs.managed;
+
+               /*
+                * Ensure that we don't destroy storage we didn't create
+                * ourselves.
+                */
+               if (!rootfs_managed)
+                       c->lxc_conf->rootfs.managed = false;
                container_destroy(c, NULL);
+               c->lxc_conf->rootfs.managed = reset_managed;
+       }
 
 free_tpath:
        free(tpath);
@@ -2217,6 +2242,9 @@ static inline bool enter_net_ns(struct lxc_container *c)
 {
        pid_t pid = do_lxcapi_init_pid(c);
 
+       if (pid < 0)
+               return false;
+
        if ((geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) &&
            (access("/proc/self/ns/user", F_OK) == 0))
                if (!switch_to_ns(pid, "user"))
@@ -2251,7 +2279,7 @@ static bool add_to_array(char ***names, char *cname, int pos)
        if (!newnames[pos])
                return false;
 
-       /* Sort the arrray as we will use binary search on it. */
+       /* Sort the array as we will use binary search on it. */
        qsort(newnames, pos + 1, sizeof(char *),
              (int (*)(const void *, const void *))string_cmp);
 
@@ -2270,7 +2298,7 @@ static bool add_to_clist(struct lxc_container ***list, struct lxc_container *c,
        *list = newlist;
        newlist[pos] = c;
 
-       /* Sort the arrray as we will use binary search on it. */
+       /* Sort the array as we will use binary search on it. */
        if (sort)
                qsort(newlist, pos + 1, sizeof(struct lxc_container *),
                      (int (*)(const void *, const void *))container_cmp);
@@ -2421,8 +2449,7 @@ static char **do_lxcapi_get_ips(struct lxc_container *c, const char *interface,
        if (pid == 0) {
                ssize_t nbytes;
                char addressOutputBuffer[INET6_ADDRSTRLEN];
-               int ret = 1;
-               char *address = NULL;
+               char *address_ptr = NULL;
                void *tempAddrPtr = NULL;
                struct netns_ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
 
@@ -2471,16 +2498,16 @@ static char **do_lxcapi_get_ips(struct lxc_container *c, const char *interface,
                        else if (!interface && strcmp("lo", tempIfAddr->ifa_name) == 0)
                                continue;
 
-                       address = (char *)inet_ntop(tempIfAddr->ifa_addr->sa_family,
+                       address_ptr = (char *)inet_ntop(tempIfAddr->ifa_addr->sa_family,
                                                    tempAddrPtr, addressOutputBuffer,
                                                    sizeof(addressOutputBuffer));
-                       if (!address)
+                       if (!address_ptr)
                                continue;
 
-                       nbytes = lxc_write_nointr(pipefd[1], address, INET6_ADDRSTRLEN);
+                       nbytes = lxc_write_nointr(pipefd[1], address_ptr, INET6_ADDRSTRLEN);
                        if (nbytes != INET6_ADDRSTRLEN) {
                                SYSERROR("Failed to send ipv6 address \"%s\"",
-                                        address);
+                                        address_ptr);
                                goto out;
                        }
 
@@ -2669,8 +2696,8 @@ static bool mod_rdep(struct lxc_container *c0, struct lxc_container *c, bool inc
        struct stat fbuf;
        void *buf = NULL;
        char *del = NULL;
-       char path[MAXPATHLEN];
-       char newpath[MAXPATHLEN];
+       char path[PATH_MAX];
+       char newpath[PATH_MAX];
        int fd, ret, n = 0, v = 0;
        bool bret = false;
        size_t len = 0, bytes = 0;
@@ -2678,12 +2705,12 @@ static bool mod_rdep(struct lxc_container *c0, struct lxc_container *c, bool inc
        if (container_disk_lock(c0))
                return false;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
-       if (ret < 0 || ret > MAXPATHLEN)
+       ret = snprintf(path, PATH_MAX, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
+       if (ret < 0 || ret > PATH_MAX)
                goto out;
 
-       ret = snprintf(newpath, MAXPATHLEN, "%s\n%s\n", c->config_path, c->name);
-       if (ret < 0 || ret > MAXPATHLEN)
+       ret = snprintf(newpath, PATH_MAX, "%s\n%s\n", c->config_path, c->name);
+       if (ret < 0 || ret > PATH_MAX)
                goto out;
 
        /* If we find an lxc-snapshot file using the old format only listing the
@@ -2794,14 +2821,14 @@ out:
 void mod_all_rdeps(struct lxc_container *c, bool inc)
 {
        struct lxc_container *p;
-       char *lxcpath = NULL, *lxcname = NULL, path[MAXPATHLEN];
+       char *lxcpath = NULL, *lxcname = NULL, path[PATH_MAX];
        size_t pathlen = 0, namelen = 0;
        FILE *f;
        int ret;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends",
+       ret = snprintf(path, PATH_MAX, "%s/%s/lxc_rdepends",
                c->config_path, c->name);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       if (ret < 0 || ret >= PATH_MAX) {
                ERROR("Path name too long");
                return;
        }
@@ -2841,14 +2868,14 @@ out:
 static bool has_fs_snapshots(struct lxc_container *c)
 {
        FILE *f;
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
        int ret, v;
        struct stat fbuf;
        bool bret = false;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
+       ret = snprintf(path, PATH_MAX, "%s/%s/lxc_snapshots", c->config_path,
                        c->name);
-       if (ret < 0 || ret > MAXPATHLEN)
+       if (ret < 0 || ret > PATH_MAX)
                goto out;
 
        /* If the file doesn't exist there are no snapshots. */
@@ -2876,7 +2903,7 @@ out:
 
 static bool has_snapshots(struct lxc_container *c)
 {
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
        struct dirent *direntp;
        int count=0;
        DIR *dir;
@@ -3353,7 +3380,7 @@ static int copy_file(const char *old, const char *new)
                return -1;
        }
 
-       while (1) {
+       for (;;) {
                len = lxc_read_nointr(in, buf, 8096);
                if (len < 0) {
                        SYSERROR("Error reading old file %s", old);
@@ -3390,12 +3417,12 @@ err:
 
 static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
 {
+       __do_free char *cpath = NULL;
        int i, len, ret;
        struct lxc_list *it;
-       char *cpath;
 
        len = strlen(oldc->config_path) + strlen(oldc->name) + 3;
-       cpath = alloca(len);
+       cpath = must_realloc(NULL, len);
        ret = snprintf(cpath, len, "%s/%s/", oldc->config_path, oldc->name);
        if (ret < 0 || ret >= len)
                return -1;
@@ -3404,7 +3431,7 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
                lxc_list_for_each(it, &c->lxc_conf->hooks[i]) {
                        char *hookname = it->elem;
                        char *fname = strrchr(hookname, '/');
-                       char tmppath[MAXPATHLEN];
+                       char tmppath[PATH_MAX];
                        if (!fname) /* relative path - we don't support, but maybe we should */
                                return 0;
 
@@ -3414,9 +3441,9 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
                        }
 
                        /* copy the script, and change the entry in confile */
-                       ret = snprintf(tmppath, MAXPATHLEN, "%s/%s/%s",
+                       ret = snprintf(tmppath, PATH_MAX, "%s/%s/%s",
                                        c->config_path, c->name, fname+1);
-                       if (ret < 0 || ret >= MAXPATHLEN)
+                       if (ret < 0 || ret >= PATH_MAX)
                                return -1;
 
                        ret = copy_file(it->elem, tmppath);
@@ -3446,7 +3473,7 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
 
 static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c)
 {
-       char newpath[MAXPATHLEN];
+       char newpath[PATH_MAX];
        char *oldpath = oldc->lxc_conf->fstab;
        int ret;
 
@@ -3459,9 +3486,9 @@ static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c)
        if (!p)
                return -1;
 
-       ret = snprintf(newpath, MAXPATHLEN, "%s/%s%s",
+       ret = snprintf(newpath, PATH_MAX, "%s/%s%s",
                        c->config_path, c->name, p);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       if (ret < 0 || ret >= PATH_MAX) {
                ERROR("error printing new path for %s", oldpath);
                return -1;
        }
@@ -3494,19 +3521,19 @@ static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c)
 
 static void copy_rdepends(struct lxc_container *c, struct lxc_container *c0)
 {
-       char path0[MAXPATHLEN], path1[MAXPATHLEN];
+       char path0[PATH_MAX], path1[PATH_MAX];
        int ret;
 
-       ret = snprintf(path0, MAXPATHLEN, "%s/%s/lxc_rdepends", c0->config_path,
+       ret = snprintf(path0, PATH_MAX, "%s/%s/lxc_rdepends", c0->config_path,
                c0->name);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       if (ret < 0 || ret >= PATH_MAX) {
                WARN("Error copying reverse dependencies");
                return;
        }
 
-       ret = snprintf(path1, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
+       ret = snprintf(path1, PATH_MAX, "%s/%s/lxc_rdepends", c->config_path,
                c->name);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       if (ret < 0 || ret >= PATH_MAX) {
                WARN("Error copying reverse dependencies");
                return;
        }
@@ -3520,13 +3547,13 @@ static void copy_rdepends(struct lxc_container *c, struct lxc_container *c0)
 static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0)
 {
        int ret;
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
        FILE *f;
        bool bret;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
+       ret = snprintf(path, PATH_MAX, "%s/%s/lxc_rdepends", c->config_path,
                c->name);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       if (ret < 0 || ret >= PATH_MAX)
                return false;
 
        f = fopen(path, "a");
@@ -3553,13 +3580,14 @@ static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0)
 bool should_default_to_snapshot(struct lxc_container *c0,
                                struct lxc_container *c1)
 {
+       __do_free char *p0 = NULL, *p1 = NULL;
        int ret;
        size_t l0 = strlen(c0->config_path) + strlen(c0->name) + 2;
        size_t l1 = strlen(c1->config_path) + strlen(c1->name) + 2;
-       char *p0 = alloca(l0 + 1);
-       char *p1 = alloca(l1 + 1);
        char *rootfs = c0->lxc_conf->rootfs.path;
 
+       p0 = must_realloc(NULL, l0 + 1);
+       p1 = must_realloc(NULL, l1 + 1);
        ret = snprintf(p0, l0, "%s/%s", c0->config_path, c0->name);
        if (ret < 0 || ret >= l0)
                return false;
@@ -3640,7 +3668,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
        int flags = data->flags;
        char **hookargs = data->hookargs;
        int ret = -1;
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
        struct lxc_storage *bdev;
        FILE *fout;
        struct lxc_conf *conf = c->lxc_conf;
@@ -3688,7 +3716,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
                }
        } else { /* TODO come up with a better way */
                free(bdev->dest);
-               bdev->dest = strdup(bdev->src);
+               bdev->dest = strdup(lxc_storage_get_path(bdev->src, bdev->type));
        }
 
        if (!lxc_list_empty(&conf->hooks[LXCHOOK_CLONE])) {
@@ -3716,10 +3744,10 @@ static int clone_update_rootfs(struct clone_update_data *data)
        }
 
        if (!(flags & LXC_CLONE_KEEPNAME)) {
-               ret = snprintf(path, MAXPATHLEN, "%s/etc/hostname", bdev->dest);
+               ret = snprintf(path, PATH_MAX, "%s/etc/hostname", bdev->dest);
                storage_put(bdev);
 
-               if (ret < 0 || ret >= MAXPATHLEN)
+               if (ret < 0 || ret >= PATH_MAX)
                        return -1;
 
                if (!file_exists(path))
@@ -3781,7 +3809,7 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
                const char *bdevtype, const char *bdevdata, uint64_t newsize,
                char **hookargs)
 {
-       char newpath[MAXPATHLEN];
+       char newpath[PATH_MAX];
        int fd, ret;
        struct clone_update_data data;
        size_t saved_unexp_len;
@@ -3795,9 +3823,8 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
 
        if (container_mem_lock(c))
                return NULL;
-
-       if (!is_stopped(c)) {
-               ERROR("error: Original container (%s) is running", c->name);
+       if (!is_stopped(c) && !(flags & LXC_CLONE_ALLOW_RUNNING)) {
+               ERROR("error: Original container (%s) is running. Use --allowrunning if you want to force a snapshot of the running container.", c->name);
                goto out;
        }
 
@@ -3808,8 +3835,8 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
        if (!lxcpath)
                lxcpath = do_lxcapi_get_config_path(c);
 
-       ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", lxcpath, newname);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       ret = snprintf(newpath, PATH_MAX, "%s/%s/config", lxcpath, newname);
+       if (ret < 0 || ret >= PATH_MAX) {
                SYSERROR("clone: failed making config pathname");
                goto out;
        }
@@ -3857,8 +3884,8 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
        saved_unexp_conf = NULL;
        c->lxc_conf->unexpanded_len = saved_unexp_len;
 
-       ret = snprintf(newpath, MAXPATHLEN, "%s/%s/rootfs", lxcpath, newname);
-       if (ret < 0 || ret >= MAXPATHLEN) {
+       ret = snprintf(newpath, PATH_MAX, "%s/%s/rootfs", lxcpath, newname);
+       if (ret < 0 || ret >= PATH_MAX) {
                SYSERROR("clone: failed making rootfs pathname");
                goto out;
        }
@@ -4034,7 +4061,9 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
 
 WRAP_API_1(bool, lxcapi_rename, const char *)
 
-static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process)
+static int lxcapi_attach(struct lxc_container *c,
+                        lxc_attach_exec_t exec_function, void *exec_payload,
+                        lxc_attach_options_t *options, pid_t *attached_process)
 {
        int ret;
 
@@ -4043,33 +4072,37 @@ static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_functio
 
        current_config = c->lxc_conf;
 
-       ret = lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
+       ret = lxc_attach(c, exec_function, exec_payload, options,
+                        attached_process);
        current_config = NULL;
        return ret;
 }
 
-static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
+static int do_lxcapi_attach_run_wait(struct lxc_container *c,
+                                    lxc_attach_options_t *options,
+                                    const char *program,
+                                    const char *const argv[])
 {
        lxc_attach_command_t command;
        pid_t pid;
-       int r;
+       int ret;
 
        if (!c)
                return -1;
 
-       command.program = (char*)program;
-       command.argv = (char**)argv;
+       command.program = (char *)program;
+       command.argv = (char **)argv;
 
-       r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, &command, options, &pid);
-       if (r < 0) {
-               ERROR("ups");
-               return r;
-       }
+       ret = lxc_attach(c, lxc_attach_run_command, &command, options, &pid);
+       if (ret < 0)
+               return ret;
 
        return lxc_wait_for_pid_status(pid);
 }
 
-static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
+static int lxcapi_attach_run_wait(struct lxc_container *c,
+                                 lxc_attach_options_t *options,
+                                 const char *program, const char *const argv[])
 {
        int ret;
 
@@ -4082,13 +4115,13 @@ static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t
 
 static int get_next_index(const char *lxcpath, char *cname)
 {
-       char *fname;
+       __do_free char *fname = NULL;
        struct stat sb;
        int i = 0, ret;
 
-       fname = alloca(strlen(lxcpath) + 20);
+       fname = must_realloc(NULL, strlen(lxcpath) + 20);
 
-       while (1) {
+       for (;;) {
                sprintf(fname, "%s/snap%d", lxcpath, i);
 
                ret = stat(fname, &sb);
@@ -4107,13 +4140,13 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath)
         * If the old style snapshot path exists, use it
         * /var/lib/lxc -> /var/lib/lxcsnaps
         */
-       ret = snprintf(snappath, MAXPATHLEN, "%ssnaps", c->config_path);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       ret = snprintf(snappath, PATH_MAX, "%ssnaps", c->config_path);
+       if (ret < 0 || ret >= PATH_MAX)
                return false;
 
        if (dir_exists(snappath)) {
-               ret = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
-               if (ret < 0 || ret >= MAXPATHLEN)
+               ret = snprintf(snappath, PATH_MAX, "%ssnaps/%s", c->config_path, c->name);
+               if (ret < 0 || ret >= PATH_MAX)
                        return false;
 
                return true;
@@ -4123,8 +4156,8 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath)
         * Use the new style path
         * /var/lib/lxc -> /var/lib/lxc + c->name + /snaps + \0
         */
-       ret = snprintf(snappath, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       ret = snprintf(snappath, PATH_MAX, "%s/%s/snaps", c->config_path, c->name);
+       if (ret < 0 || ret >= PATH_MAX)
                return false;
 
        return true;
@@ -4132,11 +4165,12 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath)
 
 static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
 {
+       __do_free char *dfnam = NULL;
        int i, flags, ret;
        time_t timer;
        struct tm tm_info;
        struct lxc_container *c2;
-       char snappath[MAXPATHLEN], newname[20];
+       char snappath[PATH_MAX], newname[20];
        char buffer[25];
        FILE *f;
 
@@ -4195,7 +4229,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
 
        strftime(buffer, 25, "%Y:%m:%d %H:%M:%S", &tm_info);
 
-       char *dfnam = alloca(strlen(snappath) + strlen(newname) + 5);
+       dfnam = must_realloc(NULL, strlen(snappath) + strlen(newname) + 5);
        sprintf(dfnam, "%s/%s/ts", snappath, newname);
        f = fopen(dfnam, "w");
        if (!f) {
@@ -4216,10 +4250,11 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
        }
 
        if (commentfile) {
+               __do_free char *path = NULL;
                /* $p / $name / comment \0 */
                int len = strlen(snappath) + strlen(newname) + 10;
-               char *path = alloca(len);
 
+               path = must_realloc(NULL, len);
                sprintf(path, "%s/%s/comment", snappath, newname);
                return copy_file(commentfile, path) < 0 ? -1 : i;
        }
@@ -4256,12 +4291,12 @@ static char *get_snapcomment_path(char* snappath, char *name)
 
 static char *get_timestamp(char* snappath, char *name)
 {
-       char path[MAXPATHLEN], *s = NULL;
+       char path[PATH_MAX], *s = NULL;
        int ret, len;
        FILE *fin;
 
-       ret = snprintf(path, MAXPATHLEN, "%s/%s/ts", snappath, name);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       ret = snprintf(path, PATH_MAX, "%s/%s/ts", snappath, name);
+       if (ret < 0 || ret >= PATH_MAX)
                return NULL;
 
        fin = fopen(path, "r");
@@ -4289,7 +4324,7 @@ static char *get_timestamp(char* snappath, char *name)
 
 static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps)
 {
-       char snappath[MAXPATHLEN], path2[MAXPATHLEN];
+       char snappath[PATH_MAX], path2[PATH_MAX];
        int count = 0, ret;
        struct dirent *direntp;
        struct lxc_snapshot *snaps =NULL, *nsnaps;
@@ -4316,8 +4351,8 @@ static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot
                if (!strcmp(direntp->d_name, ".."))
                        continue;
 
-               ret = snprintf(path2, MAXPATHLEN, "%s/%s/config", snappath, direntp->d_name);
-               if (ret < 0 || ret >= MAXPATHLEN) {
+               ret = snprintf(path2, PATH_MAX, "%s/%s/config", snappath, direntp->d_name);
+               if (ret < 0 || ret >= PATH_MAX) {
                        ERROR("pathname too long");
                        goto out_free;
                }
@@ -4374,7 +4409,7 @@ WRAP_API_1(int, lxcapi_snapshot_list, struct lxc_snapshot **)
 
 static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname)
 {
-       char clonelxcpath[MAXPATHLEN];
+       char clonelxcpath[PATH_MAX];
        int flags = 0;
        struct lxc_container *snap, *rest;
        struct lxc_storage *bdev;
@@ -4512,7 +4547,7 @@ static bool remove_all_snapshots(const char *path)
 
 static bool do_lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname)
 {
-       char clonelxcpath[MAXPATHLEN];
+       char clonelxcpath[PATH_MAX];
 
        if (!c || !c->name || !c->config_path || !snapname)
                return false;
@@ -4527,7 +4562,7 @@ WRAP_API_1(bool, lxcapi_snapshot_destroy, const char *)
 
 static bool do_lxcapi_snapshot_destroy_all(struct lxc_container *c)
 {
-       char clonelxcpath[MAXPATHLEN];
+       char clonelxcpath[PATH_MAX];
 
        if (!c || !c->name || !c->config_path)
                return false;
@@ -4556,7 +4591,7 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
        int ret;
        char *tmp;
        pid_t pid;
-       char chrootpath[MAXPATHLEN];
+       char chrootpath[PATH_MAX];
        char *directory_path = NULL;
 
        pid = fork();
@@ -4576,8 +4611,8 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
        }
 
        /* prepare the path */
-       ret = snprintf(chrootpath, MAXPATHLEN, "/proc/%d/root", init_pid);
-       if (ret < 0 || ret >= MAXPATHLEN)
+       ret = snprintf(chrootpath, PATH_MAX, "/proc/%d/root", init_pid);
+       if (ret < 0 || ret >= PATH_MAX)
                return false;
 
        ret = chroot(chrootpath);
@@ -4631,6 +4666,7 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
        struct stat st;
        char value[LXC_MAX_BUFFER];
        const char *p;
+       pid_t init_pid;
 
        /* make sure container is running */
        if (!do_lxcapi_is_running(c)) {
@@ -4657,7 +4693,13 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
        if (ret < 0 || ret >= LXC_MAX_BUFFER)
                return false;
 
-       if (!do_add_remove_node(do_lxcapi_init_pid(c), p, add, &st))
+       init_pid = do_lxcapi_init_pid(c);
+       if (init_pid < 0) {
+               ERROR("Failed to get init pid");
+               return false;
+       }
+
+       if (!do_add_remove_node(init_pid, p, add, &st))
                return false;
 
        /* add or remove device to/from cgroup access list */
@@ -4727,6 +4769,11 @@ static bool do_lxcapi_attach_interface(struct lxc_container *c,
        }
 
        init_pid = do_lxcapi_init_pid(c);
+       if (init_pid < 0) {
+               ERROR("Failed to get init pid");
+               goto err;
+       }
+
        ret = lxc_netdev_move_by_name(ifname, init_pid, dst_ifname);
        if (ret)
                goto err;
@@ -4772,6 +4819,10 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c,
                pid_t init_pid;
 
                init_pid = do_lxcapi_init_pid(c);
+               if (init_pid < 0) {
+                       ERROR("Failed to get init pid");
+                       _exit(EXIT_FAILURE);
+               }
                if (!switch_to_ns(init_pid, "net")) {
                        ERROR("Failed to enter network namespace");
                        _exit(EXIT_FAILURE);
@@ -4956,7 +5007,10 @@ static int create_mount_target(const char *dest, mode_t st_mode)
                ret = mkdir(dest, 0000);
        else
                ret = mknod(dest, S_IFREG | 0000, 0);
-       if (ret < 0) {
+
+       if (ret == 0)
+               TRACE("Created mount target \"%s\"", dest);
+       else if (ret < 0 && errno != EEXIST) {
                SYSERROR("Failed to create mount target \"%s\"", dest);
                return -1;
        }
@@ -4970,9 +5024,10 @@ static int do_lxcapi_mount(struct lxc_container *c, const char *source,
                           struct lxc_mount *mnt)
 {
        char *suff, *sret;
-       char template[MAXPATHLEN], path[MAXPATHLEN];
+       char template[PATH_MAX], path[PATH_MAX];
        pid_t pid, init_pid;
        struct stat sb;
+       bool is_dir;
        int ret = -1, fd = -EBADF;
 
        if (!c || !c->lxc_conf) {
@@ -5003,7 +5058,8 @@ static int do_lxcapi_mount(struct lxc_container *c, const char *source,
                }
        }
 
-       if (S_ISDIR(sb.st_mode)) {
+       is_dir = (S_ISDIR(sb.st_mode) != 0);
+       if (is_dir) {
                sret = mkdtemp(template);
                if (!sret) {
                        SYSERROR("Could not create shmounts temporary dir");
@@ -5041,10 +5097,13 @@ static int do_lxcapi_mount(struct lxc_container *c, const char *source,
 
                /* Enter the container namespaces */
                if (!lxc_list_empty(&c->lxc_conf->id_map)) {
-                       if (!switch_to_ns(init_pid, "user")){
+                       if (!switch_to_ns(init_pid, "user")) {
                                ERROR("Failed to enter user namespace");
                                _exit(EXIT_FAILURE);
                        }
+
+                       if (!lxc_switch_uid_gid(0, 0))
+                               _exit(EXIT_FAILURE);
                }
 
                if (!switch_to_ns(init_pid, "mnt")) {
@@ -5055,7 +5114,6 @@ static int do_lxcapi_mount(struct lxc_container *c, const char *source,
                ret = create_mount_target(target, sb.st_mode);
                if (ret < 0)
                        _exit(EXIT_FAILURE);
-               TRACE("Created mount target \"%s\"", target);
 
                suff = strrchr(template, '/');
                if (!suff)
@@ -5086,7 +5144,10 @@ static int do_lxcapi_mount(struct lxc_container *c, const char *source,
        ret = 0;
 
        (void)umount2(template, MNT_DETACH);
-       (void)unlink(template);
+       if (is_dir)
+               (void)rmdir(template);
+       else
+               (void)unlink(template);
 
 out:
        if (fd >= 0)
@@ -5187,10 +5248,21 @@ out:
        return ret;
 }
 
+static int do_lxcapi_seccomp_notify_fd(struct lxc_container *c)
+{
+       if (!c || !c->lxc_conf)
+               return minus_one_set_errno(-EINVAL);
+
+       return lxc_seccomp_get_notify_fd(&c->lxc_conf->seccomp);
+}
+
+WRAP_API(int, lxcapi_seccomp_notify_fd)
+
 struct lxc_container *lxc_container_new(const char *name, const char *configpath)
 {
        struct lxc_container *c;
        size_t len;
+       int rc;
 
        if (!name)
                return NULL;
@@ -5244,10 +5316,24 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
                goto err;
        }
 
-       if (ongoing_create(c) == 2) {
-               ERROR("Failed to complete container creation for %s", c->name);
+       rc = ongoing_create(c);
+       switch (rc) {
+       case LXC_CREATE_INCOMPLETE:
+               SYSERROR("Failed to complete container creation for %s", c->name);
                container_destroy(c, NULL);
                lxcapi_clear_config(c);
+               break;
+       case LXC_CREATE_ONGOING:
+               /* container creation going on */
+               break;
+       case LXC_CREATE_FAILED:
+               /* container creation failed */
+               if (errno != EACCES && errno != EPERM) {
+                       /* insufficient privileges */
+                       SYSERROR("Failed checking for incomplete container %s creation", c->name);
+                       goto err;
+               }
+               break;
        }
 
        c->daemonize = true;
@@ -5311,6 +5397,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
        c->console_log = lxcapi_console_log;
        c->mount = lxcapi_mount;
        c->umount = lxcapi_umount;
+       c->seccomp_notify_fd = lxcapi_seccomp_notify_fd;
 
        return c;