X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2Flxc%2Flxccontainer.c;h=57a7adeced730cd4281a60ca2673a9a2940f53d8;hb=dfce2c76be55cd36c7e629b5d56b9b30c0a4301a;hp=0d9276492086c944a8c9adc64557a353d66192ba;hpb=af2c0fa7b1631c2d751a0a6f01dfc3c5c949ebc8;p=mirror_lxc.git diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 0d9276492..57a7adece 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -61,10 +61,12 @@ #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" @@ -72,10 +74,15 @@ #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 +#endif + /* major()/minor() */ #ifdef MAJOR_IN_MKDEV #include @@ -118,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; @@ -132,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 @@ -140,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; @@ -175,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; @@ -225,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; @@ -522,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; } @@ -538,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; } @@ -764,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) { @@ -892,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; @@ -1037,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()); @@ -1205,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); @@ -1222,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); @@ -1266,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 */ @@ -1276,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) @@ -1295,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; } @@ -1315,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; @@ -1446,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; @@ -1648,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 @@ -1691,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); @@ -1724,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; ilxc_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 @@ -1933,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); @@ -2219,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")) @@ -2253,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); @@ -2272,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); @@ -2423,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; @@ -2473,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; } @@ -2671,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; @@ -2680,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 @@ -2796,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; } @@ -2843,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. */ @@ -2878,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; @@ -3355,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); @@ -3392,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; @@ -3406,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; @@ -3416,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); @@ -3448,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; @@ -3461,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; } @@ -3496,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; } @@ -3522,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"); @@ -3555,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; @@ -3642,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; @@ -3690,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])) { @@ -3718,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)) @@ -3783,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; @@ -3797,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; } @@ -3810,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; } @@ -3859,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; } @@ -4036,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; @@ -4045,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; @@ -4084,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); @@ -4109,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; @@ -4125,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; @@ -4134,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; @@ -4197,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) { @@ -4218,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; } @@ -4258,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"); @@ -4291,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; @@ -4318,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; } @@ -4376,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; @@ -4514,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; @@ -4529,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; @@ -4558,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(); @@ -4578,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); @@ -4633,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)) { @@ -4659,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 */ @@ -4729,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; @@ -4774,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); @@ -4958,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; } @@ -4972,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) { @@ -5005,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"); @@ -5043,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")) { @@ -5057,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) @@ -5088,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) @@ -5189,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; @@ -5246,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; @@ -5313,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;