[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [RFC v1] kexec: Prototype for signature verification within Xen



On Mon, Jan 14, 2019 at 01:52:07PM -0600, Eric DeVolder wrote:
> These changes work in conjunction with the signature
> verification support for Xen I published recently.
> 
> Prior to this change, kexec supported the following
> three modes of operation:
> 
> kexec_load:
> - unverified loading of kernel into Linux (original mode)
> - unverified loading of kernel into Xen
> kexec_file_load (the -s option to kexec):
> - verified loading of kernel into Linux
> 
> With the verified loading of a kernel into Linux, the scope
> of kexec changed drastically as the kernel performs most of
> the work that kexec previously did; the kernel does so so as
> to reduce the risk of compromise.
> 
> For example, the unverified loading of a kernel into Linux
> involves locating memory within the system to load the
> various pieces of data (kernel, initramdisk, command line)
> as well as reserving additional memory such as the first 1MB
> on x86 for legacy reasons as well as something known as
> 'purgatory', a trampoline that checks the integrity of the
> contents of loaded pieces of data, before invoking that
> loaded kernel. The management of purgatory involves
> manipulating an embedded ELF purgatory object file to insert
> a memory hash value, and rewrite a few run-time switches
> based on kexec command line parameters.
> 
> By contrast, the verified loading essentially just passes
> file handles for the kernel, initramdisk, and command line
> pointer, and the kernel takes care of the rest, by
> performing all the work that the unverified kexec load would
> do, but inside the kernel using trusted kernel code.
> 
> This changeset adds a fourth mode to kexec:
> 
> - verified loading of kernel into Xen
> 
> In general, Xen performs the signature verification on the
> loaded kernel, much as Linux does, but that is where the
> similarities end.  In the current Xen implementation, no
> infrastructure is present to support reading from [Linux
> dom0] file handles, or for manipulating ELF objects. As
> such, without Xen support for these actions, Xen relies upon
> kexec to provide these services, which is what this mode
> does.
> 
> To achieve this, this mode of operation essentially vectors
> the verified load for Xen through the non-verified path,
> which performs all the needed actions for kexec to work, but
> then makes an adjustment to pass the entire kernel file, not
> just the loadable portion of the kernel file, to Xen in
> order to provide the proper image for signature
> verification.
> 
> The loading of kexec images for signature verification for
> Xen is indicated with the -s switch, just like for Linux.
> 
> Changes to configure.ac are for detecting whether or not the
> Xen version supports this kexec_file_load hypercall op.
> 
> Changes to kexec-bzImage64.c are for recording what the
> change to the kernel image entry needs to be (the entire
> kernel file, not just the loadable portion), as well as
> vectoring kexec_file_load through kexec_load for Xen.
> 
> Changes to kexec-xen.c are to invoke the new Xen
> kexec_file_load hypercall op, from kexec_load.
> 
> Changes to kexec.c are to vector kexec_file_load for Xen
> throgh kexec_load for Xen, as well as make the correction
> for passing the complete kernel file to Xen.
> 
> Signed-off-by: Eric DeVolder <eric.devolder@xxxxxxxxxx>

Thanks Eric,

this looks good to me, aside from one nit below.

> ---
>  configure.ac                        |  8 ++++++++
>  kexec/arch/x86_64/kexec-bzImage64.c | 18 ++++++++++++++++++
>  kexec/kexec-xen.c                   |  7 +++++++
>  kexec/kexec.c                       | 38 
> +++++++++++++++++++++++++++++++++++++
>  4 files changed, 71 insertions(+)
> 
> diff --git a/configure.ac b/configure.ac
> index e05d601..a11787b 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -190,6 +190,14 @@ if test "$ac_cv_lib_xenctrl_xc_kexec_load" = yes ; then
>               AC_MSG_NOTICE([The kexec_status call is not available]))
>  fi
>  
> +dnl Check for the Xen kexec_status hypercall - reachable from 
> --with-xen=yes|dl
> +if test "$ac_cv_lib_xenctrl_xc_kexec_load" = yes ; then
> +     AC_CHECK_LIB(xenctrl, xc_kexec_file_load,
> +             AC_DEFINE(HAVE_XEN_KEXEC_FILE_LOAD, 1,
> +                     [The Xen kexec_file_load call is available]),
> +             AC_MSG_NOTICE([The Xen kexec_file_load call is not available]))
> +fi
> +
>  dnl ---Sanity checks
>  if test "$CC"      = "no"; then AC_MSG_ERROR([cc not found]); fi
>  if test "$CPP"     = "no"; then AC_MSG_ERROR([cpp not found]); fi
> diff --git a/kexec/arch/x86_64/kexec-bzImage64.c 
> b/kexec/arch/x86_64/kexec-bzImage64.c
> index 8edb3e4..98e9d50 100644
> --- a/kexec/arch/x86_64/kexec-bzImage64.c
> +++ b/kexec/arch/x86_64/kexec-bzImage64.c
> @@ -207,6 +207,20 @@ static int do_bzImage64_load(struct kexec_info *info,
>       align = real_mode->kernel_alignment;
>       addr = add_buffer(info, kernel + kern16_size, k_size,
>                         size, align, 0x100000, -1, -1);
> +#ifdef HAVE_XEN_KEXEC_FILE_LOAD
> +    if (xen_present() && info->file_mode)
> +    {
> +        /* Record info for post-purgatory hash computation replacement with 
> kernel file */
> +        extern char *original_kernel;
> +        extern off_t original_kernel_len;
> +        extern char *replacement_kernel;
> +        extern off_t replacement_kernel_len;
> +        original_kernel = kernel + kern16_size;
> +        original_kernel_len = k_size;
> +        replacement_kernel = kernel;
> +        replacement_kernel_len = kernel_len;
> +    }
> +#endif
>       if (addr == ULONG_MAX)
>               die("can not load bzImage64");
>       dbgprintf("Loaded 64bit kernel at 0x%lx\n", addr);
> @@ -330,7 +344,11 @@ int bzImage64_load(int argc, char **argv, const char 
> *buf, off_t len,
>       int opt;
>       int result;
>  
> +#ifdef HAVE_XEN_KEXEC_FILE_LOAD
> +     if (info->file_mode && !xen_present())
> +#else
>       if (info->file_mode)
> +#endif

>               return bzImage64_load_file(argc, argv, info);
>  
>       /* See options.h -- add any more there, too. */
> diff --git a/kexec/kexec-xen.c b/kexec/kexec-xen.c
> index 1887390..2a59d62 100644
> --- a/kexec/kexec-xen.c
> +++ b/kexec/kexec-xen.c
> @@ -124,8 +124,15 @@ int xen_kexec_load(struct kexec_info *info)
>               arch = EM_386;
>  #endif
>  
> +#ifdef HAVE_XEN_KEXEC_FILE_LOAD
> +    if (info->file_mode)
> +     ret = xc_kexec_file_load(xch, type, arch, (uint64_t)info->entry,
> +                         nr_segments, xen_segs);
> +    else
> +#else
>       ret = xc_kexec_load(xch, type, arch, (uint64_t)info->entry,
>                           nr_segments, xen_segs);
> +#endif
>  
>  out:
>       xc_hypercall_buffer_array_destroy(xch, array);
> diff --git a/kexec/kexec.c b/kexec/kexec.c
> index 32ae56c..80a4905 100644
> --- a/kexec/kexec.c
> +++ b/kexec/kexec.c
> @@ -61,6 +61,13 @@ static unsigned long kexec_flags = 0;
>  /* Flags for kexec file (fd) based syscall */
>  static unsigned long kexec_file_flags = 0;
>  int kexec_debug = 0;
> +#ifdef HAVE_XEN_KEXEC_FILE_LOAD
> +static int do_kexec_file_syscall = 0;
> +char *original_kernel = NULL;
> +off_t original_kernel_len = 0;
> +char *replacement_kernel = NULL;
> +off_t replacement_kernel_len = 0;
> +#endif
>  
>  void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int 
> nr_mr)
>  {
> @@ -690,6 +697,24 @@ static void update_purgatory(struct kexec_info *info)
>                          sizeof(region));
>       elf_rel_set_symbol(&info->rhdr, "sha256_digest", &digest,
>                          sizeof(digest));
> +#ifdef HAVE_XEN_KEXEC_FILE_LOAD
> +    /* Now that purgatory hash computed, replace kernel loadable segment 
> with entire kernel file for Xen to process */
> +    if (xen_present() && info->file_mode)
> +    {

Minor nit: could we use "if (x) {" rather than  having the "{" on a new
line?

> +        if (original_kernel && original_kernel_len)
> +        {
> +             for(i = 0; i < info->nr_segments; i++) {
> +                if ((info->segment[i].buf == original_kernel) &&
> +                    (info->segment[i].bufsz == original_kernel_len))
> +                {
> +                    info->segment[i].buf = replacement_kernel;
> +                    info->segment[i].bufsz = replacement_kernel_len;
> +                    break;
> +                }
> +            }
> +        }
> +    }
> +#endif
>  }
>  
>  /*
> @@ -710,6 +735,9 @@ static int my_load(const char *type, int fileind, int 
> argc, char **argv,
>       memset(&info, 0, sizeof(info));
>       info.kexec_flags = kexec_flags;
>       info.skip_checks = skip_checks;
> +#ifdef HAVE_XEN_KEXEC_FILE_LOAD
> +     info.file_mode = do_kexec_file_syscall;
> +#endif
>  
>       result = 0;
>       if (argc - fileind <= 0) {
> @@ -1260,7 +1288,9 @@ int main(int argc, char *argv[])
>       int do_ifdown = 0, skip_ifdown = 0;
>       int do_unload = 0;
>       int do_reuse_initrd = 0;
> +#ifndef HAVE_XEN_KEXEC_FILE_LOAD
>       int do_kexec_file_syscall = 0;
> +#endif
>       int do_kexec_fallback = 0;
>       int skip_checks = 0;
>       int do_status = 0;
> @@ -1489,7 +1519,11 @@ int main(int argc, char *argv[])
>                       result = k_unload(kexec_flags);
>       }
>       if (do_load && (result == 0)) {
> +#ifdef HAVE_XEN_KEXEC_FILE_LOAD
> +             if (do_kexec_file_syscall && !xen_present()) {
> +#else
>               if (do_kexec_file_syscall) {
> +#endif
>                       result = do_kexec_file_load(fileind, argc, argv,
>                                                kexec_file_flags);
>                       if (do_kexec_fallback) switch (result) {
> @@ -1533,7 +1567,11 @@ int main(int argc, char *argv[])
>                                       break;
>                       }
>               }
> +#ifdef HAVE_XEN_KEXEC_FILE_LOAD
> +             if (!do_kexec_file_syscall || xen_present())
> +#else
>               if (!do_kexec_file_syscall)
> +#endif
>                       result = my_load(type, fileind, argc, argv,
>                                               kexec_flags, skip_checks, 
> entry);
>       }
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> kexec mailing list
> kexec@xxxxxxxxxxxxxxxxxxx
> http://lists.infradead.org/mailman/listinfo/kexec
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.