Some changes to trust cpu-based hwrng (such as RDRAND) for

initializing hashed pointers and (optionally, controlled by a config
 option) to initialize the CRNG to avoid boot hangs.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAltyBEkACgkQ8vlZVpUN
 gaNZ6wgAhNyYLr2c0V0UnQyvguZXcJLBerqqGh9XvG//66kXUvYfT0NJSd2i7DZ/
 u4ypf9NxfG4/emg2DDy3r+K/UjhgCIKKjzfp2MzYeEptJGg9V9EV7v1YtFJYs39g
 cPmFv1l7fPNqe3qXXsbuZe2pSnJfEfzHeOStDNrEX1CJStt+LC7HRz1/dIcgycOa
 CsB3yILQpgxu9HcVCfIeDtxjly7GQYTJKQGLAe/8MdatZ96HW/E4obvnDZhuFtCH
 54OumcKhFXiODFLpBsK3Bllk2v9fO1Gq/SuYmNA85mXqbZVAUV2YNZK2HWASXwkB
 NxwRcfLywgqfYmtvpp63rHSjJB76AQ==
 =l9HN
 -----END PGP SIGNATURE-----

Merge tag 'random_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random

Pull random updates from Ted Ts'o:
 "Some changes to trust cpu-based hwrng (such as RDRAND) for
  initializing hashed pointers and (optionally, controlled by a config
  option) to initialize the CRNG to avoid boot hangs"

* tag 'random_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random:
  random: Make crng state queryable
  random: remove preempt disabled region
  random: add a config option to trust the CPU's hwrng
  vsprintf: Add command line option debug_boot_weak_hash
  vsprintf: Use hw RNG for ptr_key
  random: Return nbytes filled from hw RNG
  random: Fix whitespace pre random-bytes work
This commit is contained in:
Linus Torvalds 2018-08-15 21:16:02 -07:00
commit 99a2c789dd
5 changed files with 85 additions and 16 deletions

View file

@ -748,6 +748,14 @@
debug [KNL] Enable kernel debugging (events log level). debug [KNL] Enable kernel debugging (events log level).
debug_boot_weak_hash
[KNL] Enable printing [hashed] pointers early in the
boot sequence. If enabled, we use a weak hash instead
of siphash to hash pointers. Use this option if you are
seeing instances of '(___ptrval___)') and need to see a
value (hashed pointer) instead. Cryptographically
insecure, please do not use on production kernels.
debug_locks_verbose= debug_locks_verbose=
[KNL] verbose self-tests [KNL] verbose self-tests
Format=<0|1> Format=<0|1>

View file

