On Mon, Apr 12, 2021 at 10:09:32AM -0400, Chris von Recklinghausen wrote:
> Suspend fails on a system in fips mode because md5 is used for the e820
> integrity check and is not available. Use crc32 instead.
> 
> This patch changes the integrity check algorithm from md5 to crc32.
> 
> The purpose of the integrity check is to detect possible differences
> between the memory map used at the time when the hibernation image is
> about to be loaded into memory and the memory map used at the image
> creation time, because it is generally unsafe to load the image if the
> current memory map doesn't match the one used when it was created. so
> it is not intended as a cryptographic integrity check.

This still doesn't actually explain why a non-cryptographic checksum is
sufficient.  "Detection of possible differences" could very well require
cryptographic authentication; it depends on whether malicious changes need to be
detected or not.

> 
> Fixes: 62a03defeabd ("PM / hibernate: Verify the consistent of e820 memory map
>        by md5 digest")
> 
> Signed-off-by: Chris von Recklinghausen <creck...@redhat.com>
> ---
> v1 -> v2
>    bump up RESTORE_MAGIC
> v2 -> v3
>    move embelishment from cover letter to commit comments (no code change)
> v3 -> v4
>    add note to comments that md5 isn't used for encryption here.
> v4 -> v5
>    reword comment per Simo's suggestion
> v5 -> v6
>    use wording from Eric Biggers, use crc32_le instead of crc32 from crypto
>       framework (crc32_le is in the core API and removes need for #defines)
> 
>  arch/x86/power/hibernate.c | 76 +++++++++++---------------------------
>  1 file changed, 22 insertions(+), 54 deletions(-)
> 
> diff --git a/arch/x86/power/hibernate.c b/arch/x86/power/hibernate.c
> index cd3914fc9f3d..f39e507e34ca 100644
> --- a/arch/x86/power/hibernate.c
> +++ b/arch/x86/power/hibernate.c
> @@ -13,6 +13,8 @@
>  #include <linux/kdebug.h>
>  #include <linux/cpu.h>
>  #include <linux/pgtable.h>
> +#include <linux/types.h>
> +#include <linux/crc32.h>
>  
>  #include <crypto/hash.h>

crypto/hash.h is no longer needed.

>  
> @@ -55,94 +57,60 @@ int pfn_is_nosave(unsigned long pfn)
>  }
>  
>  
> -#define MD5_DIGEST_SIZE 16
> +#define CRC32_DIGEST_SIZE (sizeof (u32))
>  
>  struct restore_data_record {
>       unsigned long jump_address;
>       unsigned long jump_address_phys;
>       unsigned long cr3;
>       unsigned long magic;
> -     u8 e820_digest[MD5_DIGEST_SIZE];
> +     u8 e820_digest[CRC32_DIGEST_SIZE];
>  };

It would be simpler to just make this field 'unsigned long'.  Then there would
be no need to deal with memcpy().

> -#if IS_BUILTIN(CONFIG_CRYPTO_MD5)
>  /**
> - * get_e820_md5 - calculate md5 according to given e820 table
> + * get_e820_crc32 - calculate crc32 according to given e820 table

Calling this "compute_e820_crc32()" would avoid confusion with retrieving the
previously-stored crc32 value.

> +     ret = crc32_le(0, (unsigned char const *)table, size);

It would be better to do ~crc32_le(~0, ...) (i.e., invert at beginning and end)
to match the recommended usage of CRC-32.  Unfortunately the library function
doesn't do the inversions by default.

>  static int hibernation_e820_save(void *buf)
>  {
> -     return get_e820_md5(e820_table_firmware, buf);
> +     return get_e820_crc32(e820_table_firmware, buf);
>  }

This should be inlined into arch_hibernation_header_save().  Also note that it
can no longer fail.

>  
>  static bool hibernation_e820_mismatch(void *buf)
>  {

This should be inlined into arch_hibernation_header_restore().

>       int ret;
> -     u8 result[MD5_DIGEST_SIZE];
> +     u8 result[CRC32_DIGEST_SIZE];
>  
> -     memset(result, 0, MD5_DIGEST_SIZE);
> +     memset(result, 0, CRC32_DIGEST_SIZE);
>       /* If there is no digest in suspend kernel, let it go. */
> -     if (!memcmp(result, buf, MD5_DIGEST_SIZE))
> +     if (!memcmp(result, buf, CRC32_DIGEST_SIZE))
>               return false;

There's no need to handle the "no digest" case anymore, right?  Since crc32_le()
is always available.

- Eric

Reply via email to