Skip to content

Commit f5d1499

Browse files
Chris von Recklinghausenrafaeljw
authored andcommitted
PM: hibernate: x86: Use crc32 instead of md5 for hibernation e820 integrity check
Hibernation fails on a system in fips mode because md5 is used for the e820 integrity check and is not available. Use crc32 instead. The check is intended to detect whether the E820 memory map provided by the firmware after cold boot unexpectedly differs from the one that was in use when the hibernation image was created. In this case, the hibernation image cannot be restored, as it may cover memory regions that are no longer available to the OS. A non-cryptographic checksum such as CRC-32 is sufficient to detect such inadvertent deviations. Fixes: 62a03de ("PM / hibernate: Verify the consistent of e820 memory map by md5 digest") Reviewed-by: Eric Biggers <ebiggers@google.com> Tested-by: Dexuan Cui <decui@microsoft.com> Reviewed-by: Dexuan Cui <decui@microsoft.com> Signed-off-by: Chris von Recklinghausen <crecklin@redhat.com> [ rjw: Subject edit ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 4da6d76 commit f5d1499

2 files changed

Lines changed: 16 additions & 77 deletions

File tree

arch/x86/kernel/e820.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
* - inform the user about the firmware's notion of memory layout
3232
* via /sys/firmware/memmap
3333
*
34-
* - the hibernation code uses it to generate a kernel-independent MD5
35-
* fingerprint of the physical memory layout of a system.
34+
* - the hibernation code uses it to generate a kernel-independent CRC32
35+
* checksum of the physical memory layout of a system.
3636
*
3737
* - 'e820_table_kexec': a slightly modified (by the kernel) firmware version
3838
* passed to us by the bootloader - the major difference between

arch/x86/power/hibernate.c

Lines changed: 14 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
#include <linux/kdebug.h>
1414
#include <linux/cpu.h>
1515
#include <linux/pgtable.h>
16-
17-
#include <crypto/hash.h>
16+
#include <linux/types.h>
17+
#include <linux/crc32.h>
1818

1919
#include <asm/e820/api.h>
2020
#include <asm/init.h>
@@ -54,95 +54,33 @@ int pfn_is_nosave(unsigned long pfn)
5454
return pfn >= nosave_begin_pfn && pfn < nosave_end_pfn;
5555
}
5656

57-
58-
#define MD5_DIGEST_SIZE 16
59-
6057
struct restore_data_record {
6158
unsigned long jump_address;
6259
unsigned long jump_address_phys;
6360
unsigned long cr3;
6461
unsigned long magic;
65-
u8 e820_digest[MD5_DIGEST_SIZE];
62+
unsigned long e820_checksum;
6663
};
6764

68-
#if IS_BUILTIN(CONFIG_CRYPTO_MD5)
6965
/**
70-
* get_e820_md5 - calculate md5 according to given e820 table
66+
* compute_e820_crc32 - calculate crc32 of a given e820 table
7167
*
7268
* @table: the e820 table to be calculated
73-
* @buf: the md5 result to be stored to
69+
*
70+
* Return: the resulting checksum
7471
*/
75-
static int get_e820_md5(struct e820_table *table, void *buf)
72+
static inline u32 compute_e820_crc32(struct e820_table *table)
7673
{
77-
struct crypto_shash *tfm;
78-
struct shash_desc *desc;
79-
int size;
80-
int ret = 0;
81-
82-
tfm = crypto_alloc_shash("md5", 0, 0);
83-
if (IS_ERR(tfm))
84-
return -ENOMEM;
85-
86-
desc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm),
87-
GFP_KERNEL);
88-
if (!desc) {
89-
ret = -ENOMEM;
90-
goto free_tfm;
91-
}
92-
93-
desc->tfm = tfm;
94-
95-
size = offsetof(struct e820_table, entries) +
74+
int size = offsetof(struct e820_table, entries) +
9675
sizeof(struct e820_entry) * table->nr_entries;
9776

98-
if (crypto_shash_digest(desc, (u8 *)table, size, buf))
99-
ret = -EINVAL;
100-
101-
kfree_sensitive(desc);
102-
103-
free_tfm:
104-
crypto_free_shash(tfm);
105-
return ret;
106-
}
107-
108-
static int hibernation_e820_save(void *buf)
109-
{
110-
return get_e820_md5(e820_table_firmware, buf);
111-
}
112-
113-
static bool hibernation_e820_mismatch(void *buf)
114-
{
115-
int ret;
116-
u8 result[MD5_DIGEST_SIZE];
117-
118-
memset(result, 0, MD5_DIGEST_SIZE);
119-
/* If there is no digest in suspend kernel, let it go. */
120-
if (!memcmp(result, buf, MD5_DIGEST_SIZE))
121-
return false;
122-
123-
ret = get_e820_md5(e820_table_firmware, result);
124-
if (ret)
125-
return true;
126-
127-
return memcmp(result, buf, MD5_DIGEST_SIZE) ? true : false;
128-
}
129-
#else
130-
static int hibernation_e820_save(void *buf)
131-
{
132-
return 0;
133-
}
134-
135-
static bool hibernation_e820_mismatch(void *buf)
136-
{
137-
/* If md5 is not builtin for restore kernel, let it go. */
138-
return false;
77+
return ~crc32_le(~0, (unsigned char const *)table, size);
13978
}
140-
#endif
14179

14280
#ifdef CONFIG_X86_64
143-
#define RESTORE_MAGIC 0x23456789ABCDEF01UL
81+
#define RESTORE_MAGIC 0x23456789ABCDEF02UL
14482
#else
145-
#define RESTORE_MAGIC 0x12345678UL
83+
#define RESTORE_MAGIC 0x12345679UL
14684
#endif
14785

14886
/**
@@ -179,7 +117,8 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size)
179117
*/
180118
rdr->cr3 = restore_cr3 & ~CR3_PCID_MASK;
181119

182-
return hibernation_e820_save(rdr->e820_digest);
120+
rdr->e820_checksum = compute_e820_crc32(e820_table_firmware);
121+
return 0;
183122
}
184123

185124
/**
@@ -200,7 +139,7 @@ int arch_hibernation_header_restore(void *addr)
200139
jump_address_phys = rdr->jump_address_phys;
201140
restore_cr3 = rdr->cr3;
202141

203-
if (hibernation_e820_mismatch(rdr->e820_digest)) {
142+
if (rdr->e820_checksum != compute_e820_crc32(e820_table_firmware)) {
204143
pr_crit("Hibernate inconsistent memory map detected!\n");
205144
return -ENODEV;
206145
}

0 commit comments

Comments
 (0)