From 116c1678527c1ea643b48023d3ed2751ef3d8ff1 Mon Sep 17 00:00:00 2001 From: mlarkin Date: Mon, 17 Jan 2022 02:54:28 +0000 Subject: [PATCH] Allow more memory ranges in hibernate The previous limit of VM_PHYSSEG_MAX ranges (16) was proving too small for newer machines. This diff reorganizes the hibernate signature block to allow for 22 ranges by removing the kernel version comparison and replacing it with a SHA of several unique kernel features (the version string and several addresses of functions not inside the same .o). Reported by claudio@, who also helped fix some issues in the diff. Input from deraadt@ as well. Tested by myself and claudio on a variety of machines. Only compile tested on i386 as I have no more S4-capable i386 hardware anymore. ok claudio@ --- sys/arch/amd64/amd64/hibernate_machdep.c | 12 ++++---- sys/arch/i386/i386/hibernate_machdep.c | 14 ++++----- sys/kern/subr_hibernate.c | 38 ++++++++++-------------- sys/sys/hibernate.h | 12 ++++---- 4 files changed, 35 insertions(+), 41 deletions(-) diff --git a/sys/arch/amd64/amd64/hibernate_machdep.c b/sys/arch/amd64/amd64/hibernate_machdep.c index 7781507fa7c..699a121571d 100644 --- a/sys/arch/amd64/amd64/hibernate_machdep.c +++ b/sys/arch/amd64/amd64/hibernate_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate_machdep.c,v 1.47 2022/01/16 22:27:46 mlarkin Exp $ */ +/* $OpenBSD: hibernate_machdep.c,v 1.48 2022/01/17 02:54:28 mlarkin Exp $ */ /* * Copyright (c) 2012 Mike Larkin @@ -153,7 +153,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) #if NACPI > 0 /* Record ACPI trampoline code page */ - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); hiber_info->ranges[hiber_info->nranges].base = ACPI_TRAMPOLINE; hiber_info->ranges[hiber_info->nranges].end = @@ -162,7 +162,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) hiber_info->nranges++; /* Record ACPI trampoline data page */ - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); hiber_info->ranges[hiber_info->nranges].base = ACPI_TRAMP_DATA; hiber_info->ranges[hiber_info->nranges].end = @@ -172,7 +172,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) #endif #ifdef MULTIPROCESSOR /* Record MP trampoline code page */ - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); hiber_info->ranges[hiber_info->nranges].base = MP_TRAMPOLINE; hiber_info->ranges[hiber_info->nranges].end = @@ -181,7 +181,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) hiber_info->nranges++; /* Record MP trampoline data page */ - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); hiber_info->ranges[hiber_info->nranges].base = MP_TRAMP_DATA; @@ -195,7 +195,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) /* Skip non-NVS ranges (already processed) */ if (bmp->type != BIOS_MAP_NVS) continue; - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); i = hiber_info->nranges; diff --git a/sys/arch/i386/i386/hibernate_machdep.c b/sys/arch/i386/i386/hibernate_machdep.c index 8c0f1eb8dcd..a25a59d713e 100644 --- a/sys/arch/i386/i386/hibernate_machdep.c +++ b/sys/arch/i386/i386/hibernate_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate_machdep.c,v 1.57 2022/01/16 22:27:46 mlarkin Exp $ */ +/* $OpenBSD: hibernate_machdep.c,v 1.58 2022/01/17 02:54:28 mlarkin Exp $ */ /* * Copyright (c) 2011 Mike Larkin @@ -151,7 +151,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) } /* Record lowmem PTP page */ - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); hiber_info->ranges[hiber_info->nranges].base = PTP0_PA; hiber_info->ranges[hiber_info->nranges].end = @@ -161,7 +161,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) #if NACPI > 0 /* Record ACPI trampoline code page */ - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); hiber_info->ranges[hiber_info->nranges].base = ACPI_TRAMPOLINE; hiber_info->ranges[hiber_info->nranges].end = @@ -170,7 +170,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) hiber_info->nranges++; /* Record ACPI trampoline data page */ - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); hiber_info->ranges[hiber_info->nranges].base = ACPI_TRAMP_DATA; hiber_info->ranges[hiber_info->nranges].end = @@ -180,7 +180,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) #endif #ifdef MULTIPROCESSOR /* Record MP trampoline code page */ - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); hiber_info->ranges[hiber_info->nranges].base = MP_TRAMPOLINE; hiber_info->ranges[hiber_info->nranges].end = @@ -189,7 +189,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) hiber_info->nranges++; /* Record MP trampoline data page */ - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); hiber_info->ranges[hiber_info->nranges].base = MP_TRAMP_DATA; hiber_info->ranges[hiber_info->nranges].end = @@ -202,7 +202,7 @@ get_hibernate_info_md(union hibernate_info *hiber_info) /* Skip non-NVS ranges (already processed) */ if (bmp->type != BIOS_MAP_NVS) continue; - if (hiber_info->nranges >= VM_PHYSSEG_MAX) + if (hiber_info->nranges >= nitems(hiber_info->ranges)) return (1); i = hiber_info->nranges; diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c index f60851846e6..f2abf7cb8bf 100644 --- a/sys/kern/subr_hibernate.c +++ b/sys/kern/subr_hibernate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_hibernate.c,v 1.132 2022/01/07 02:47:07 guenther Exp $ */ +/* $OpenBSD: subr_hibernate.c,v 1.133 2022/01/17 02:54:28 mlarkin Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt @@ -550,17 +550,6 @@ uvm_page_rle(paddr_t addr) return pg_end - pg; } -/* - * Calculate a hopefully unique version # for this kernel, based upon - * how it was linked. - */ -u_int32_t -hibsum(void) -{ - return ((long)malloc ^ (long)km_alloc ^ (long)printf ^ (long)strlen); -} - - /* * Fills out the hibernate_info union pointed to by hib * with information about this machine (swap signature block @@ -572,6 +561,8 @@ get_hibernate_info(union hibernate_info *hib, int suspend) struct disklabel dl; char err_string[128], *dl_ret; int part; + SHA2_CTX ctx; + void *fn; #ifndef NO_PROPOLICE /* Save propolice guard */ @@ -608,11 +599,17 @@ get_hibernate_info(union hibernate_info *hib, int suspend) hib->sig_offset = DL_GETPSIZE(&dl.d_partitions[part]) - sizeof(union hibernate_info)/DEV_BSIZE; - /* Stash kernel version information */ - memset(&hib->kernel_version, 0, 128); - bcopy(version, &hib->kernel_version, - min(strlen(version), sizeof(hib->kernel_version)-1)); - hib->kernel_sum = hibsum(); + SHA256Init(&ctx); + SHA256Update(&ctx, version, strlen(version)); + fn = printf; + SHA256Update(&ctx, &fn, sizeof(fn)); + fn = malloc; + SHA256Update(&ctx, &fn, sizeof(fn)); + fn = km_alloc; + SHA256Update(&ctx, &fn, sizeof(fn)); + fn = strlen; + SHA256Update(&ctx, &fn, sizeof(fn)); + SHA256Final((u_int8_t *)&hib->kern_hash, &ctx); if (suspend) { /* Grab the previously-allocated piglet addresses */ @@ -954,12 +951,7 @@ hibernate_compare_signature(union hibernate_info *mine, return (1); } - if (strcmp(mine->kernel_version, disk->kernel_version) != 0) { - printf("unhibernate failed: original kernel changed\n"); - return (1); - } - - if (hibsum() != disk->kernel_sum) { + if (bcmp(mine->kern_hash, disk->kern_hash, SHA256_DIGEST_LENGTH) != 0) { printf("unhibernate failed: original kernel changed\n"); return (1); } diff --git a/sys/sys/hibernate.h b/sys/sys/hibernate.h index 2b60243c405..75feaebac73 100644 --- a/sys/sys/hibernate.h +++ b/sys/sys/hibernate.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate.h,v 1.44 2022/01/16 22:27:46 mlarkin Exp $ */ +/* $OpenBSD: hibernate.h,v 1.45 2022/01/17 02:54:28 mlarkin Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt @@ -23,6 +23,9 @@ #include #include #include +#include + +#define HIB_PHYSSEG_MAX 22 #define HIBERNATE_CHUNK_USED 1 #define HIBERNATE_CHUNK_CONFLICT 2 @@ -86,20 +89,19 @@ typedef int (*hibio_fn)(dev_t, daddr_t, vaddr_t, size_t, int, void *); union hibernate_info { struct { u_int32_t magic; + dev_t dev; size_t nranges; - struct hibernate_memory_range ranges[VM_PHYSSEG_MAX]; + struct hibernate_memory_range ranges[HIB_PHYSSEG_MAX]; size_t image_size; size_t chunk_ctr; - dev_t dev; daddr_t sig_offset; daddr_t chunktable_offset; daddr_t image_offset; paddr_t piglet_pa; vaddr_t piglet_va; - char kernel_version[128]; - u_int32_t kernel_sum; hibio_fn io_func; void *io_page; + u_int8_t kern_hash[SHA256_DIGEST_LENGTH]; #ifndef NO_PROPOLICE long guard; #endif /* ! NO_PROPOLICE */ -- 2.20.1