|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 1/7] x86/kexec: add digest checks
From: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
During kexec load a sha256 digest is calculated of all the kexec
segments combined. This digest is stored and verified again during kexec
execution.
This is a requirement for Secure Boot to ensure that kexec data has not
been tampered with or corrupted between signature verification and
actual execution.
Only kexec crash is supported. The segments for normal kexec are stored
in temporary buffers and moved to their intended destination during
execution. To calculate/verify the normal kexec data before relocation
would involve walking the relocation table to find every temporary
buffer which was out of scope for Secure Boot work.
Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
Signed-off-by: Kevin Lampis <klampis@xxxxxxxxxx>
---
xen/common/kexec.c | 10 ++++
xen/common/kimage.c | 98 ++++++++++++++++++++++++++++++++++++++++
xen/include/xen/kimage.h | 6 +++
3 files changed, 114 insertions(+)
diff --git a/xen/common/kexec.c b/xen/common/kexec.c
index 65776a95fd..c920bc6d8a 100644
--- a/xen/common/kexec.c
+++ b/xen/common/kexec.c
@@ -383,6 +383,12 @@ void kexec_crash(enum crash_reason reason)
if ( !test_bit(KEXEC_IMAGE_CRASH_BASE + pos, &kexec_flags) )
return;
+ if ( kimage_verify_digest(kexec_image[KEXEC_IMAGE_CRASH_BASE + pos]) != 0 )
+ {
+ printk(XENLOG_ERR "kexec digest failed, won't boot corrupted image\n");
+ return;
+ }
+
kexecing = true;
if ( kexec_common_shutdown() != 0 )
@@ -1132,6 +1138,10 @@ static int kexec_load(XEN_GUEST_HANDLE_PARAM(void) uarg)
if ( ret < 0 )
goto error;
+ ret = kimage_calc_digest(kimage, kimage->digest);
+ if ( ret )
+ return ret;
+
ret = kexec_load_slot(kimage);
if ( ret < 0 )
goto error;
diff --git a/xen/common/kimage.c b/xen/common/kimage.c
index 6202491f7e..018ef66451 100644
--- a/xen/common/kimage.c
+++ b/xen/common/kimage.c
@@ -20,9 +20,12 @@
#include <xen/mm.h>
#include <xen/kexec.h>
#include <xen/kimage.h>
+#include <xen/sha2.h>
#include <asm/page.h>
+#define KIMAGE_SHA256_REGIONS 16
+
/*
* When kexec transitions to the new kernel there is a one-to-one
* mapping between physical and virtual addresses. On processors
@@ -820,6 +823,101 @@ int kimage_alloc(struct kexec_image **rimage, uint8_t
type, uint16_t arch,
return result;
}
+static int kimage_calc_one_digest(struct sha2_256_state *ctx,
+ xen_kexec_segment_t *segment)
+{
+ paddr_t dest;
+ unsigned long sbytes;
+ int ret = 0;
+
+ sbytes = segment->buf_size;
+ dest = segment->dest_maddr;
+
+ while ( sbytes )
+ {
+ unsigned long dest_mfn;
+ void *dest_va;
+ size_t schunk, dchunk;
+
+ dest_mfn = dest >> PAGE_SHIFT;
+
+ dchunk = PAGE_SIZE;
+ schunk = min(dchunk, sbytes);
+
+ dest_va = map_domain_page(_mfn(dest_mfn));
+ if ( !dest_va )
+ return -EINVAL;
+
+ sha2_256_update(ctx, dest_va, schunk);
+
+ unmap_domain_page(dest_va);
+ if ( ret )
+ return -EFAULT;
+
+ sbytes -= schunk;
+ dest += dchunk;
+ }
+ return 0;
+}
+
+int kimage_calc_digest(const struct kexec_image *image,
+ uint8_t digest[SHA2_256_DIGEST_SIZE])
+{
+ int ret;
+ struct sha2_256_state ctx;
+ unsigned int s;
+
+ if ( image->type == KEXEC_TYPE_DEFAULT )
+ {
+ /* TODO implement digest calculation for normal kexec */
+ return 0;
+ }
+
+ if ( image->nr_segments > KIMAGE_SHA256_REGIONS )
+ {
+ dprintk(XENLOG_DEBUG, "More segments than allocated SHA256 regions\n");
+ return -E2BIG;
+ }
+
+
+ sha2_256_init(&ctx);
+
+ for ( s = 0; s < image->nr_segments; s++ ) {
+ ret = kimage_calc_one_digest(&ctx, &image->segments[s]);
+ if ( ret )
+ return ret;
+ }
+
+ sha2_256_final(&ctx, digest);
+ return 0;
+}
+
+int kimage_verify_digest(const struct kexec_image *image)
+{
+ uint8_t digest[SHA2_256_DIGEST_SIZE];
+ int ret;
+
+ if ( image->type == KEXEC_TYPE_DEFAULT )
+ {
+ /* TODO implement digest check for normal kexec */
+ return 0;
+ }
+
+ ret = kimage_calc_digest(image, digest);
+ if ( ret )
+ return ret;
+
+ if ( memcmp(digest, image->digest, sizeof(digest)) != 0 )
+ {
+ printk(XENLOG_ERR "kexec digest failed expected %*phN but got %*phN\n",
+ SHA2_256_DIGEST_SIZE, image->digest,
+ SHA2_256_DIGEST_SIZE, digest);
+ return 1;
+ }
+
+ return 0;
+}
+
int kimage_load_segments(struct kexec_image *image)
{
int s;
diff --git a/xen/include/xen/kimage.h b/xen/include/xen/kimage.h
index fccba1d88d..ad52551ba2 100644
--- a/xen/include/xen/kimage.h
+++ b/xen/include/xen/kimage.h
@@ -11,6 +11,7 @@
#include <xen/list.h>
#include <xen/mm.h>
+#include <xen/sha2.h>
#include <public/kexec.h>
#define KEXEC_SEGMENT_MAX 16
@@ -37,6 +38,8 @@ struct kexec_image {
/* Address of next control page to allocate for crash kernels. */
paddr_t next_crash_page;
+
+ uint8_t digest[SHA2_256_DIGEST_SIZE];
};
int kimage_alloc(struct kexec_image **rimage, uint8_t type, uint16_t arch,
@@ -52,6 +55,9 @@ mfn_t kimage_entry_mfn(kimage_entry_t *entry, bool compat);
unsigned long kimage_entry_ind(kimage_entry_t *entry, bool compat);
int kimage_build_ind(struct kexec_image *image, mfn_t ind_mfn,
bool compat);
+int kimage_verify_digest(const struct kexec_image *image);
+int kimage_calc_digest(const struct kexec_image *image,
+ uint8_t digest[SHA2_256_DIGEST_SIZE]);
#endif /* __ASSEMBLER__ */
--
2.52.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |