diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2013-04-09 18:58:04 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2013-04-09 18:58:04 +0000 |
commit | 544774105036bd144223e6ee478a376c9f0f3c3b (patch) | |
tree | 68a16d5e5ce20ef45370b8f6a379167cb3321e5b | |
parent | e5b489474ef8d0f38cb59905768f98d4c6e2dc78 (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.c | 60 | ||||
-rw-r--r-- | sys/sys/hibernate.h | 10 |
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; |