Blob Blame History Raw
From 03dc808fb73d82b882cc7080fc9a1f774a5add83 Mon Sep 17 00:00:00 2001
From: "Lee, Chun-Yi" <jlee@suse.com>
Date: Mon, 11 Dec 2017 22:11:36 +0800
Subject: [PATCH 03/11] x86/KASLR: public the function for getting random long
 number
Patch-mainline: Never, SUSE-specific
References: fate#316350

Separating the functions for getting random long number from KASLR
to x86 library, then it can be used to generate random long for
EFI secret key.

Joey Lee:
The EFI secure key mechanism be rejected by kernel upstream because
- The entropy inputs in EFI boot stage are too weak for key generation.
  - SLE applied RDRAND (x86) or EFI_RNG_PROTOCOL to grab stronger entropy.
- The UEFI variable store was not designed with confidentiality in mind.
  Secure boot relies on Microsoft's Business interests. Microsoft doesn't
  use UEFI variables for confidentiality, so we shouldn't either.

References: https://lkml.org/lkml/2018/8/5/10
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 arch/x86/boot/compressed/kaslr.c |   21 ------------
 arch/x86/boot/compressed/misc.c  |   17 ++++++++++
 arch/x86/boot/compressed/misc.h  |    6 +++
 arch/x86/lib/random.c            |   66 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 89 insertions(+), 21 deletions(-)
 create mode 100644 arch/x86/lib/random.c

--- a/arch/x86/boot/compressed/kaslr.c
+++ b/arch/x86/boot/compressed/kaslr.c
@@ -30,13 +30,11 @@
 #include "error.h"
 #include "../string.h"
 
-#include <generated/compile.h>
 #include <linux/module.h>
 #include <linux/uts.h>
 #include <linux/utsname.h>
 #include <linux/ctype.h>
 #include <linux/efi.h>
-#include <generated/utsrelease.h>
 #include <asm/efi.h>
 
 /* Macros used by the included decompressor code below. */
@@ -54,25 +52,6 @@ extern unsigned long get_cmd_line_ptr(vo
 /* Used by PAGE_KERN* macros: */
 pteval_t __default_kernel_pte_mask __read_mostly = ~0;
 
-/* Simplified build-specific string for starting entropy. */
-static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
-		LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
-
-static unsigned long rotate_xor(unsigned long hash, const void *area,
-				size_t size)
-{
-	size_t i;
-	unsigned long *ptr = (unsigned long *)area;
-
-	for (i = 0; i < size / sizeof(hash); i++) {
-		/* Rotate by odd number of bits and XOR. */
-		hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
-		hash ^= ptr[i];
-	}
-
-	return hash;
-}
-
 /* Attempt to create a simple but unpredictable starting entropy. */
 static unsigned long get_boot_seed(void)
 {
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -448,3 +448,20 @@ void fortify_panic(const char *name)
 {
 	error("detected buffer overflow");
 }
+
+#if CONFIG_RANDOMIZE_BASE
+unsigned long rotate_xor(unsigned long hash, const void *area,
+			size_t size)
+{
+	size_t i;
+	unsigned long *ptr = (unsigned long *)area;
+
+	for (i = 0; i < size / sizeof(hash); i++) {
+		/* Rotate by odd number of bits and XOR. */
+		hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
+		hash ^= ptr[i];
+	}
+
+	return hash;
+}
+#endif
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -75,6 +75,8 @@ struct mem_vector {
 };
 
 #if CONFIG_RANDOMIZE_BASE
+#include <generated/compile.h>
+#include <generated/utsrelease.h>
 /* kaslr.c */
 void choose_random_location(unsigned long input,
 			    unsigned long input_size,
@@ -83,6 +85,10 @@ void choose_random_location(unsigned lon
 			    unsigned long *virt_addr);
 /* cpuflags.c */
 bool has_cpuflag(int flag);
+/* Simplified build-specific string for starting entropy. */
+static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
+		LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
+unsigned long rotate_xor(unsigned long hash, const void *area, size_t size);
 #else
 static inline void choose_random_location(unsigned long input,
 					  unsigned long input_size,
--- /dev/null
+++ b/arch/x86/lib/random.c
@@ -0,0 +1,66 @@
+#include <asm/io.h>
+#include <asm/archrandom.h>
+
+#define I8254_PORT_CONTROL	0x43
+#define I8254_PORT_COUNTER0	0x40
+#define I8254_CMD_READBACK	0xC0
+#define I8254_SELECT_COUNTER0	0x02
+#define I8254_STATUS_NOTREADY	0x40
+static inline u16 i8254(void)
+{
+	u16 status, timer;
+
+	do {
+		outb(I8254_CMD_READBACK | I8254_SELECT_COUNTER0,
+		     I8254_PORT_CONTROL);
+		status = inb(I8254_PORT_COUNTER0);
+		timer  = inb(I8254_PORT_COUNTER0);
+		timer |= inb(I8254_PORT_COUNTER0) << 8;
+	} while (status & I8254_STATUS_NOTREADY);
+
+	return timer;
+}
+
+static unsigned long get_random_long(const char *purpose)
+{
+#ifdef CONFIG_X86_64
+	const unsigned long mix_const = 0x5d6008cbf3848dd3UL;
+#else
+	const unsigned long mix_const = 0x3f39e593UL;
+#endif
+	unsigned long raw, random = get_boot_seed();
+	bool use_i8254 = true;
+
+	debug_putstr(purpose);
+
+	if (has_cpuflag(X86_FEATURE_RDRAND)) {
+		debug_putstr(" RDRAND");
+		if (rdrand_long(&raw)) {
+			random ^= raw;
+			use_i8254 = false;
+		}
+	}
+
+	if (has_cpuflag(X86_FEATURE_TSC)) {
+		debug_putstr(" RDTSC");
+		raw = rdtsc();
+
+		random ^= raw;
+		use_i8254 = false;
+	}
+
+	if (use_i8254) {
+		debug_putstr(" i8254");
+		random ^= i8254();
+	}
+
+	/* Circular multiply for better bit diffusion */
+	asm(_ASM_MUL "%3"
+	    : "=a" (random), "=d" (raw)
+	    : "a" (random), "rm" (mix_const));
+	random += raw;
+
+	debug_putstr("...\n");
+
+	return random;
+}