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: No, will be submitted to upstream
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.
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
@@ -31,13 +31,11 @@
#include "misc.h"
#include "error.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. */
@@ -46,25 +44,6 @@
extern unsigned long get_cmd_line_ptr(void);
-/* 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
@@ -431,3 +431,20 @@ asmlinkage __visible void *extract_kerne
debug_putstr("done.\nBooting the kernel.\n");
return output;
}
+
+#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
@@ -66,6 +66,8 @@ int cmdline_find_option_bool(const char
#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,
@@ -74,6 +76,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;
+}