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:
commit
99a2c789dd
5 changed files with 85 additions and 16 deletions
|
@ -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>
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(¬_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(¬_filled_random_ptr_key)) {
|
if (static_branch_unlikely(¬_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 */
|
||||||
|
|
Loading…
Reference in a new issue