From 8ddd6efa56c3fe23df9fe4cf5e2b49cc55416ef4 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Fri, 22 Jun 2018 09:15:31 +1000 Subject: [PATCH 1/7] random: Fix whitespace pre random-bytes work There are a couple of whitespace issues around the function get_random_bytes_arch(). In preparation for patching this function let's clean them up. Acked-by: Theodore Ts'o Signed-off-by: Tobin C. Harding Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index bd449ad52442..8e53e9515a1d 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1737,7 +1737,7 @@ void get_random_bytes_arch(void *buf, int nbytes) if (!arch_get_random_long(&v)) break; - + memcpy(p, &v, chunk); p += chunk; nbytes -= chunk; @@ -1748,7 +1748,6 @@ void get_random_bytes_arch(void *buf, int nbytes) } EXPORT_SYMBOL(get_random_bytes_arch); - /* * init_std_data - initialize pool with system data * From 753d433b586d1d43c487e3d660f5778c7c8d58ea Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Fri, 22 Jun 2018 09:15:32 +1000 Subject: [PATCH 2/7] random: Return nbytes filled from hw RNG Currently the function get_random_bytes_arch() has return value 'void'. If the hw RNG fails we currently fall back to using get_random_bytes(). This defeats the purpose of requesting random material from the hw RNG in the first place. There are currently no intree users of get_random_bytes_arch(). Only get random bytes from the hw RNG, make function return the number of bytes retrieved from the hw RNG. Acked-by: Theodore Ts'o Reviewed-by: Steven Rostedt (VMware) Signed-off-by: Tobin C. Harding Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 16 +++++++++------- include/linux/random.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 8e53e9515a1d..34ddfd57419b 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1725,26 +1725,28 @@ EXPORT_SYMBOL(del_random_ready_callback); * 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 * 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; - trace_get_random_bytes_arch(nbytes, _RET_IP_); - while (nbytes) { + trace_get_random_bytes_arch(left, _RET_IP_); + while (left) { 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)) break; memcpy(p, &v, chunk); p += chunk; - nbytes -= chunk; + left -= chunk; } - if (nbytes) - get_random_bytes(p, nbytes); + return nbytes - left; } EXPORT_SYMBOL(get_random_bytes_arch); diff --git a/include/linux/random.h b/include/linux/random.h index 2ddf13b4281e..f1c9bc5cd231 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -38,7 +38,7 @@ extern void get_random_bytes(void *buf, int nbytes); extern int wait_for_random_bytes(void); extern int add_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 extern const struct file_operations random_fops, urandom_fops; From 1c4facb846c7f863bc65483394e80acdbacf671b Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Fri, 22 Jun 2018 09:15:33 +1000 Subject: [PATCH 3/7] vsprintf: Use hw RNG for ptr_key Currently we must wait for enough entropy to become available before hashed pointers can be printed. We can remove this wait by using the hw RNG if available. Use hw RNG to get keying material. Reviewed-by: Steven Rostedt (VMware) Suggested-by: Kees Cook Signed-off-by: Tobin C. Harding Signed-off-by: Theodore Ts'o --- lib/vsprintf.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index a48aaa79d352..6c1fb395bddf 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1675,8 +1675,16 @@ static struct random_ready_callback random_ready = { 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) { return 0; } else if (ret == -EALREADY) { From 3672476edaa0660eb833f54fa9edeb505417b75c Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Fri, 22 Jun 2018 09:15:34 +1000 Subject: [PATCH 4/7] vsprintf: Add command line option debug_boot_weak_hash Currently printing [hashed] pointers requires enough entropy to be available. Early in the boot sequence this may not be the case resulting in a dummy string '(____ptrval____)' being printed. This makes debugging the early boot sequence difficult. We can relax the requirement to use cryptographically secure hashing during debugging. This enables debugging while keeping development/production kernel behaviour the same. If new command line option debug_boot_weak_hash is enabled use cryptographically insecure hashing and hash pointer value immediately. Reviewed-by: Steven Rostedt (VMware) Signed-off-by: Tobin C. Harding Signed-off-by: Theodore Ts'o --- Documentation/admin-guide/kernel-parameters.txt | 8 ++++++++ lib/vsprintf.c | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index efc7aa7a0670..0c8f7889efa1 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -748,6 +748,14 @@ 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= [KNL] verbose self-tests Format=<0|1> diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 6c1fb395bddf..1ee2829f3b54 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -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); } +/* 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 siphash_key_t ptr_key __read_mostly; @@ -1703,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)"; 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)) { spec.field_width = 2 * sizeof(ptr); /* string length must be less than default_width */ From 39a8883a2b989d1d21bd8dd99f5557f0c5e89694 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 17 Jul 2018 18:24:27 -0400 Subject: [PATCH 5/7] random: add a config option to trust the CPU's hwrng This gives the user building their own kernel (or a Linux distribution) the option of deciding whether or not to trust the CPU's hardware random number generator (e.g., RDRAND for x86 CPU's) as being correctly implemented and not having a back door introduced (perhaps courtesy of a Nation State's law enforcement or intelligence agencies). This will prevent getrandom(2) from blocking, if there is a willingness to trust the CPU manufacturer. Signed-off-by: Theodore Ts'o --- drivers/char/Kconfig | 14 ++++++++++++++ drivers/char/random.c | 11 ++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 212f447938ae..ce277ee0a28a 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -554,3 +554,17 @@ config ADI 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. + diff --git a/drivers/char/random.c b/drivers/char/random.c index 34ddfd57419b..f4013b8a711b 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -782,6 +782,7 @@ static void invalidate_batched_entropy(void); static void crng_initialize(struct crng_state *crng) { int i; + int arch_init = 1; unsigned long rv; 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); for (i = 4; i < 16; i++) { if (!arch_get_random_seed_long(&rv) && - !arch_get_random_long(&rv)) + !arch_get_random_long(&rv)) { rv = random_get_entropy(); + arch_init = 0; + } 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; } From b34fbaa9289328c7aec67d2b8b8b7d02bc61c67d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 22 Jul 2018 10:51:50 -0400 Subject: [PATCH 6/7] random: remove preempt disabled region No need to keep preemption disabled across the whole function. mix_pool_bytes() uses a spin_lock() to protect the pool and there are other places like write_pool() whhich invoke mix_pool_bytes() without disabling preemption. credit_entropy_bits() is invoked from other places like add_hwgenerator_randomness() without disabling preemption. Before commit 95b709b6be49 ("random: drop trickle mode") the function used __this_cpu_inc_return() which would require disabled preemption. The preempt_disable() section was added in commit 43d5d3018c37 ("[PATCH] random driver preempt robustness", history tree). It was claimed that the code relied on "vt_ioctl() being called under BKL". Cc: "Theodore Ts'o" Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner [bigeasy: enhance the commit message] Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index f4013b8a711b..561082d46a82 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1131,8 +1131,6 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) } sample; long delta, delta2, delta3; - preempt_disable(); - sample.jiffies = jiffies; sample.cycles = random_get_entropy(); sample.num = num; @@ -1170,8 +1168,6 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) * and limit entropy entimate to 12 bits. */ credit_entropy_bits(r, min_t(int, fls(delta>>1), 11)); - - preempt_enable(); } void add_input_randomness(unsigned int type, unsigned int code, From 9a47249d444d344051c7c0e909fad0e88515a5c2 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 31 Jul 2018 21:11:00 +0200 Subject: [PATCH 7/7] random: Make crng state queryable It is very useful to be able to know whether or not get_random_bytes_wait / wait_for_random_bytes is going to block or not, or whether plain get_random_bytes is going to return good randomness or bad randomness. The particular use case is for mitigating certain attacks in WireGuard. A handshake packet arrives and is queued up. Elsewhere a worker thread takes items from the queue and processes them. In replying to these items, it needs to use some random data, and it has to be good random data. If we simply block until we can have good randomness, then it's possible for an attacker to fill the queue up with packets waiting to be processed. Upon realizing the queue is full, WireGuard will detect that it's under a denial of service attack, and behave accordingly. A better approach is just to drop incoming handshake packets if the crng is not yet initialized. This patch, therefore, makes that information directly accessible. Signed-off-by: Jason A. Donenfeld Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 15 +++++++++++++++ include/linux/random.h | 1 + 2 files changed, 16 insertions(+) diff --git a/drivers/char/random.c b/drivers/char/random.c index 561082d46a82..bf5f99fc36f1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1663,6 +1663,21 @@ int wait_for_random_bytes(void) } 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 * pool is initialised. diff --git a/include/linux/random.h b/include/linux/random.h index f1c9bc5cd231..445a0ea4ff49 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -36,6 +36,7 @@ extern void add_interrupt_randomness(int irq, int irq_flags) __latent_entropy; extern void get_random_bytes(void *buf, int nbytes); 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 void del_random_ready_callback(struct random_ready_callback *rdy); extern int __must_check get_random_bytes_arch(void *buf, int nbytes);