]> 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 06384f0692335c1e4e3414d5c57900b6653a91da..57a7adeced730cd4281a60ca2673a9a2940f53d8 100644 (file)
@@ -61,6 +61,7 @@
 #include "lxc.h"
 #include "lxccontainer.h"
 #include "lxclock.h"
+#include "memory_utils.h"
 #include "monitor.h"
 #include "namespace.h"
 #include "network.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>
@@ -120,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;
@@ -134,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
@@ -142,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;
@@ -177,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;
@@ -227,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;
@@ -524,7 +537,6 @@ WRAP_API(bool, lxcapi_is_running)
 
 static bool do_lxcapi_freeze(struct lxc_container *c)
 {
-       int ret;
        lxc_state_t s;
 
        if (!c || !c->lxc_conf)
@@ -541,7 +553,6 @@ WRAP_API(bool, lxcapi_freeze)
 
 static bool do_lxcapi_unfreeze(struct lxc_container *c)
 {
-       int ret;
        lxc_state_t s;
 
        if (!c || !c->lxc_conf)
@@ -768,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) {
@@ -896,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;
@@ -1209,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);
@@ -1226,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);
@@ -1270,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 */
@@ -1280,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)
@@ -1299,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;
        }
 
@@ -1319,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;
@@ -1450,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;
@@ -1652,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
 
@@ -1695,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);
@@ -1728,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
@@ -2235,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"))
@@ -3370,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);
@@ -3407,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;
@@ -3570,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;
@@ -4050,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;
 
@@ -4059,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;
 
@@ -4098,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);
@@ -4148,6 +4165,7 @@ 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;
@@ -4211,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) {
@@ -4232,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;
        }
@@ -4647,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)) {
@@ -4673,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 */
@@ -4743,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;
@@ -4788,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);
@@ -4972,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;
        }
@@ -5076,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)
@@ -5211,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;
@@ -5268,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;
@@ -5335,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;