[libvirt] [PATCH sandbox 0/3] Misc patches

This is just a handful of patches for libvirt-sandbox. Traditionally I've just directly pushed code to libvirt-sandbox, but since we now have a few other people working on it, I'll start posting my patches for review first. Daniel P. Berrange (3): Support lzma and gzip compressed kernel modules Explicitly check for supported URIs when starting guests Add LIBVIRT_SANDBOX_INIT_DEBUG env variable configure.ac | 4 + libvirt-sandbox.spec.in | 2 + libvirt-sandbox/Makefile.am | 7 + .../libvirt-sandbox-builder-container.c | 3 +- libvirt-sandbox/libvirt-sandbox-builder-initrd.c | 35 ++--- libvirt-sandbox/libvirt-sandbox-builder-machine.c | 3 +- .../libvirt-sandbox-context-interactive.c | 27 ++++ libvirt-sandbox/libvirt-sandbox-init-qemu.c | 143 ++++++++++++++++++++- po/POTFILES.in | 1 + 9 files changed, 203 insertions(+), 22 deletions(-) -- 2.4.2

Modern distros like Fedora have started to compress their kernel module files, so we can't simply read the file contents and load the module. We have to first do a decompression step, as the kernel won't do that itself. While Fedora uses lzma, upstream kernels are also capable of using gzip. This links in the lzma and gzip libraries to handle decompression. NB the static versions of lzma/gzip are required since libvirt-sandbox-init-qemu must be statically linked. --- configure.ac | 4 + libvirt-sandbox.spec.in | 2 + libvirt-sandbox/Makefile.am | 7 ++ libvirt-sandbox/libvirt-sandbox-builder-initrd.c | 35 +++--- libvirt-sandbox/libvirt-sandbox-init-qemu.c | 143 ++++++++++++++++++++++- 5 files changed, 173 insertions(+), 18 deletions(-) diff --git a/configure.ac b/configure.ac index cd3745a..4f53c94 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,8 @@ LIBVIRT_GCONFIG_REQUIRED=0.1.8 LIBVIRT_GLIB_REQUIRED=0.1.7 LIBVIRT_GOBJECT_REQUIRED=0.1.7 GOBJECT_INTROSPECTION_REQUIRED=0.10.8 +LZMA_REQUIRED=5.0.0 +ZLIB_REQUIRED=1.2.0 LIBVIRT_SANDBOX_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` LIBVIRT_SANDBOX_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'` @@ -78,6 +80,8 @@ PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GLIB, libvirt-glib-1.0 >= $LIBVIRT_GOBJECT_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GOBJECT, libvirt-gobject-1.0 >= $LIBVIRT_GOBJECT_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GCONFIG, libvirt-gconfig-1.0 >= $LIBVIRT_GCONFIG_REQUIRED) +PKG_CHECK_MODULES(ZLIB, zlib >= $ZLIB_REQUIRED) +PKG_CHECK_MODULES(LZMA, liblzma >= $LZMA_REQUIRED) LIBVIRT_SANDBOX_CAPNG LIBVIRT_SANDBOX_GETTEXT diff --git a/libvirt-sandbox.spec.in b/libvirt-sandbox.spec.in index 7deadb2..1ec6e27 100644 --- a/libvirt-sandbox.spec.in +++ b/libvirt-sandbox.spec.in @@ -27,6 +27,8 @@ BuildRequires: /usr/bin/pod2man BuildRequires: intltool BuildRequires: libselinux-devel BuildRequires: glib2-devel >= 2.32.0 +BuildRequires: xz-devel >= 5.0.0, xz-static +BuildRequires: zlib-devel >= 1.2.0, zlib-static Requires: rpm-python # For virsh lxc-enter-namespace command Requires: libvirt-client >= %{libvirt_version} diff --git a/libvirt-sandbox/Makefile.am b/libvirt-sandbox/Makefile.am index 96302cb..30c9ebf 100644 --- a/libvirt-sandbox/Makefile.am +++ b/libvirt-sandbox/Makefile.am @@ -139,6 +139,7 @@ libvirt_sandbox_1_0_la_CFLAGS = \ -DLOCALEDIR="\"$(datadir)/locale"\" \ $(COVERAGE_CFLAGS) \ -I$(top_srcdir) \ + -I$(top_builddir) \ $(GIO_UNIX_CFLAGS) \ $(LIBVIRT_GLIB_CFLAGS) \ $(LIBVIRT_GOBJECT_CFLAGS) \ @@ -172,6 +173,7 @@ libvirt_sandbox_init_common_CFLAGS = \ -DLOCALEDIR="\"$(datadir)/locale"\" \ $(COVERAGE_CFLAGS) \ -I$(top_srcdir) \ + -I$(top_builddir) \ $(GIO_UNIX_CFLAGS) \ $(LIBVIRT_GLIB_CFLAGS) \ $(LIBVIRT_GOBJECT_CFLAGS) \ @@ -196,6 +198,7 @@ libvirt_sandbox_init_lxc_CFLAGS = \ -DLIBEXECDIR="\"$(libexecdir)\"" \ -DSANDBOXCONFIGDIR="\"$(sandboxconfigdir)\"" \ -I$(top_srcdir) \ + -I$(top_builddir) \ $(GIO_UNIX_CFLAGS) \ $(LIBVIRT_GLIB_CFLAGS) \ $(LIBVIRT_GOBJECT_CFLAGS) \ @@ -217,11 +220,15 @@ libvirt_sandbox_init_qemu_SOURCES = libvirt-sandbox-init-qemu.c libvirt_sandbox_init_qemu_CFLAGS = \ -DLIBEXECDIR="\"$(libexecdir)\"" \ -DSANDBOXCONFIGDIR="\"$(sandboxconfigdir)\"" \ + $(ZLIB_CFLAGS) \ + $(LZMA_CFLAGS) \ $(WARN_CFLAGS) \ $(NULL) libvirt_sandbox_init_qemu_LDFLAGS = \ -all-static \ $(COVERAGE_CFLAGS:-f%=-Wc,f%) \ + $(ZLIB_LIBS) \ + $(LZMA_LIBS) \ $(WARN_CFLAGS) \ $(NULL) diff --git a/libvirt-sandbox/libvirt-sandbox-builder-initrd.c b/libvirt-sandbox/libvirt-sandbox-builder-initrd.c index 95f05e2..59a03e6 100644 --- a/libvirt-sandbox/libvirt-sandbox-builder-initrd.c +++ b/libvirt-sandbox/libvirt-sandbox-builder-initrd.c @@ -232,7 +232,7 @@ static GList *gvir_sandbox_builder_initrd_find_files(GList *modnames, if (strstr(thisname, ".ko")) { GList *tmp = modnames; while (tmp) { - if (g_str_equal(thisname, tmp->data)) { + if (g_str_has_prefix(thisname, tmp->data)) { modfiles = g_list_append(modfiles, child); child = NULL; } @@ -293,7 +293,7 @@ static GList *gvir_sandbox_builder_initrd_find_files(GList *modnames, if (strstr(de->d_name, ".ko")) { GList *tmp = modnames; while (tmp) { - if (g_str_equal(de->d_name, tmp->data)) { + if (g_str_has_prefix(de->d_name, tmp->data)) { modfiles = g_list_append(modfiles, child); child = NULL; } @@ -366,7 +366,6 @@ static gboolean gvir_sandbox_builder_initrd_populate_tmpdir(const gchar *tmpdir, GFile *modlist = NULL; gchar *modlistpath = NULL; GOutputStream *modlistos = NULL; - GError *e = NULL; if (!gvir_sandbox_builder_initrd_copy_file( gvir_sandbox_config_initrd_get_init(config), @@ -374,11 +373,9 @@ static gboolean gvir_sandbox_builder_initrd_populate_tmpdir(const gchar *tmpdir, return FALSE; modnames = gvir_sandbox_config_initrd_get_modules(config); - modfiles = gvir_sandbox_builder_initrd_find_modules(modnames, config, &e); - if (e) { - g_propagate_error(error, e); + modfiles = gvir_sandbox_builder_initrd_find_modules(modnames, config, error); + if (*error) goto cleanup; - } tmp = modfiles; while (tmp) { @@ -404,14 +401,22 @@ static gboolean gvir_sandbox_builder_initrd_populate_tmpdir(const gchar *tmpdir, tmp = modnames; while (tmp) { - if (!g_output_stream_write_all(modlistos, - tmp->data, strlen(tmp->data), - NULL, NULL, error)) - goto cleanup; - if (!g_output_stream_write_all(modlistos, - "\n", 1, - NULL, NULL, error)) - goto cleanup; + GList *files = modfiles; + while (files) { + const gchar *basename = g_file_get_basename(files->data); + if (g_str_has_prefix(basename, tmp->data)) { + if (!g_output_stream_write_all(modlistos, + basename, strlen(basename), + NULL, NULL, error)) + goto cleanup; + if (!g_output_stream_write_all(modlistos, + "\n", 1, + NULL, NULL, error)) + goto cleanup; + break; + } + files = files->next; + } tmp = tmp->next; } diff --git a/libvirt-sandbox/libvirt-sandbox-init-qemu.c b/libvirt-sandbox/libvirt-sandbox-init-qemu.c index 750c9de..2c2c803 100644 --- a/libvirt-sandbox/libvirt-sandbox-init-qemu.c +++ b/libvirt-sandbox/libvirt-sandbox-init-qemu.c @@ -42,6 +42,8 @@ #include <fcntl.h> #include <sys/reboot.h> #include <termios.h> +#include <lzma.h> +#include <zlib.h> #define ATTR_UNUSED __attribute__((__unused__)) @@ -481,15 +483,150 @@ static char *readall(const char *filename, size_t *len) return data; } + +static int +has_suffix(const char *filename, const char *ext) +{ + char *offset = strstr(filename, ext); + return (offset && + offset[strlen(ext)] == '\0'); +} + +static char * +load_module_file_lzma(const char *filename, size_t *len) +{ + lzma_stream st = LZMA_STREAM_INIT; + char *xzdata; + size_t xzlen; + char *data; + lzma_ret ret; + + *len = 0; + + if (debug) + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); + + if ((ret = lzma_stream_decoder(&st, UINT64_MAX, + LZMA_CONCATENATED)) != LZMA_OK) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: lzma init failure: %d\n", + __func__, filename, ret); + exit_poweroff(); + } + xzdata = readall(filename, &xzlen); + + st.next_in = (unsigned char *)xzdata; + st.avail_in = xzlen; + + *len = 32 * 1024; + if (!(data = malloc(*len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + + st.next_out = (unsigned char *)data; + st.avail_out = *len; + + do { + ret = lzma_code(&st, LZMA_FINISH); + if (st.avail_out == 0) { + size_t used = *len; + *len += (32 * 1024); + if (!(data = realloc(data, *len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + st.next_out = (unsigned char *)data + used; + st.avail_out = *len - used; + } + if (ret != LZMA_OK && ret != LZMA_STREAM_END) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: lzma decode failure: %d\n", + __func__, filename, ret); + exit_poweroff(); + } + } while (ret != LZMA_STREAM_END); + lzma_end(&st); + free(xzdata); + return data; +} + +static char * +load_module_file_zlib(const char *filename, size_t *len) +{ + gzFile fp; + char *data; + unsigned int avail; + size_t total; + int got; + + if (debug) + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); + + if (!(fp = gzopen(filename, "rb"))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: gzopen failure\n", + __func__, filename); + exit_poweroff(); + } + + *len = 32 * 1024; + if (!(data = malloc(*len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + + avail = *len; + total = 0; + + do { + got = gzread(fp, data + total, avail); + + if (got < 0) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: gzread failure\n", + __func__, filename); + exit_poweroff(); + } + + total += got; + if (total >= *len) { + *len += (32 * 1024); + if (!(data = realloc(data, *len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + avail = *len - total; + } + } while (got > 0); + + gzclose(fp); + return data; +} + +static char * +load_module_file_raw(const char *filename, size_t *len) +{ + if (debug) + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); + return readall(filename, len); +} + +static char * +load_module_file(const char *filename, size_t *len) +{ + if (has_suffix(filename, ".ko.xz")) + return load_module_file_lzma(filename, len); + else if (has_suffix(filename, ".ko.gz")) + return load_module_file_zlib(filename, len); + else + return load_module_file_raw(filename, len); +} + + static void insmod(const char *filename) { char *data; size_t len; - if (debug) - fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); - data = readall(filename, &len); + data = load_module_file(filename, &len); if (init_module(data, (unsigned long)len, "") < 0) { const char *msg; -- 2.4.2

