@@ -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
@@ -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) {
@@ -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;
}
@@ -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;
@@ -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 */
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@intel.com> Cc: Mark Brown <broonie@kernel.org> Cc: x86@kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- 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(-)