[RFC PATCH 8/8] x86/cpu: Support the hardware randomization option for Key Locker internal key

From: Chang S. Bae
Date: Wed Dec 16 2020 - 12:47:25 EST


Hardware can load the internal key with randomization. random.trust_cpu
determines the use of the CPU's random number generator. Take the parameter
to use the CPU's internal key randomization.

The backup mechanism is required to distribute the key. It is the only
way to copy the (unknown) key value to other CPUs.

This randomization option is disabled when hardware does not support the
key backup.

Signed-off-by: Chang S. Bae <chang.seok.bae@xxxxxxxxx>
Cc: Mark Brown <broonie@xxxxxxxxxx>
Cc: x86@xxxxxxxxxx
Cc: linux-doc@xxxxxxxxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
---
arch/x86/include/asm/keylocker.h | 2 +-
arch/x86/kernel/cpu/common.c | 3 ++-
arch/x86/kernel/keylocker.c | 31 ++++++++++++++++++++++++++++---
drivers/char/random.c | 6 ++++++
include/linux/random.h | 2 ++
5 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/keylocker.h b/arch/x86/include/asm/keylocker.h
index 722574c305c2..a6774ced916a 100644
--- a/arch/x86/include/asm/keylocker.h
+++ b/arch/x86/include/asm/keylocker.h
@@ -19,7 +19,7 @@ bool check_keylocker_readiness(void);

bool load_keylocker(void);

-void make_keylocker_data(void);
+void make_keylocker_data(bool use_hwrand);
#ifdef CONFIG_X86_KEYLOCKER
void invalidate_keylocker_data(void);
#else
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index ba5bd79fbac2..48881d8ea559 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -485,12 +485,13 @@ static __always_inline void setup_keylocker(struct cpuinfo_x86 *c)
cr4_set_bits(X86_CR4_KEYLOCKER);

if (c == &boot_cpu_data) {
+ bool use_hwrand = check_random_trust_cpu();
bool keyloaded;

if (!check_keylocker_readiness())
goto disable_keylocker;

- make_keylocker_data();
+ make_keylocker_data(use_hwrand);

keyloaded = load_keylocker();
if (!keyloaded) {
diff --git a/arch/x86/kernel/keylocker.c b/arch/x86/kernel/keylocker.c
index 229875ac80d5..e77e4c3d785e 100644
--- a/arch/x86/kernel/keylocker.c
+++ b/arch/x86/kernel/keylocker.c
@@ -13,6 +13,7 @@
#include <asm/fpu/api.h>

static bool keybackup_available;
+static bool keyhwrand_available;

bool check_keylocker_readiness(void)
{
@@ -33,25 +34,33 @@ bool check_keylocker_readiness(void)
pr_debug("x86/keylocker: no key backup support with possible S3/4\n");
return false;
}
+
+ keyhwrand_available = (ecx & KEYLOCKER_CPUID_ECX_RAND);
return true;
}

/* Load Internal (Wrapping) Key */
#define LOADIWKEY ".byte 0xf3,0x0f,0x38,0xdc,0xd1"
#define LOADIWKEY_NUM_OPERANDS 3
+#define LOADIWKEY_HWRAND_RETRY 10

static struct key {
bool valid;
+ bool hwrand;
struct reg_128_bit value[LOADIWKEY_NUM_OPERANDS];
} keydata;

-void make_keylocker_data(void)
+void make_keylocker_data(bool use_hwrand)
{
int i;

for (i = 0; i < LOADIWKEY_NUM_OPERANDS; i++)
get_random_bytes(&keydata.value[i], sizeof(struct reg_128_bit));

+ keydata.hwrand = (use_hwrand && keyhwrand_available && keybackup_available);
+ if (use_hwrand && !keydata.hwrand)
+ pr_warn("x86/keylocker: hardware random key not fully supported\n");
+
keydata.valid = true;
}

@@ -63,12 +72,22 @@ void invalidate_keylocker_data(void)
}

#define USE_SWKEY 0
+#define USE_HWRANDKEY BIT(1)

bool load_keylocker(void)
{
struct reg_128_bit zeros = { 0 };
- u32 keysrc = USE_SWKEY;
bool err = true;
+ u32 keysrc;
+ int retry;
+
+ if (keydata.hwrand) {
+ keysrc = USE_HWRANDKEY;
+ retry = LOADIWKEY_HWRAND_RETRY;
+ } else {
+ keysrc = USE_SWKEY;
+ retry = 0;
+ }

kernel_fpu_begin();

@@ -77,13 +96,19 @@ bool load_keylocker(void)
"m"(keydata.value[1]),
"m"(keydata.value[2]));

- asm volatile (LOADIWKEY CC_SET(z) : CC_OUT(z) (err) : "a"(keysrc));
+ do {
+ asm volatile (LOADIWKEY CC_SET(z) : CC_OUT(z) (err) : "a"(keysrc));
+ retry--;
+ } while (err && retry >= 0);

asm volatile ("movdqu %0, %%xmm0; movdqu %0, %%xmm1; movdqu %0, %%xmm2;"
:: "m"(zeros));

kernel_fpu_end();

+ if (keydata.hwrand)
+ invalidate_keylocker_data();
+
return err ? false : true;
}

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 2a41b21623ae..3ee0d659ab2a 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -781,6 +781,12 @@ static int __init parse_trust_cpu(char *arg)
}
early_param("random.trust_cpu", parse_trust_cpu);

+bool check_random_trust_cpu(void)
+{
+ return trust_cpu;
+}
+EXPORT_SYMBOL(check_random_trust_cpu);
+
static bool crng_init_try_arch(struct crng_state *crng)
{
int i;
diff --git a/include/linux/random.h b/include/linux/random.h
index f45b8be3e3c4..f08f44988b13 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -158,4 +158,6 @@ static inline bool __init arch_get_random_long_early(unsigned long *v)
}
#endif

+extern bool check_random_trust_cpu(void);
+
#endif /* _LINUX_RANDOM_H */
--
2.17.1