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.
This patch is deliberately written 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 this 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, this patch interprets the particular CoCo issue as just a CoCo issue, and therefore separates this all out into driver (well, arch/platform) code.
Cc: Borislav Petkov bp@alien8.de Cc: Daniel P. Berrangé berrange@redhat.com Cc: Dave Hansen dave.hansen@linux.intel.com Cc: H. Peter Anvin hpa@zytor.com Cc: Ingo Molnar mingo@redhat.com Cc: Thomas Gleixner tglx@linutronix.de Cc: stable@vger.kernel.org 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 Signed-off-by: Jason A. Donenfeld Jason@zx2c4.com --- Changes v3->v4: - Add stable@ tag and reviewed-by lines. - Add comment for Dave explaining where the "32" comes from.
arch/x86/coco/core.c | 40 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/coco.h | 2 ++ arch/x86/kernel/setup.c | 2 ++ 3 files changed, 44 insertions(+)
diff --git a/arch/x86/coco/core.c b/arch/x86/coco/core.c index eeec9986570e..0e988bff4aec 100644 --- a/arch/x86/coco/core.c +++ b/arch/x86/coco/core.c @@ -3,13 +3,16 @@ * 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/random.h>
+#include <asm/archrandom.h> #include <asm/coco.h> #include <asm/processor.h>
@@ -153,3 +156,40 @@ __init void cc_set_mask(u64 mask) { cc_mask = mask; } + +__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_vendor == CC_VENDOR_NONE) + 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)); +} diff --git a/arch/x86/include/asm/coco.h b/arch/x86/include/asm/coco.h index 76c310b19b11..e9d059449885 100644 --- a/arch/x86/include/asm/coco.h +++ b/arch/x86/include/asm/coco.h @@ -15,6 +15,7 @@ extern enum cc_vendor cc_vendor; 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)
@@ -27,6 +28,7 @@ static inline u64 cc_mkdec(u64 val) { return val; } +static inline void cc_random_init(void) { } #endif
#endif /* _ASM_X86_COCO_H */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 84201071dfac..30a653cfc7d2 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -36,6 +36,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> @@ -994,6 +995,7 @@ void __init setup_arch(char **cmdline_p) * memory size. */ mem_encrypt_setup_arch(); + cc_random_init();
efi_fake_memmap(); efi_find_mirror();
On 2/21/24 20:05, Jason A. Donenfeld wrote:
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.
This patch is deliberately written 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 this 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, this patch interprets the particular CoCo issue as just a CoCo issue, and therefore separates this all out into driver (well, arch/platform) code.
Cc: Borislav Petkov bp@alien8.de Cc: Daniel P. Berrangé berrange@redhat.com Cc: Dave Hansen dave.hansen@linux.intel.com Cc: H. Peter Anvin hpa@zytor.com Cc: Ingo Molnar mingo@redhat.com Cc: Thomas Gleixner tglx@linutronix.de Cc: stable@vger.kernel.org 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 Signed-off-by: Jason A. Donenfeld Jason@zx2c4.com
Changes v3->v4:
Add stable@ tag and reviewed-by lines.
Add comment for Dave explaining where the "32" comes from.
arch/x86/coco/core.c | 40 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/coco.h | 2 ++ arch/x86/kernel/setup.c | 2 ++ 3 files changed, 44 insertions(+)
diff --git a/arch/x86/coco/core.c b/arch/x86/coco/core.c index eeec9986570e..0e988bff4aec 100644 --- a/arch/x86/coco/core.c +++ b/arch/x86/coco/core.c @@ -3,13 +3,16 @@
- 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/random.h> +#include <asm/archrandom.h> #include <asm/coco.h> #include <asm/processor.h> @@ -153,3 +156,40 @@ __init void cc_set_mask(u64 mask) { cc_mask = mask; }
+__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_vendor == CC_VENDOR_NONE)
I responded to an earlier version of this patch, adding that response here:
You probably want to use:
if (!cc_platform_has(CC_GUEST_MEM_ENCRYPT)) return;
Otherwise, you can hit the bare-metal case where AMD SME is active and then cc_vendor will not be CC_VENDOR_NONE.
Thanks, Tom
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));
+} diff --git a/arch/x86/include/asm/coco.h b/arch/x86/include/asm/coco.h index 76c310b19b11..e9d059449885 100644 --- a/arch/x86/include/asm/coco.h +++ b/arch/x86/include/asm/coco.h @@ -15,6 +15,7 @@ extern enum cc_vendor cc_vendor; 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) @@ -27,6 +28,7 @@ static inline u64 cc_mkdec(u64 val) { return val; } +static inline void cc_random_init(void) { } #endif #endif /* _ASM_X86_COCO_H */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 84201071dfac..30a653cfc7d2 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -36,6 +36,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> @@ -994,6 +995,7 @@ void __init setup_arch(char **cmdline_p) * memory size. */ mem_encrypt_setup_arch();
- cc_random_init();
efi_fake_memmap(); efi_find_mirror();
Hi Tom,
On Fri, Feb 23, 2024 at 11:05 PM Tom Lendacky thomas.lendacky@amd.com wrote:
On 2/21/24 20:05, Jason A. Donenfeld wrote:
if (cc_vendor == CC_VENDOR_NONE)
I responded to an earlier version of this patch, adding that response here:
You probably want to use:
if (!cc_platform_has(CC_GUEST_MEM_ENCRYPT)) return;
Otherwise, you can hit the bare-metal case where AMD SME is active and then cc_vendor will not be CC_VENDOR_NONE.
Nice catch, thanks. I'll do that for v+1.
Jason
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.
This patch is deliberately written 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 this 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, this patch interprets the particular CoCo issue as just a CoCo issue, and therefore separates this all out into driver (well, arch/platform) code.
Cc: Borislav Petkov bp@alien8.de Cc: Daniel P. Berrangé berrange@redhat.com Cc: Dave Hansen dave.hansen@linux.intel.com Cc: H. Peter Anvin hpa@zytor.com Cc: Ingo Molnar mingo@redhat.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Tom Lendacky thomas.lendacky@amd.com Cc: stable@vger.kernel.org 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 Signed-off-by: Jason A. Donenfeld Jason@zx2c4.com --- Changes v4->v5: - Use `cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)` instead of checking cc_vendor, per Tom's recommendation.
arch/x86/coco/core.c | 40 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/coco.h | 2 ++ arch/x86/kernel/setup.c | 2 ++ 3 files changed, 44 insertions(+)
diff --git a/arch/x86/coco/core.c b/arch/x86/coco/core.c index eeec9986570e..b419a29ef0e5 100644 --- a/arch/x86/coco/core.c +++ b/arch/x86/coco/core.c @@ -3,13 +3,16 @@ * 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/random.h>
+#include <asm/archrandom.h> #include <asm/coco.h> #include <asm/processor.h>
@@ -153,3 +156,40 @@ __init void cc_set_mask(u64 mask) { cc_mask = mask; } + +__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)); +} diff --git a/arch/x86/include/asm/coco.h b/arch/x86/include/asm/coco.h index 76c310b19b11..e9d059449885 100644 --- a/arch/x86/include/asm/coco.h +++ b/arch/x86/include/asm/coco.h @@ -15,6 +15,7 @@ extern enum cc_vendor cc_vendor; 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)
@@ -27,6 +28,7 @@ static inline u64 cc_mkdec(u64 val) { return val; } +static inline void cc_random_init(void) { } #endif
#endif /* _ASM_X86_COCO_H */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 84201071dfac..30a653cfc7d2 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -36,6 +36,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> @@ -994,6 +995,7 @@ void __init setup_arch(char **cmdline_p) * memory size. */ mem_encrypt_setup_arch(); + cc_random_init();
efi_fake_memmap(); efi_find_mirror();
Hi Borislav,
On Sat, Feb 24, 2024 at 02:18:56AM +0100, Jason A. Donenfeld wrote:
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.
This patch is deliberately written 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 this 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, this patch interprets the particular CoCo issue as just a CoCo issue, and therefore separates this all out into driver (well, arch/platform) code.
Cc: Borislav Petkov bp@alien8.de Cc: Daniel P. Berrangé berrange@redhat.com Cc: Dave Hansen dave.hansen@linux.intel.com Cc: H. Peter Anvin hpa@zytor.com Cc: Ingo Molnar mingo@redhat.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Tom Lendacky thomas.lendacky@amd.com Cc: stable@vger.kernel.org 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 Signed-off-by: Jason A. Donenfeld Jason@zx2c4.com
This has been sitting on the list for a while with a few positive reviews and no outstanding objections, afaict. Can you merge this to tip?
Thanks, Jason
Hi Jason,
On Thu, Mar 14, 2024 at 12:34:03AM +0100, Jason A. Donenfeld wrote:
This has been sitting on the list for a while with a few positive reviews and no outstanding objections, afaict. Can you merge this to tip?
the tip tree is open for new code after the merge window is over.
On Sat, Feb 24, 2024 at 02:18:56AM +0100, Jason A. Donenfeld wrote:
+__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));
Please redo your patch ontop of latest tip/master:
arch/x86/coco/core.c: In function ‘cc_random_init’: arch/x86/coco/core.c:189:9: error: implicit declaration of function ‘memzero_explicit’ [-Werror=implicit-function-declaration] 189 | memzero_explicit(rng_seed, sizeof(rng_seed)); | ^~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors make[4]: *** [scripts/Makefile.build:244: arch/x86/coco/core.o] Error 1 make[3]: *** [scripts/Makefile.build:485: arch/x86/coco] Error 2 make[3]: *** Waiting for unfinished jobs.... make[2]: *** [scripts/Makefile.build:485: arch/x86] Error 2 make[2]: *** Waiting for unfinished jobs.... make[1]: *** [/mnt/kernel/kernel/2nd/linux/Makefile:1919: .] Error 2 make: *** [Makefile:240: __sub-make] Error 2
Thx.
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.
This patch is deliberately written 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 this 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, this patch interprets the particular CoCo issue as just a CoCo issue, and therefore separates this all out into driver (well, arch/platform) code.
Cc: Borislav Petkov bp@alien8.de Cc: Daniel P. Berrangé berrange@redhat.com Cc: Dave Hansen dave.hansen@linux.intel.com Cc: H. Peter Anvin hpa@zytor.com Cc: Ingo Molnar mingo@redhat.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Tom Lendacky thomas.lendacky@amd.com Cc: stable@vger.kernel.org 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 Signed-off-by: Jason A. Donenfeld Jason@zx2c4.com --- Changes v5->v6: - Rebase on tip/master. - Add string.h include.
arch/x86/coco/core.c | 41 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/coco.h | 2 ++ arch/x86/kernel/setup.c | 2 ++ 3 files changed, 45 insertions(+)
diff --git a/arch/x86/coco/core.c b/arch/x86/coco/core.c index d07be9d05cd0..ddd4efdc79d6 100644 --- a/arch/x86/coco/core.c +++ b/arch/x86/coco/core.c @@ -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)); +} diff --git a/arch/x86/include/asm/coco.h b/arch/x86/include/asm/coco.h index fb7388bbc212..c086699b0d0c 100644 --- a/arch/x86/include/asm/coco.h +++ b/arch/x86/include/asm/coco.h @@ -22,6 +22,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)
@@ -34,6 +35,7 @@ static inline u64 cc_mkdec(u64 val) { return val; } +static inline void cc_random_init(void) { } #endif
#endif /* _ASM_X86_COCO_H */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index f04cef846e51..e3f01caf104b 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -37,6 +37,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();
On 3/26/24 11:07, Jason A. Donenfeld wrote:
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.
This patch is deliberately written 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 this 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, this patch interprets the particular CoCo issue as just a CoCo issue, and therefore separates this all out into driver (well, arch/platform) code.
Cc: Borislav Petkov bp@alien8.de Cc: Daniel P. Berrangé berrange@redhat.com Cc: Dave Hansen dave.hansen@linux.intel.com Cc: H. Peter Anvin hpa@zytor.com Cc: Ingo Molnar mingo@redhat.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Tom Lendacky thomas.lendacky@amd.com Cc: stable@vger.kernel.org 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 Signed-off-by: Jason A. Donenfeld Jason@zx2c4.com
Tested-by: Tom Lendacky thomas.lendacky@amd.com
Changes v5->v6:
Rebase on tip/master.
Add string.h include.
arch/x86/coco/core.c | 41 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/coco.h | 2 ++ arch/x86/kernel/setup.c | 2 ++ 3 files changed, 45 insertions(+)
The following commit has been merged into the x86/urgent branch of tip:
Commit-ID: 99485c4c026f024e7cb82da84c7951dbe3deb584 Gitweb: https://git.kernel.org/tip/99485c4c026f024e7cb82da84c7951dbe3deb584 Author: Jason A. Donenfeld Jason@zx2c4.com AuthorDate: Tue, 26 Mar 2024 17:07:35 +01:00 Committer: Borislav Petkov (AMD) bp@alien8.de CommitterDate: Thu, 04 Apr 2024 10:40:19 +02:00
x86/coco: Require seeding RNG with RDRAND on CoCo systems
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 --- arch/x86/coco/core.c | 41 ++++++++++++++++++++++++++++++++++++- arch/x86/include/asm/coco.h | 2 ++- arch/x86/kernel/setup.c | 2 ++- 3 files changed, 45 insertions(+)
diff --git a/arch/x86/coco/core.c b/arch/x86/coco/core.c index d07be9d..ddd4efd 100644 --- a/arch/x86/coco/core.c +++ b/arch/x86/coco/core.c @@ -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)); +} diff --git a/arch/x86/include/asm/coco.h b/arch/x86/include/asm/coco.h index fb7388b..c086699 100644 --- a/arch/x86/include/asm/coco.h +++ b/arch/x86/include/asm/coco.h @@ -22,6 +22,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)
@@ -34,6 +35,7 @@ static inline u64 cc_mkdec(u64 val) { return val; } +static inline void cc_random_init(void) { } #endif
#endif /* _ASM_X86_COCO_H */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 0109e6c..e125e05 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -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> @@ -991,6 +992,7 @@ void __init setup_arch(char **cmdline_p) * memory size. */ mem_encrypt_setup_arch(); + cc_random_init();
efi_fake_memmap(); efi_find_mirror();
linux-stable-mirror@lists.linaro.org