]> 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 fee73c44399a7efbc8f3d1acf69cc97d5d49f85f..57a7adeced730cd4281a60ca2673a9a2940f53d8 100644 (file)
 #include "utils.h"
 #include "version.h"
 
+#if HAVE_OPENSSL
+#include <openssl/evp.h>
+#endif
+
 /* major()/minor() */
 #ifdef MAJOR_IN_MKDEV
 #include <sys/mkdev.h>
@@ -121,7 +125,7 @@ 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;
+       __do_free char *fname = NULL;
        int ret;
        size_t len;
 
@@ -135,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
@@ -143,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)
 {
-       __do_free char *path;
-       int fd, ret;
-       size_t len;
+       __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 = 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;
@@ -178,20 +192,18 @@ 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;
+       __do_free char *path = NULL;
        int fd, ret;
        size_t len;
        struct flock lk = {0};
@@ -228,7 +240,7 @@ static int create_partial(struct lxc_container *c)
 
 static void remove_partial(struct lxc_container *c, int fd)
 {
-       __do_free char *path;
+       __do_free char *path = NULL;
        int ret;
        size_t len;
 
@@ -525,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)
@@ -542,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)
@@ -893,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;
@@ -1208,7 +1219,6 @@ static int do_create_container_dir(const char *path, struct lxc_conf *conf)
 {
        __do_free char *p = NULL;
        int lasterr;
-       size_t len;
        int ret = -1;
 
        mode_t mask = umask(0002);
@@ -1265,7 +1275,7 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
                                             const char *type,
                                             struct bdev_specs *specs)
 {
-       __do_free char *dest;
+       __do_free char *dest = NULL;
        int ret;
        size_t len;
        struct lxc_storage *bdev;
@@ -1294,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;
        }
 
@@ -1314,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;
@@ -1445,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;
@@ -1647,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
 
@@ -1690,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);
@@ -1723,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
@@ -2230,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"))
@@ -3402,7 +3417,7 @@ err:
 
 static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
 {
-       __do_free char *cpath;
+       __do_free char *cpath = NULL;
        int i, len, ret;
        struct lxc_list *it;
 
@@ -3565,7 +3580,7 @@ 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, *p1;
+       __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;
@@ -4046,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;
 
@@ -4055,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;
 
@@ -4094,7 +4115,7 @@ static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t
 
 static int get_next_index(const char *lxcpath, char *cname)
 {
-       __do_free char *fname;
+       __do_free char *fname = NULL;
        struct stat sb;
        int i = 0, ret;
 
@@ -4229,7 +4250,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
        }
 
        if (commentfile) {
-               __do_free char *path;
+               __do_free char *path = NULL;
                /* $p / $name / comment \0 */
                int len = strlen(snappath) + strlen(newname) + 10;
 
@@ -4645,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)) {
@@ -4671,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 */
@@ -4741,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;
@@ -4786,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);
@@ -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;