@ -554,3 +554,17 @@ config ADI
endmenu endmenu
config RANDOM_TRUST_CPU
bool "Trust the CPU manufacturer to initialize Linux's CRNG"
depends on X86 || S390 || PPC
default n
help
Assume that CPU manufacturer (e.g., Intel or AMD for RDSEED or
RDRAND, IBM for the S390 and Power PC architectures) is trustworthy
for the purposes of initializing Linux's CRNG. Since this is not
something that can be independently audited, this amounts to trusting
that CPU manufacturer (perhaps with the insistence or mandate
of a Nation State's intelligence or law enforcement agencies)
has not installed a hidden back door to compromise the CPU's
random number generation facilities.

View file

@ -782,6 +782,7 @@ static void invalidate_batched_entropy(void);
static void crng_initialize(struct crng_state *crng) static void crng_initialize(struct crng_state *crng)
{ {
int i; int i;
int arch_init = 1;
unsigned long rv; unsigned long rv;
memcpy(&crng->state[0], "expand 32-byte k", 16); memcpy(&crng->state[0], "expand 32-byte k", 16);
@ -792,10 +793,18 @@ static void crng_initialize(struct crng_state *crng)
_get_random_bytes(&crng->state[4], sizeof(__u32) * 12); _get_random_bytes(&crng->state[4], sizeof(__u32) * 12);
for (i = 4; i < 16; i++) { for (i = 4; i < 16; i++) {
if (!arch_get_random_seed_long(&rv) && if (!arch_get_random_seed_long(&rv) &&
!arch_get_random_long(&rv)) !arch_get_random_long(&rv)) {
rv = random_get_entropy(); rv = random_get_entropy();
arch_init = 0;
}
crng->state[i] ^= rv; crng->state[i] ^= rv;
} }
#ifdef CONFIG_RANDOM_TRUST_CPU
if (arch_init) {
crng_init = 2;
pr_notice("random: crng done (trusting CPU's manufacturer)\n");
}
#endif
crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
} }
@ -1122,8 +1131,6 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
} sample; } sample;
long delta, delta2, delta3; long delta, delta2, delta3;
preempt_disable();
sample.jiffies = jiffies; sample.jiffies = jiffies;
sample.cycles = random_get_entropy(); sample.cycles = random_get_entropy();
sample.num = num; sample.num = num;
@ -1161,8 +1168,6 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
* and limit entropy entimate to 12 bits. * and limit entropy entimate to 12 bits.
*/ */
credit_entropy_bits(r, min_t(int, fls(delta>>1), 11)); credit_entropy_bits(r, min_t(int, fls(delta>>1), 11));
preempt_enable();
} }
void add_input_randomness(unsigned int type, unsigned int code, void add_input_randomness(unsigned int type, unsigned int code,
@ -1658,6 +1663,21 @@ int wait_for_random_bytes(void)
} }
EXPORT_SYMBOL(wait_for_random_bytes); EXPORT_SYMBOL(wait_for_random_bytes);
/*
* Returns whether or not the urandom pool has been seeded and thus guaranteed
* to supply cryptographically secure random numbers. This applies to: the
* /dev/urandom device, the get_random_bytes function, and the get_random_{u32,
* ,u64,int,long} family of functions.
*
* Returns: true if the urandom pool has been seeded.
* false if the urandom pool has not been seeded.
*/
bool rng_is_initialized(void)
{
return crng_ready();
}
EXPORT_SYMBOL(rng_is_initialized);
/* /*
* Add a callback function that will be invoked when the nonblocking * Add a callback function that will be invoked when the nonblocking
* pool is initialised. * pool is initialised.
@ -1725,30 +1745,31 @@ EXPORT_SYMBOL(del_random_ready_callback);
* key known by the NSA). So it's useful if we need the speed, but * key known by the NSA). So it's useful if we need the speed, but
* only if we're willing to trust the hardware manufacturer not to * only if we're willing to trust the hardware manufacturer not to
* have put in a back door. * have put in a back door.
*
* Return number of bytes filled in.
*/ */
void get_random_bytes_arch(void *buf, int nbytes) int __must_check get_random_bytes_arch(void *buf, int nbytes)
{ {
int left = nbytes;
char *p = buf; char *p = buf;
trace_get_random_bytes_arch(nbytes, _RET_IP_); trace_get_random_bytes_arch(left, _RET_IP_);
while (nbytes) { while (left) {
unsigned long v; unsigned long v;
int chunk = min(nbytes, (int)sizeof(unsigned long)); int chunk = min_t(int, left, sizeof(unsigned long));
if (!arch_get_random_long(&v)) if (!arch_get_random_long(&v))
break; break;
memcpy(p, &v, chunk); memcpy(p, &v, chunk);
p += chunk; p += chunk;
nbytes -= chunk; left -= chunk;
} }
if (nbytes) return nbytes - left;
get_random_bytes(p, nbytes);
} }
EXPORT_SYMBOL(get_random_bytes_arch); EXPORT_SYMBOL(get_random_bytes_arch);
/* /*
* init_std_data - initialize pool with system data * init_std_data - initialize pool with system data
* *

View file

@ -36,9 +36,10 @@ extern void add_interrupt_randomness(int irq, int irq_flags) __latent_entropy;
extern void get_random_bytes(void *buf, int nbytes); extern void get_random_bytes(void *buf, int nbytes);
extern int wait_for_random_bytes(void); extern int wait_for_random_bytes(void);
extern bool rng_is_initialized(void);
extern int add_random_ready_callback(struct random_ready_callback *rdy); extern int add_random_ready_callback(struct random_ready_callback *rdy);
extern void del_random_ready_callback(struct random_ready_callback *rdy); extern void del_random_ready_callback(struct random_ready_callback *rdy);
extern void get_random_bytes_arch(void *buf, int nbytes); extern int __must_check get_random_bytes_arch(void *buf, int nbytes);
#ifndef MODULE #ifndef MODULE
extern const struct file_operations random_fops, urandom_fops; extern const struct file_operations random_fops, urandom_fops;

View file

@ -1651,6 +1651,17 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
return widen_string(buf, buf - buf_start, end, spec); return widen_string(buf, buf - buf_start, end, spec);
} }
/* Make pointers available for printing early in the boot sequence. */
static int debug_boot_weak_hash __ro_after_init;
static int __init debug_boot_weak_hash_enable(char *str)
{
debug_boot_weak_hash = 1;
pr_info("debug_boot_weak_hash enabled\n");
return 0;
}
early_param("debug_boot_weak_hash", debug_boot_weak_hash_enable);
static DEFINE_STATIC_KEY_TRUE(not_filled_random_ptr_key); static DEFINE_STATIC_KEY_TRUE(not_filled_random_ptr_key);
static siphash_key_t ptr_key __read_mostly; static siphash_key_t ptr_key __read_mostly;
@ -1675,8 +1686,16 @@ static struct random_ready_callback random_ready = {
static int __init initialize_ptr_random(void) static int __init initialize_ptr_random(void)
{ {
int ret = add_random_ready_callback(&random_ready); int key_size = sizeof(ptr_key);
int ret;
/* Use hw RNG if available. */
if (get_random_bytes_arch(&ptr_key, key_size) == key_size) {
static_branch_disable(&not_filled_random_ptr_key);
return 0;
}
ret = add_random_ready_callback(&random_ready);
if (!ret) { if (!ret) {
return 0; return 0;
} else if (ret == -EALREADY) { } else if (ret == -EALREADY) {
@ -1695,6 +1714,12 @@ static char *ptr_to_id(char *buf, char *end, void *ptr, struct printf_spec spec)
const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)"; const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)";
unsigned long hashval; unsigned long hashval;
/* When debugging early boot use non-cryptographically secure hash. */
if (unlikely(debug_boot_weak_hash)) {
hashval = hash_long((unsigned long)ptr, 32);
return pointer_string(buf, end, (const void *)hashval, spec);
}
if (static_branch_unlikely(&not_filled_random_ptr_key)) { if (static_branch_unlikely(&not_filled_random_ptr_key)) {
spec.field_width = 2 * sizeof(ptr); spec.field_width = 2 * sizeof(ptr);
/* string length must be less than default_width */ /* string length must be less than default_width */