]> git.itanic.dy.fi Git - linux-stable/commitdiff
x86/coco: Require seeding RNG with RDRAND on CoCo systems
authorJason A. Donenfeld <Jason@zx2c4.com>
Tue, 26 Mar 2024 16:07:35 +0000 (17:07 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 10 Apr 2024 14:38:19 +0000 (16:38 +0200)
commit 99485c4c026f024e7cb82da84c7951dbe3deb584 upstream.

There are few uses of CoCo that don't rely on working cryptography and
hence a working RNG. Unfortunately, the CoCo threat model means that the
VM host cannot be trusted and may actively work against guests to
extract secrets or manipulate computation. Since a malicious host can
modify or observe nearly all inputs to guests, the only remaining source
of entropy for CoCo guests is RDRAND.

If RDRAND is broken -- due to CPU hardware fault -- the RNG as a whole
is meant to gracefully continue on gathering entropy from other sources,
but since there aren't other sources on CoCo, this is catastrophic.
This is mostly a concern at boot time when initially seeding the RNG, as
after that the consequences of a broken RDRAND are much more
theoretical.

So, try at boot to seed the RNG using 256 bits of RDRAND output. If this
fails, panic(). This will also trigger if the system is booted without
RDRAND, as RDRAND is essential for a safe CoCo boot.

Add this deliberately to be "just a CoCo x86 driver feature" and not
part of the RNG itself. Many device drivers and platforms have some
desire to contribute something to the RNG, and add_device_randomness()
is specifically meant for this purpose.

Any driver can call it with seed data of any quality, or even garbage
quality, and it can only possibly make the quality of the RNG better or
have no effect, but can never make it worse.

Rather than trying to build something into the core of the RNG, consider
the particular CoCo issue just a CoCo issue, and therefore separate it
all out into driver (well, arch/platform) code.

  [ bp: Massage commit message. ]

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Elena Reshetova <elena.reshetova@intel.com>
Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Reviewed-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20240326160735.73531-1-Jason@zx2c4.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/coco/core.c
arch/x86/include/asm/coco.h
arch/x86/kernel/setup.c

index d07be9d05cd03781072798e5802a5ef34d7a057a..ddd4efdc79d66875bb8b17387aaea883c3b621cc 100644 (file)
@@ -3,13 +3,17 @@
  * Confidential Computing Platform Capability checks
  *
  * Copyright (C) 2021 Advanced Micro Devices, Inc.
+ * Copyright (C) 2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
  *
  * Author: Tom Lendacky <thomas.lendacky@amd.com>
  */
 
 #include <linux/export.h>
 #include <linux/cc_platform.h>
+#include <linux/string.h>
+#include <linux/random.h>
 
+#include <asm/archrandom.h>
 #include <asm/coco.h>
 #include <asm/processor.h>
 
@@ -148,3 +152,40 @@ u64 cc_mkdec(u64 val)
        }
 }
 EXPORT_SYMBOL_GPL(cc_mkdec);
+
+__init void cc_random_init(void)
+{
+       /*
+        * The seed is 32 bytes (in units of longs), which is 256 bits, which
+        * is the security level that the RNG is targeting.
+        */
+       unsigned long rng_seed[32 / sizeof(long)];
+       size_t i, longs;
+
+       if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
+               return;
+
+       /*
+        * Since the CoCo threat model includes the host, the only reliable
+        * source of entropy that can be neither observed nor manipulated is
+        * RDRAND. Usually, RDRAND failure is considered tolerable, but since
+        * CoCo guests have no other unobservable source of entropy, it's
+        * important to at least ensure the RNG gets some initial random seeds.
+        */
+       for (i = 0; i < ARRAY_SIZE(rng_seed); i += longs) {
+               longs = arch_get_random_longs(&rng_seed[i], ARRAY_SIZE(rng_seed) - i);
+
+               /*
+                * A zero return value means that the guest doesn't have RDRAND
+                * or the CPU is physically broken, and in both cases that
+                * means most crypto inside of the CoCo instance will be
+                * broken, defeating the purpose of CoCo in the first place. So
+                * just panic here because it's absolutely unsafe to continue
+                * executing.
+                */
+               if (longs == 0)
+                       panic("RDRAND is defective.");
+       }
+       add_device_randomness(rng_seed, sizeof(rng_seed));
+       memzero_explicit(rng_seed, sizeof(rng_seed));
+}
index 18bbdda0532210f2ad26e3ece7f0d33e80907b4e..3dd052bfefc51c6ee4fd9a8ee04b07c7d577a206 100644 (file)
@@ -21,6 +21,7 @@ static inline void cc_set_mask(u64 mask)
 
 u64 cc_mkenc(u64 val);
 u64 cc_mkdec(u64 val);
+void cc_random_init(void);
 #else
 #define cc_vendor (CC_VENDOR_NONE)
 
@@ -33,6 +34,7 @@ static inline u64 cc_mkdec(u64 val)
 {
        return val;
 }
+static inline void cc_random_init(void) { }
 #endif
 
 #endif /* _ASM_X86_COCO_H */
index 97dd702857413ff79c51eccb64a5d1ac07894aad..3998109195dab9233e0a9fe06f5058dd7d054668 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/bios_ebda.h>
 #include <asm/bugs.h>
 #include <asm/cacheinfo.h>
+#include <asm/coco.h>
 #include <asm/cpu.h>
 #include <asm/efi.h>
 #include <asm/gart.h>
@@ -993,6 +994,7 @@ void __init setup_arch(char **cmdline_p)
         * memory size.
         */
        mem_encrypt_setup_arch();
+       cc_random_init();
 
        efi_fake_memmap();
        efi_find_mirror();