0d054d4e82
Under earlyprintk, each RNG call produces a debug report line. To support the future FGKASLR feature, which will fetch random bytes during function shuffling, this is not useful information (each line is identical and tells us nothing new), needlessly spamming the console. Instead, allow for a NULL "purpose" to suppress the debug reporting. Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Nick Desaulniers <ndesaulniers@google.com> Link: https://lore.kernel.org/r/20211013175742.1197608-3-keescook@chromium.org
99 lines
2.2 KiB
C
99 lines
2.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Entropy functions used on early boot for KASLR base and memory
|
|
* randomization. The base randomization is done in the compressed
|
|
* kernel and memory randomization is done early when the regular
|
|
* kernel starts. This file is included in the compressed kernel and
|
|
* normally linked in the regular.
|
|
*/
|
|
#include <asm/asm.h>
|
|
#include <asm/kaslr.h>
|
|
#include <asm/msr.h>
|
|
#include <asm/archrandom.h>
|
|
#include <asm/e820/api.h>
|
|
#include <asm/io.h>
|
|
|
|
/*
|
|
* When built for the regular kernel, several functions need to be stubbed out
|
|
* or changed to their regular kernel equivalent.
|
|
*/
|
|
#ifndef KASLR_COMPRESSED_BOOT
|
|
#include <asm/cpufeature.h>
|
|
#include <asm/setup.h>
|
|
|
|
#define debug_putstr(v) early_printk("%s", v)
|
|
#define has_cpuflag(f) boot_cpu_has(f)
|
|
#define get_boot_seed() kaslr_offset()
|
|
#endif
|
|
|
|
#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;
|
|
}
|
|
|
|
unsigned long kaslr_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;
|
|
|
|
if (purpose) {
|
|
debug_putstr(purpose);
|
|
debug_putstr(" KASLR using");
|
|
}
|
|
|
|
if (has_cpuflag(X86_FEATURE_RDRAND)) {
|
|
if (purpose)
|
|
debug_putstr(" RDRAND");
|
|
if (rdrand_long(&raw)) {
|
|
random ^= raw;
|
|
use_i8254 = false;
|
|
}
|
|
}
|
|
|
|
if (has_cpuflag(X86_FEATURE_TSC)) {
|
|
if (purpose)
|
|
debug_putstr(" RDTSC");
|
|
raw = rdtsc();
|
|
|
|
random ^= raw;
|
|
use_i8254 = false;
|
|
}
|
|
|
|
if (use_i8254) {
|
|
if (purpose)
|
|
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;
|
|
|
|
if (purpose)
|
|
debug_putstr("...\n");
|
|
|
|
return random;
|
|
}
|