summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormlarkin <mlarkin@openbsd.org>2013-04-09 18:58:03 +0000
committermlarkin <mlarkin@openbsd.org>2013-04-09 18:58:03 +0000
commit86840a47ed254df2f605831f8286e1e5ec4fb307 (patch)
tree3692c11eaf6854568274015d57cb5ba784a04245
parentnewvers.sh uses 'basename' to determine the directory name to stamp the (diff)
downloadwireguard-openbsd-86840a47ed254df2f605831f8286e1e5ec4fb307.tar.xz
wireguard-openbsd-86840a47ed254df2f605831f8286e1e5ec4fb307.zip
Add a magic number to the head of the signature block. Check for magic
number match during signature block read during speculative unhibernate on boot. If the magic number matches but we have otherwise chosen to not unhibernate (due to kernel/memory mismatch), clear the signature block early to avoid accidentally trying to unhibernate on subsequent boots. This prevents accidental unhibernates and endless unhibernate/reboot cycles. Add a define for HIBERNATE_DEBUG for various debugging printfs (disabled by default). Finally, change some KASSERTs to warning printfs (they probably shouldn't have been KASSERTs in the first place). "looks good" deraadt@
-rw-r--r--sys/kern/subr_hibernate.c60
-rw-r--r--sys/sys/hibernate.h10
2 files changed, 60 insertions, 10 deletions
diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c
index df490f1e6d1..8a1f92c94e7 100644
--- a/sys/kern/subr_hibernate.c
+++ b/sys/kern/subr_hibernate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_hibernate.c,v 1.53 2013/03/28 16:58:45 deraadt Exp $ */
+/* $OpenBSD: subr_hibernate.c,v 1.54 2013/04/09 18:58:03 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
@@ -657,8 +657,12 @@ get_hibernate_info(union hibernate_info *hiber_info, int suspend)
hiber_info->secsize = dl.d_secsize;
/* Make sure the signature can fit in one block */
- KASSERT(sizeof(union hibernate_info) <= hiber_info->secsize);
+ if(sizeof(union hibernate_info) > hiber_info->secsize)
+ return (1);
+ /* Magic number */
+ hiber_info->magic = HIBERNATE_MAGIC;
+
/* Calculate swap offset from start of disk */
hiber_info->swap_offset = dl.d_partitions[1].p_offset;
@@ -975,16 +979,21 @@ hibernate_clear_signature(void)
union hibernate_info hiber_info;
/* Zero out a blank hiber_info */
- bzero(&blank_hiber_info, sizeof(hiber_info));
+ bzero(&blank_hiber_info, sizeof(union hibernate_info));
+ /* Get the signature block location */
if (get_hibernate_info(&hiber_info, 0))
return (1);
/* Write (zeroed) hibernate info to disk */
+#ifdef HIBERNATE_DEBUG
+ printf("clearing hibernate signature block location: %lld\n",
+ hiber_info.sig_offset - hiber_info.swap_offset);
+#endif /* HIBERNATE_DEBUG */
if (hibernate_block_io(&hiber_info,
hiber_info.sig_offset - hiber_info.swap_offset,
hiber_info.secsize, (vaddr_t)&blank_hiber_info, 1))
- panic("error hibernate write 6");
+ printf("Warning: could not clear hibernate signature\n");
return (0);
}
@@ -1030,16 +1039,30 @@ hibernate_compare_signature(union hibernate_info *mine,
{
u_int i;
- if (mine->nranges != disk->nranges)
+ if (mine->nranges != disk->nranges) {
+#ifdef HIBERNATE_DEBUG
+ printf("hibernate memory range count mismatch\n");
+#endif
return (1);
+ }
- if (strcmp(mine->kernel_version, disk->kernel_version) != 0)
+ if (strcmp(mine->kernel_version, disk->kernel_version) != 0) {
+#ifdef HIBERNATE_DEBUG
+ printf("hibernate kernel version mismatch\n");
+#endif
return (1);
+ }
for (i = 0; i < mine->nranges; i++) {
if ((mine->ranges[i].base != disk->ranges[i].base) ||
- (mine->ranges[i].end != disk->ranges[i].end) )
+ (mine->ranges[i].end != disk->ranges[i].end) ) {
+#ifdef HIBERNATE_DEBUG
+ printf("hib range %d mismatch [%p-%p != %p-%p]\n",
+ i, mine->ranges[i].base, mine->ranges[i].end,
+ disk->ranges[i].base, disk->ranges[i].end);
+#endif
return (1);
+ }
}
return (0);
@@ -1128,11 +1151,31 @@ hibernate_resume(void)
/* Read hibernate info from disk */
s = splbio();
+#ifdef HIBERNATE_DEBUG
+ printf("reading hibernate signature block location: %lld\n",
+ hiber_info.sig_offset - hiber_info.swap_offset);
+#endif /* HIBERNATE_DEBUG */
+
if (hibernate_block_io(&hiber_info,
hiber_info.sig_offset - hiber_info.swap_offset,
hiber_info.secsize, (vaddr_t)&disk_hiber_info, 0))
panic("error in hibernate read");
+ /* Check magic number */
+ if (disk_hiber_info.magic != HIBERNATE_MAGIC) {
+ splx(s);
+ return;
+ }
+
+ /*
+ * We (possibly) found a hibernate signature. Clear signature first,
+ * to prevent accidental resume or endless resume cycles later.
+ */
+ if (hibernate_clear_signature()) {
+ splx(s);
+ return;
+ }
+
/*
* If on-disk and in-memory hibernate signatures match,
* this means we should do a resume from hibernate.
@@ -1596,8 +1639,7 @@ hibernate_read_image(union hibernate_info *hiber_info)
/* Prepare the resume time pmap/page table */
hibernate_populate_resume_pt(hiber_info, image_start, image_end);
- /* Read complete, clear the signature and return */
- return hibernate_clear_signature();
+ return (0);
}
/*
diff --git a/sys/sys/hibernate.h b/sys/sys/hibernate.h
index 7e3470d0b64..fa01a982668 100644
--- a/sys/sys/hibernate.h
+++ b/sys/sys/hibernate.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hibernate.h,v 1.23 2013/01/17 02:36:45 deraadt Exp $ */
+/* $OpenBSD: hibernate.h,v 1.24 2013/04/09 18:58:03 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
@@ -24,10 +24,17 @@
#include <lib/libz/zlib.h>
#include <machine/vmparam.h>
+#if 0
+#define HIBERNATE_DEBUG
+#endif
+
#define HIBERNATE_CHUNK_USED 1
#define HIBERNATE_CHUNK_CONFLICT 2
#define HIBERNATE_CHUNK_PLACED 4
+/* Magic number used to indicate hibernate signature block */
+#define HIBERNATE_MAGIC 0x0B5D0B5D
+
struct hiballoc_entry;
/*
@@ -78,6 +85,7 @@ typedef int (*hibio_fn)(dev_t, daddr_t, vaddr_t, size_t, int, void *);
*/
union hibernate_info {
struct {
+ u_int32_t magic;
size_t nranges;
struct hibernate_memory_range ranges[VM_PHYSSEG_MAX];
size_t image_size;