[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