[PATCH v6 14/14] arm64: hibernate: Prevent resume from a different kernel version
Pavel Machek
pavel at ucw.cz
Sun Apr 10 04:49:38 PDT 2016
On Mon 2016-02-29 17:20:23, James Morse wrote:
> Resuming using a different kernel version is fragile, while there are
> sufficient details in the hibernate arch-header to perform the restore,
> changes in the boot process can have a long-lasting impact on the system.
> In particular, if the EFI stub causes more runtime services memory to be
> allocated, the amount of memory left for linux is reduced. If we are
> lucky, this will cause restore to fail with the message:
> > PM: Image mismatch: memory size
> If we are unlucky, the system will explode sometime later when an EFI
> runtime services call is made.
>
> Prevent resuming with a different kernel build, by storing UTS_VERSION
> in the hibernate header. This also ensures the page size and va bits
> configuration remain the same.
>
> Signed-off-by: James Morse <james.morse at arm.com>
Better solution would be to store the current bits _and_ UTS version. Then bump UTS_VERSION
every time Linux behaviour changes w.r.t. EFI. For a while, it would change a lot, but then
it should stabilize, as the port stabilizes
> ---
> arch/arm64/kernel/hibernate.c | 35 +++++------------------------------
> 1 file changed, 5 insertions(+), 30 deletions(-)
>
> diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
> index 279c556ee24b..486315249f2a 100644
> --- a/arch/arm64/kernel/hibernate.c
> +++ b/arch/arm64/kernel/hibernate.c
> @@ -20,6 +20,7 @@
> #include <linux/pm.h>
> #include <linux/sched.h>
> #include <linux/suspend.h>
> +#include <linux/utsname.h>
> #include <linux/version.h>
>
> #include <asm/barrier.h>
> @@ -42,8 +43,6 @@
> #define pud_index(x) 0
> #endif
>
> -#define TCR_IPS_BITS (0x7UL<<32)
> -
> /*
> * Hibernate core relies on this value being 0 on resume, and marks it
> * __nosavedata assuming it will keep the resume kernel's '0' value. This
> @@ -54,17 +53,6 @@
> */
> extern int in_suspend;
>
> -/*
> - * This value is written to the hibernate arch header, and prevents resuming
> - * from a hibernate image produced by an incompatible kernel. If you change
> - * a value that isn't saved/restored by hibernate, you should change this value.
> - *
> - * For example, if the mair_el1 values used by the kernel are changed, you
> - * should prevent resuming from a kernel with incompatible attributes, as these
> - * aren't saved/restored.
> - */
> -#define HIBERNATE_VERSION KERNEL_VERSION(4, 6, 0)
> -
> /* Find a symbols alias in the linear map */
> #define LMADDR(x) phys_to_virt(virt_to_phys(x))
>
> @@ -81,8 +69,7 @@ extern char hibernate_el2_vectors[];
> extern char el2_setup[];
>
> struct arch_hibernate_hdr_invariants {
> - unsigned long version;
> - unsigned long tcr_el1; /* page_size, va bit etc */
> + char uts_version[__NEW_UTS_LEN + 1];
> };
>
> /* These values need to be know across a hibernate/restore. */
> @@ -104,11 +91,8 @@ static struct arch_hibernate_hdr {
>
> static inline void arch_hdr_invariants(struct arch_hibernate_hdr_invariants *i)
> {
> - i->version = HIBERNATE_VERSION;
> - asm volatile("mrs %0, tcr_el1" : "=r"(i->tcr_el1));
> -
> - /* IPS bits vary on big/little systems, mask them out */
> - i->tcr_el1 &= ~TCR_IPS_BITS;
> + memset(i, 0, sizeof(*i));
> + memcpy(i->uts_version, init_utsname()->version, sizeof(i->uts_version));
> }
>
> int pfn_is_nosave(unsigned long pfn)
> @@ -155,18 +139,9 @@ int arch_hibernation_header_restore(void *addr)
> struct arch_hibernate_hdr_invariants invariants;
> struct arch_hibernate_hdr *hdr = addr;
>
> - /*
> - * If this header is ancient, it may be smaller than we expect.
> - * Test the version first.
> - */
> - if (hdr->invariants.version != HIBERNATE_VERSION) {
> - pr_crit("Hibernate image not compatible with this kernel version!\n");
> - return -EINVAL;
> - }
> -
> arch_hdr_invariants(&invariants);
> if (memcmp(&hdr->invariants, &invariants, sizeof(invariants))) {
> - pr_crit("Hibernate image not compatible with this kernel configuration!\n");
> + pr_crit("Hibernate image not generated by this kernel!\n");
> return -EINVAL;
> }
>
> --
> 2.7.0
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
More information about the linux-arm-kernel
mailing list