On Tue, 2015-06-16 at 12:25 +0100, Daniel P. Berrange wrote:
Modern distros like Fedora have started to compress their kernel module files, so we can't simply read the file contents and load the module. We have to first do a decompression step, as the kernel won't do that itself. While Fedora uses lzma, upstream kernels are also capable of using gzip.
This links in the lzma and gzip libraries to handle decompression. NB the static versions of lzma/gzip are required since libvirt-sandbox-init-qemu must be statically linked. --- configure.ac | 4 + libvirt-sandbox.spec.in | 2 + libvirt-sandbox/Makefile.am | 7 ++ libvirt-sandbox/libvirt-sandbox-builder-initrd.c | 35 +++--- libvirt-sandbox/libvirt-sandbox-init-qemu.c | 143 ++++++++++++++++++++++- 5 files changed, 173 insertions(+), 18 deletions(-)
diff --git a/configure.ac b/configure.ac index cd3745a..4f53c94 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,8 @@ LIBVIRT_GCONFIG_REQUIRED=0.1.8 LIBVIRT_GLIB_REQUIRED=0.1.7 LIBVIRT_GOBJECT_REQUIRED=0.1.7 GOBJECT_INTROSPECTION_REQUIRED=0.10.8 +LZMA_REQUIRED=5.0.0 +ZLIB_REQUIRED=1.2.0
LIBVIRT_SANDBOX_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` LIBVIRT_SANDBOX_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'` @@ -78,6 +80,8 @@ PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GLIB, libvirt-glib-1.0 >= $LIBVIRT_GOBJECT_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GOBJECT, libvirt-gobject-1.0 >= $LIBVIRT_GOBJECT_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GCONFIG, libvirt-gconfig-1.0 >= $LIBVIRT_GCONFIG_REQUIRED) +PKG_CHECK_MODULES(ZLIB, zlib >= $ZLIB_REQUIRED) +PKG_CHECK_MODULES(LZMA, liblzma >= $LZMA_REQUIRED)
Would be great to have some check for the presence of the static libs we need here. rkeene pointed to this example doing similar thing: http://kitcreator.rkeene.org/fossil/info/b344f06840acf86cbd6b6fdc1bd45dd649d... Even if not in this commit, would be good to have later. ACK for the rest. -- Cedric
LIBVIRT_SANDBOX_CAPNG LIBVIRT_SANDBOX_GETTEXT diff --git a/libvirt-sandbox.spec.in b/libvirt-sandbox.spec.in index 7deadb2..1ec6e27 100644 --- a/libvirt-sandbox.spec.in +++ b/libvirt-sandbox.spec.in @@ -27,6 +27,8 @@ BuildRequires: /usr/bin/pod2man BuildRequires: intltool BuildRequires: libselinux-devel BuildRequires: glib2-devel >= 2.32.0 +BuildRequires: xz-devel >= 5.0.0, xz-static +BuildRequires: zlib-devel >= 1.2.0, zlib-static Requires: rpm-python # For virsh lxc-enter-namespace command Requires: libvirt-client >= %{libvirt_version} diff --git a/libvirt-sandbox/Makefile.am b/libvirt-sandbox/Makefile.am index 96302cb..30c9ebf 100644 --- a/libvirt-sandbox/Makefile.am +++ b/libvirt-sandbox/Makefile.am @@ -139,6 +139,7 @@ libvirt_sandbox_1_0_la_CFLAGS = \ -DLOCALEDIR="\"$(datadir)/locale"\" \ $(COVERAGE_CFLAGS) \ -I$(top_srcdir) \ + -I$(top_builddir) \ $(GIO_UNIX_CFLAGS) \ $(LIBVIRT_GLIB_CFLAGS) \ $(LIBVIRT_GOBJECT_CFLAGS) \ @@ -172,6 +173,7 @@ libvirt_sandbox_init_common_CFLAGS = \ -DLOCALEDIR="\"$(datadir)/locale"\" \ $(COVERAGE_CFLAGS) \ -I$(top_srcdir) \ + -I$(top_builddir) \ $(GIO_UNIX_CFLAGS) \ $(LIBVIRT_GLIB_CFLAGS) \ $(LIBVIRT_GOBJECT_CFLAGS) \ @@ -196,6 +198,7 @@ libvirt_sandbox_init_lxc_CFLAGS = \ -DLIBEXECDIR="\"$(libexecdir)\"" \ -DSANDBOXCONFIGDIR="\"$(sandboxconfigdir)\"" \ -I$(top_srcdir) \ + -I$(top_builddir) \ $(GIO_UNIX_CFLAGS) \ $(LIBVIRT_GLIB_CFLAGS) \ $(LIBVIRT_GOBJECT_CFLAGS) \ @@ -217,11 +220,15 @@ libvirt_sandbox_init_qemu_SOURCES = libvirt-sandbox-init-qemu.c libvirt_sandbox_init_qemu_CFLAGS = \ -DLIBEXECDIR="\"$(libexecdir)\"" \ -DSANDBOXCONFIGDIR="\"$(sandboxconfigdir)\"" \ + $(ZLIB_CFLAGS) \ + $(LZMA_CFLAGS) \ $(WARN_CFLAGS) \ $(NULL) libvirt_sandbox_init_qemu_LDFLAGS = \ -all-static \ $(COVERAGE_CFLAGS:-f%=-Wc,f%) \ + $(ZLIB_LIBS) \ + $(LZMA_LIBS) \ $(WARN_CFLAGS) \ $(NULL)
diff --git a/libvirt-sandbox/libvirt-sandbox-builder-initrd.c b/libvirt-sandbox/libvirt-sandbox-builder-initrd.c index 95f05e2..59a03e6 100644 --- a/libvirt-sandbox/libvirt-sandbox-builder-initrd.c +++ b/libvirt-sandbox/libvirt-sandbox-builder-initrd.c @@ -232,7 +232,7 @@ static GList *gvir_sandbox_builder_initrd_find_files(GList *modnames, if (strstr(thisname, ".ko")) { GList *tmp = modnames; while (tmp) { - if (g_str_equal(thisname, tmp->data)) { + if (g_str_has_prefix(thisname, tmp->data)) { modfiles = g_list_append(modfiles, child); child = NULL; } @@ -293,7 +293,7 @@ static GList *gvir_sandbox_builder_initrd_find_files(GList *modnames, if (strstr(de->d_name, ".ko")) { GList *tmp = modnames; while (tmp) { - if (g_str_equal(de->d_name, tmp->data)) { + if (g_str_has_prefix(de->d_name, tmp->data)) { modfiles = g_list_append(modfiles, child); child = NULL; } @@ -366,7 +366,6 @@ static gboolean gvir_sandbox_builder_initrd_populate_tmpdir(const gchar *tmpdir, GFile *modlist = NULL; gchar *modlistpath = NULL; GOutputStream *modlistos = NULL; - GError *e = NULL;
if (!gvir_sandbox_builder_initrd_copy_file( gvir_sandbox_config_initrd_get_init(config), @@ -374,11 +373,9 @@ static gboolean gvir_sandbox_builder_initrd_populate_tmpdir(const gchar *tmpdir, return FALSE;
modnames = gvir_sandbox_config_initrd_get_modules(config); - modfiles = gvir_sandbox_builder_initrd_find_modules(modnames, config, &e); - if (e) { - g_propagate_error(error, e); + modfiles = gvir_sandbox_builder_initrd_find_modules(modnames, config, error); + if (*error) goto cleanup; - }
tmp = modfiles; while (tmp) { @@ -404,14 +401,22 @@ static gboolean gvir_sandbox_builder_initrd_populate_tmpdir(const gchar *tmpdir,
tmp = modnames; while (tmp) { - if (!g_output_stream_write_all(modlistos, - tmp->data, strlen(tmp->data), - NULL, NULL, error)) - goto cleanup; - if (!g_output_stream_write_all(modlistos, - "\n", 1, - NULL, NULL, error)) - goto cleanup; + GList *files = modfiles; + while (files) { + const gchar *basename = g_file_get_basename(files->data); + if (g_str_has_prefix(basename, tmp->data)) { + if (!g_output_stream_write_all(modlistos, + basename, strlen(basename), + NULL, NULL, error)) + goto cleanup; + if (!g_output_stream_write_all(modlistos, + "\n", 1, + NULL, NULL, error)) + goto cleanup; + break; + } + files = files->next; + } tmp = tmp->next; }
diff --git a/libvirt-sandbox/libvirt-sandbox-init-qemu.c b/libvirt-sandbox/libvirt-sandbox-init-qemu.c index 750c9de..2c2c803 100644 --- a/libvirt-sandbox/libvirt-sandbox-init-qemu.c +++ b/libvirt-sandbox/libvirt-sandbox-init-qemu.c @@ -42,6 +42,8 @@ #include <fcntl.h> #include <sys/reboot.h> #include <termios.h> +#include <lzma.h> +#include <zlib.h>
#define ATTR_UNUSED __attribute__((__unused__))
@@ -481,15 +483,150 @@ static char *readall(const char *filename, size_t *len) return data; }
+ +static int +has_suffix(const char *filename, const char *ext) +{ + char *offset = strstr(filename, ext); + return (offset && + offset[strlen(ext)] == '\0'); +} + +static char * +load_module_file_lzma(const char *filename, size_t *len) +{ + lzma_stream st = LZMA_STREAM_INIT; + char *xzdata; + size_t xzlen; + char *data; + lzma_ret ret; + + *len = 0; + + if (debug) + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); + + if ((ret = lzma_stream_decoder(&st, UINT64_MAX, + LZMA_CONCATENATED)) != LZMA_OK) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: lzma init failure: %d\n", + __func__, filename, ret); + exit_poweroff(); + } + xzdata = readall(filename, &xzlen); + + st.next_in = (unsigned char *)xzdata; + st.avail_in = xzlen; + + *len = 32 * 1024; + if (!(data = malloc(*len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + + st.next_out = (unsigned char *)data; + st.avail_out = *len; + + do { + ret = lzma_code(&st, LZMA_FINISH); + if (st.avail_out == 0) { + size_t used = *len; + *len += (32 * 1024); + if (!(data = realloc(data, *len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + st.next_out = (unsigned char *)data + used; + st.avail_out = *len - used; + } + if (ret != LZMA_OK && ret != LZMA_STREAM_END) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: lzma decode failure: %d\n", + __func__, filename, ret); + exit_poweroff(); + } + } while (ret != LZMA_STREAM_END); + lzma_end(&st); + free(xzdata); + return data; +} + +static char * +load_module_file_zlib(const char *filename, size_t *len) +{ + gzFile fp; + char *data; + unsigned int avail; + size_t total; + int got; + + if (debug) + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); + + if (!(fp = gzopen(filename, "rb"))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: gzopen failure\n", + __func__, filename); + exit_poweroff(); + } + + *len = 32 * 1024; + if (!(data = malloc(*len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + + avail = *len; + total = 0; + + do { + got = gzread(fp, data + total, avail); + + if (got < 0) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: gzread failure\n", + __func__, filename); + exit_poweroff(); + } + + total += got; + if (total >= *len) { + *len += (32 * 1024); + if (!(data = realloc(data, *len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + avail = *len - total; + } + } while (got > 0); + + gzclose(fp); + return data; +} + +static char * +load_module_file_raw(const char *filename, size_t *len) +{ + if (debug) + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); + return readall(filename, len); +} + +static char * +load_module_file(const char *filename, size_t *len) +{ + if (has_suffix(filename, ".ko.xz")) + return load_module_file_lzma(filename, len); + else if (has_suffix(filename, ".ko.gz")) + return load_module_file_zlib(filename, len); + else + return load_module_file_raw(filename, len); +} + + static void insmod(const char *filename) { char *data; size_t len; - if (debug) - fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename);
- data = readall(filename, &len); + data = load_module_file(filename, &len);
if (init_module(data, (unsigned long)len, "") < 0) { const char *msg;

While the sandbox API is designed to be hypervisor agnostic, the internal implementation needs work for each hypervisor target. To avoid user errors at runtime, do an upfront check to see if the URI they supply is suitable. Since we don't support remote executions, we do a straight string comparison on the URI, instead of just a protocol check --- .../libvirt-sandbox-context-interactive.c | 27 ++++++++++++++++++++++ po/POTFILES.in | 1 + 2 files changed, 28 insertions(+) diff --git a/libvirt-sandbox/libvirt-sandbox-context-interactive.c b/libvirt-sandbox/libvirt-sandbox-context-interactive.c index 78b2fbd..3ab63ec 100644 --- a/libvirt-sandbox/libvirt-sandbox-context-interactive.c +++ b/libvirt-sandbox/libvirt-sandbox-context-interactive.c @@ -24,6 +24,8 @@ #include <string.h> #include <errno.h> +#include <glib/gi18n.h> + #include "libvirt-sandbox/libvirt-sandbox.h" /** @@ -60,6 +62,13 @@ enum { //static gint signals[LAST_SIGNAL]; +#define GVIR_SANDBOX_CONTEXT_INTERACTIVE_ERROR gvir_sandbox_context_interactive_error_quark() + +static GQuark +gvir_sandbox_context_interactive_error_quark(void) +{ + return g_quark_from_static_string("gvir-sandbox-context-interactive"); +} static void gvir_sandbox_context_interactive_get_property(GObject *object, guint prop_id, @@ -198,6 +207,7 @@ static gboolean gvir_sandbox_context_interactive_start(GVirSandboxContext *ctxt, gchar *emptydir; gchar *configfile; gboolean ret = FALSE; + const gchar *uri; if (!GVIR_SANDBOX_CONTEXT_CLASS(gvir_sandbox_context_interactive_parent_class)->start(ctxt, error)) return FALSE; @@ -213,6 +223,23 @@ static gboolean gvir_sandbox_context_interactive_start(GVirSandboxContext *ctxt, configfile = g_build_filename(configdir, "sandbox.cfg", NULL); emptydir = g_build_filename(configdir, "empty", NULL); + uri = gvir_connection_get_uri(connection); + + if (geteuid() == 0) { + if (!g_str_equal(uri, "lxc:///") && + !g_str_equal(uri, "qemu:///system")) { + g_set_error(error, GVIR_SANDBOX_CONTEXT_INTERACTIVE_ERROR, 0, + _("Only 'lxc:///' or 'qemu:///system' URIs supported when running as root")); + goto cleanup; + } + } else { + if (!g_str_equal(uri, "qemu:///session")) { + g_set_error(error, GVIR_SANDBOX_CONTEXT_INTERACTIVE_ERROR, 0, + _("Only 'qemu:///session' URIs supported when running as non-root")); + goto cleanup; + } + } + if (!(builder = gvir_sandbox_builder_for_connection(connection, error))) goto cleanup; diff --git a/po/POTFILES.in b/po/POTFILES.in index 653abc5..11bd5e7 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -7,5 +7,6 @@ libvirt-sandbox/libvirt-sandbox-console.c libvirt-sandbox/libvirt-sandbox-console-raw.c libvirt-sandbox/libvirt-sandbox-console-rpc.c libvirt-sandbox/libvirt-sandbox-context.c +libvirt-sandbox/libvirt-sandbox-context-interactive.c libvirt-sandbox/libvirt-sandbox-init-common.c libvirt-sandbox/libvirt-sandbox-rpcpacket.c -- 2.4.2

On Tue, 2015-06-16 at 12:25 +0100, Daniel P. Berrange wrote:
While the sandbox API is designed to be hypervisor agnostic, the internal implementation needs work for each hypervisor target. To avoid user errors at runtime, do an upfront check to see if the URI they supply is suitable. Since we don't support remote executions, we do a straight string comparison on the URI, instead of just a protocol check --- .../libvirt-sandbox-context-interactive.c | 27 ++++++++++++++++++++++ po/POTFILES.in | 1 + 2 files changed, 28 insertions(+)
diff --git a/libvirt-sandbox/libvirt-sandbox-context-interactive.c b/libvirt-sandbox/libvirt-sandbox-context-interactive.c index 78b2fbd..3ab63ec 100644 --- a/libvirt-sandbox/libvirt-sandbox-context-interactive.c +++ b/libvirt-sandbox/libvirt-sandbox-context-interactive.c @@ -24,6 +24,8 @@ #include <string.h> #include <errno.h>
+#include <glib/gi18n.h> + #include "libvirt-sandbox/libvirt-sandbox.h"
/** @@ -60,6 +62,13 @@ enum {
//static gint signals[LAST_SIGNAL];
+#define GVIR_SANDBOX_CONTEXT_INTERACTIVE_ERROR gvir_sandbox_context_interactive_error_quark() + +static GQuark +gvir_sandbox_context_interactive_error_quark(void) +{ + return g_quark_from_static_string("gvir-sandbox-context-interactive"); +}
static void gvir_sandbox_context_interactive_get_property(GObject *object, guint prop_id, @@ -198,6 +207,7 @@ static gboolean gvir_sandbox_context_interactive_start(GVirSandboxContext *ctxt, gchar *emptydir; gchar *configfile; gboolean ret = FALSE; + const gchar *uri;
if (!GVIR_SANDBOX_CONTEXT_CLASS(gvir_sandbox_context_interactive_parent_class)->start(ctxt, error)) return FALSE; @@ -213,6 +223,23 @@ static gboolean gvir_sandbox_context_interactive_start(GVirSandboxContext *ctxt, configfile = g_build_filename(configdir, "sandbox.cfg", NULL); emptydir = g_build_filename(configdir, "empty", NULL);
+ uri = gvir_connection_get_uri(connection); + + if (geteuid() == 0) { + if (!g_str_equal(uri, "lxc:///") && + !g_str_equal(uri, "qemu:///system")) { + g_set_error(error, GVIR_SANDBOX_CONTEXT_INTERACTIVE_ERROR, 0, + _("Only 'lxc:///' or 'qemu:///system' URIs supported when running as root")); + goto cleanup; + } + } else { + if (!g_str_equal(uri, "qemu:///session")) { + g_set_error(error, GVIR_SANDBOX_CONTEXT_INTERACTIVE_ERROR, 0, + _("Only 'qemu:///session' URIs supported when running as non-root")); + goto cleanup; + } + } + if (!(builder = gvir_sandbox_builder_for_connection(connection, error))) goto cleanup; diff --git a/po/POTFILES.in b/po/POTFILES.in index 653abc5..11bd5e7 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -7,5 +7,6 @@ libvirt-sandbox/libvirt-sandbox-console.c libvirt-sandbox/libvirt-sandbox-console-raw.c libvirt-sandbox/libvirt-sandbox-console-rpc.c libvirt-sandbox/libvirt-sandbox-context.c +libvirt-sandbox/libvirt-sandbox-context-interactive.c libvirt-sandbox/libvirt-sandbox-init-common.c libvirt-sandbox/libvirt-sandbox-rpcpacket.c
ACK -- Cedric

Allow debugging of the init process separately from debugging of libvirt sandbox infrastructure, by using the new env var LIBVIRT_SANDBOX_INIT_DEBUG=1. --- libvirt-sandbox/libvirt-sandbox-builder-container.c | 3 +-- libvirt-sandbox/libvirt-sandbox-builder-machine.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libvirt-sandbox/libvirt-sandbox-builder-container.c b/libvirt-sandbox/libvirt-sandbox-builder-container.c index c3a58b2..8db69de 100644 --- a/libvirt-sandbox/libvirt-sandbox-builder-container.c +++ b/libvirt-sandbox/libvirt-sandbox-builder-container.c @@ -125,8 +125,7 @@ static gchar *gvir_sandbox_builder_container_cmdline(GVirSandboxConfig *config G gchar *tmp; /* Now kernel args */ - if (getenv("LIBVIRT_SANDBOX_DEBUG") && - g_str_equal(getenv("LIBVIRT_SANDBOX_DEBUG"), "2")) + if (getenv("LIBVIRT_SANDBOX_INIT_DEBUG")) g_string_append(str, "debug"); if ((tmp = getenv("LIBVIRT_SANDBOX_STRACE"))) { diff --git a/libvirt-sandbox/libvirt-sandbox-builder-machine.c b/libvirt-sandbox/libvirt-sandbox-builder-machine.c index e342ba1..c04dee9 100644 --- a/libvirt-sandbox/libvirt-sandbox-builder-machine.c +++ b/libvirt-sandbox/libvirt-sandbox-builder-machine.c @@ -232,8 +232,7 @@ static gchar *gvir_sandbox_builder_machine_cmdline(GVirSandboxConfig *config G_G /* Now kernel args */ g_string_append(str, " console=ttyS0"); - if (getenv("LIBVIRT_SANDBOX_DEBUG") && - g_str_equal(getenv("LIBVIRT_SANDBOX_DEBUG"), "2")) + if (getenv("LIBVIRT_SANDBOX_INIT_DEBUG")) g_string_append(str, " debug loglevel=10 earlyprintk=ttyS0"); else g_string_append(str, " quiet loglevel=0"); -- 2.4.2

On Tue, 2015-06-16 at 12:25 +0100, Daniel P. Berrange wrote:
Allow debugging of the init process separately from debugging of libvirt sandbox infrastructure, by using the new env var LIBVIRT_SANDBOX_INIT_DEBUG=1. --- libvirt-sandbox/libvirt-sandbox-builder-container.c | 3 +-- libvirt-sandbox/libvirt-sandbox-builder-machine.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/libvirt-sandbox/libvirt-sandbox-builder-container.c b/libvirt-sandbox/libvirt-sandbox-builder-container.c index c3a58b2..8db69de 100644 --- a/libvirt-sandbox/libvirt-sandbox-builder-container.c +++ b/libvirt-sandbox/libvirt-sandbox-builder-container.c @@ -125,8 +125,7 @@ static gchar *gvir_sandbox_builder_container_cmdline(GVirSandboxConfig *config G gchar *tmp;
/* Now kernel args */ - if (getenv("LIBVIRT_SANDBOX_DEBUG") && - g_str_equal(getenv("LIBVIRT_SANDBOX_DEBUG"), "2")) + if (getenv("LIBVIRT_SANDBOX_INIT_DEBUG")) g_string_append(str, "debug");
if ((tmp = getenv("LIBVIRT_SANDBOX_STRACE"))) { diff --git a/libvirt-sandbox/libvirt-sandbox-builder-machine.c b/libvirt-sandbox/libvirt-sandbox-builder-machine.c index e342ba1..c04dee9 100644 --- a/libvirt-sandbox/libvirt-sandbox-builder-machine.c +++ b/libvirt-sandbox/libvirt-sandbox-builder-machine.c @@ -232,8 +232,7 @@ static gchar *gvir_sandbox_builder_machine_cmdline(GVirSandboxConfig *config G_G
/* Now kernel args */ g_string_append(str, " console=ttyS0"); - if (getenv("LIBVIRT_SANDBOX_DEBUG") && - g_str_equal(getenv("LIBVIRT_SANDBOX_DEBUG"), "2")) + if (getenv("LIBVIRT_SANDBOX_INIT_DEBUG")) g_string_append(str, " debug loglevel=10 earlyprintk=ttyS0"); else g_string_append(str, " quiet loglevel=0");
ACK -- Cedric
participants (2)
-
Cedric Bosdonnat
-
Daniel P. Berrange