summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_hibernate.c
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 /sys/kern/subr_hibernate.c
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@
Diffstat (limited to 'sys/kern/subr_hibernate.c')
-rw-r--r--sys/kern/subr_hibernate.c60
1 files changed, 51 insertions, 9 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);
}
/*