Allow more memory ranges in hibernate
authormlarkin <mlarkin@openbsd.org>
Mon, 17 Jan 2022 02:54:28 +0000 (02:54 +0000)
committermlarkin <mlarkin@openbsd.org>
Mon, 17 Jan 2022 02:54:28 +0000 (02:54 +0000)
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
sys/arch/i386/i386/hibernate_machdep.c
sys/kern/subr_hibernate.c
sys/sys/hibernate.h

index 7781507..699a121 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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;
index 8c0f1eb..a25a59d 100644 (file)
@@ -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 <mlarkin@openbsd.org>
@@ -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;
index f608518..f2abf7c 100644 (file)
@@ -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 <ariane@stack.nl>
@@ -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);
        }
index 2b60243..75feaeb 100644 (file)
@@ -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 <ariane@stack.nl>
@@ -23,6 +23,9 @@
 #include <sys/tree.h>
 #include <lib/libz/zlib.h>
 #include <machine/vmparam.h>
+#include <crypto/sha2.h>
+
+#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 */