[libvirt] [PATCH sandbox 1/3] Support lzma and gzip compressed kernel modules
Cedric Bosdonnat
cbosdonnat at suse.com
Tue Jun 16 14:57:10 UTC 2015
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/b344f06840acf86cbd6b6fdc1bd45dd649db9ad2?ln=113-154
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;
More information about the libvir-list
mailing list