summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Larkin <mlarkin@cvs.openbsd.org>2013-04-09 18:58:04 +0000
committerMike Larkin <mlarkin@cvs.openbsd.org>2013-04-09 18:58:04 +0000
commit544774105036bd144223e6ee478a376c9f0f3c3b (patch)
tree68a16d5e5ce20ef45370b8f6a379167cb3321e5b
parente5b489474ef8d0f38cb59905768f98d4c6e2dc78 (diff)
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;