From nobody Sun Jun 28 06:40:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 359A3C433EF for ; Fri, 11 Feb 2022 12:36:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350152AbiBKMgP (ORCPT ); Fri, 11 Feb 2022 07:36:15 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41744 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235615AbiBKMgL (ORCPT ); Fri, 11 Feb 2022 07:36:11 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B93A72BF for ; Fri, 11 Feb 2022 04:36:08 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 60CFDB829DD for ; Fri, 11 Feb 2022 12:36:07 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 70BB4C340EE; Fri, 11 Feb 2022 12:36:05 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="CQi9nD97" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644582964; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LWzS0mxyHFBKh8dXUL5dPMBahNNosCP3EmVR3IgONbg=; b=CQi9nD97NsPudnIPE1es0Qm7PifDhTex3yZuRY5QWTEXMv7rgzd8Z2RLsLhiFeBOlV7kKR TyUalwUF7uvNiGkhfeODwSkxI92f7N/WGR5XIOlKR/zPtp/mzYAe4pPEPUFlMrSGP312gL qDC8/Ul2XgN4PcFlPqFf0brYMfkpN64= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id a7c5a99a (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 11 Feb 2022 12:36:04 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH 1/9] random: introduce drain_entropy() helper to declutter crng_reseed() Date: Fri, 11 Feb 2022 13:35:38 +0100 Message-Id: <20220211123546.474952-2-Jason@zx2c4.com> In-Reply-To: <20220211123546.474952-1-Jason@zx2c4.com> References: <20220211123546.474952-1-Jason@zx2c4.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" In preparation for separating responsibilities, break out the entropy count management part of crng_reseed() into its own function. No functional changes. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld --- drivers/char/random.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 44a20a1a1b3a..436b146b33be 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -260,6 +260,7 @@ static struct { }; =20 static void extract_entropy(void *buf, size_t nbytes); +static bool drain_entropy(void *buf, size_t nbytes); =20 static void crng_reseed(void); =20 @@ -453,22 +454,13 @@ static void crng_slow_load(const void *cp, size_t len) static void crng_reseed(void) { unsigned long flags; - int entropy_count; unsigned long next_gen; u8 key[CHACHA_KEY_SIZE]; bool finalize_init =3D false; =20 - /* First we make sure we have POOL_MIN_BITS of entropy in the pool, - * and then we drain all of it. Only then can we extract a new key. - */ - do { - entropy_count =3D READ_ONCE(input_pool.entropy_count); - if (entropy_count < POOL_MIN_BITS) - return; - } while (cmpxchg(&input_pool.entropy_count, entropy_count, 0) !=3D entrop= y_count); - extract_entropy(key, sizeof(key)); - wake_up_interruptible(&random_write_wait); - kill_fasync(&fasync, SIGIO, POLL_OUT); + /* Only reseed if we can, to prevent brute forcing a small amount of new = bits. */ + if (!drain_entropy(key, sizeof(key))) + return; =20 /* We copy the new key into the base_crng, overwriting the old one, * and update the generation counter. We avoid hitting ULONG_MAX, @@ -893,6 +885,25 @@ static void extract_entropy(void *buf, size_t nbytes) memzero_explicit(&block, sizeof(block)); } =20 +/* + * First we make sure we have POOL_MIN_BITS of entropy in the pool, + * and then we drain all of it. Only then can we extract a new key + * with extract_entropy(). + */ +static bool drain_entropy(void *buf, size_t nbytes) +{ + unsigned int entropy_count; + do { + entropy_count =3D READ_ONCE(input_pool.entropy_count); + if (entropy_count < POOL_MIN_BITS) + return false; + } while (cmpxchg(&input_pool.entropy_count, entropy_count, 0) !=3D entrop= y_count); + extract_entropy(buf, nbytes); + wake_up_interruptible(&random_write_wait); + kill_fasync(&fasync, SIGIO, POLL_OUT); + return true; +} + #define warn_unseeded_randomness(previous) \ _warn_unseeded_randomness(__func__, (void *)_RET_IP_, (previous)) =20 --=20 2.35.0 From nobody Sun Jun 28 06:40:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 065C2C433F5 for ; Fri, 11 Feb 2022 12:36:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350165AbiBKMgR (ORCPT ); Fri, 11 Feb 2022 07:36:17 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41746 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243958AbiBKMgL (ORCPT ); Fri, 11 Feb 2022 07:36:11 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 062BADB3 for ; Fri, 11 Feb 2022 04:36:09 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 918E361D64 for ; Fri, 11 Feb 2022 12:36:08 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id AB01FC340E9; Fri, 11 Feb 2022 12:36:07 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="QBB72DiJ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644582967; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HyNsVaUyQWOPLIUs8NzWo56+7MmoIS24JC7SU4iNpOc=; b=QBB72DiJGxEYs11e7lVekH2F1M1hCb+/hTdG479c9LMVCqhsuU1HQ6JrtalBkbGogRWGyn oNrNjp1cAeGQEzsItFvCWb03iQSm7XhWl6/MCS77PZ23lbKdlKo8spVlFR+TSeGoNrZseg dc6E84C2EpEu7Ens84nQxbJqwnAHBcU= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 75506883 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 11 Feb 2022 12:36:06 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH 2/9] random: remove useless header comment Date: Fri, 11 Feb 2022 13:35:39 +0100 Message-Id: <20220211123546.474952-3-Jason@zx2c4.com> In-Reply-To: <20220211123546.474952-1-Jason@zx2c4.com> References: <20220211123546.474952-1-Jason@zx2c4.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This really adds nothing at all useful. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld --- include/linux/random.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/linux/random.h b/include/linux/random.h index e92efb39779c..37e1e8c43d7e 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -1,9 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * include/linux/random.h - * - * Include file for the random number generator. - */ + #ifndef _LINUX_RANDOM_H #define _LINUX_RANDOM_H =20 --=20 2.35.0 From nobody Sun Jun 28 06:40:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AB561C433F5 for ; Fri, 11 Feb 2022 12:36:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350160AbiBKMgW (ORCPT ); Fri, 11 Feb 2022 07:36:22 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41790 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1350141AbiBKMgO (ORCPT ); Fri, 11 Feb 2022 07:36:14 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0555DB3 for ; Fri, 11 Feb 2022 04:36:12 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 7A359B829DD for ; Fri, 11 Feb 2022 12:36:11 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id E319CC340E9; Fri, 11 Feb 2022 12:36:09 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="alGXrey+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644582969; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3W9147nzeFnTQhROd6DTBvSjeGMqVmGM0L+osN5FRJA=; b=alGXrey+kCWtpqeSkSNZam3X5XDDhmGLrXs+AyjlObb/vg1+ut7f+s/0epHOZuNPFhI20Y OFDS0k9CzXpL1N42yb9dnSlnnJqAgXdDKhkX1PESXDaG8q0HCDdi998y+TSC/OKuZrWjQD fVKF4KR1ugQo6VmIijrCvWQa1TeeXF8= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 4506ae0d (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 11 Feb 2022 12:36:09 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH 3/9] random: rewrite header introductory comment Date: Fri, 11 Feb 2022 13:35:40 +0100 Message-Id: <20220211123546.474952-4-Jason@zx2c4.com> In-Reply-To: <20220211123546.474952-1-Jason@zx2c4.com> References: <20220211123546.474952-1-Jason@zx2c4.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This top comment is a description of what's to follow below, and hence in the subsequent reorganization commits, where much of this text will resurface. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld --- drivers/char/random.c | 175 ++++-------------------------------------- 1 file changed, 16 insertions(+), 159 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 436b146b33be..149cbd481b96 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -2,168 +2,25 @@ /* * Copyright (C) 2017-2022 Jason A. Donenfeld . All Right= s Reserved. * Copyright Matt Mackall , 2003, 2004, 2005 - * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All - * rights reserved. - */ - -/* - * Exported interfaces ---- output - * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D - * - * There are four exported interfaces; two for use within the kernel, - * and two for use from userspace. - * - * Exported interfaces ---- userspace output - * ----------------------------------------- - * - * The userspace interfaces are two character devices /dev/random and - * /dev/urandom. /dev/random is suitable for use when very high - * quality randomness is desired (for example, for key generation or - * one-time pads), as it will only return a maximum of the number of - * bits of randomness (as estimated by the random number generator) - * contained in the entropy pool. - * - * The /dev/urandom device does not have this limit, and will return - * as many bytes as are requested. As more and more random bytes are - * requested without giving time for the entropy pool to recharge, - * this will result in random numbers that are merely cryptographically - * strong. For many applications, however, this is acceptable. - * - * Exported interfaces ---- kernel output - * -------------------------------------- - * - * The primary kernel interfaces are: - * - * void get_random_bytes(void *buf, size_t nbytes); - * u32 get_random_u32() - * u64 get_random_u64() - * unsigned int get_random_int() - * unsigned long get_random_long() - * - * These interfaces will return the requested number of random bytes - * into the given buffer or as a return value. This is equivalent to a - * read from /dev/urandom. The get_random_{u32,u64,int,long}() family - * of functions may be higher performance for one-off random integers, - * because they do a bit of buffering. - * - * prandom_u32() - * ------------- - * - * For even weaker applications, see the pseudorandom generator - * prandom_u32(), prandom_max(), and prandom_bytes(). If the random - * numbers aren't security-critical at all, these are *far* cheaper. - * Useful for self-tests, random error simulation, randomized backoffs, - * and any other application where you trust that nobody is trying to - * maliciously mess with you by guessing the "random" numbers. - * - * Exported interfaces ---- input - * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D - * - * The current exported interfaces for gathering environmental noise - * from the devices are: - * - * void add_device_randomness(const void *buf, size_t size); - * void add_input_randomness(unsigned int type, unsigned int code, - * unsigned int value); - * void add_interrupt_randomness(int irq); - * void add_disk_randomness(struct gendisk *disk); - * void add_hwgenerator_randomness(const void *buffer, size_t count, - * size_t entropy); - * void add_bootloader_randomness(const void *buf, size_t size); - * - * add_device_randomness() is for adding data to the random pool that - * is likely to differ between two devices (or possibly even per boot). - * This would be things like MAC addresses or serial numbers, or the - * read-out of the RTC. This does *not* add any actual entropy to the - * pool, but it initializes the pool to different values for devices - * that might otherwise be identical and have very little entropy - * available to them (particularly common in the embedded world). - * - * add_input_randomness() uses the input layer interrupt timing, as well as - * the event type information from the hardware. - * - * add_interrupt_randomness() uses the interrupt timing as random - * inputs to the entropy pool. Using the cycle counters and the irq source - * as inputs, it feeds the randomness roughly once a second. - * - * add_disk_randomness() uses what amounts to the seek time of block - * layer request events, on a per-disk_devt basis, as input to the - * entropy pool. Note that high-speed solid state drives with very low - * seek times do not make for good sources of entropy, as their seek - * times are usually fairly consistent. - * - * All of these routines try to estimate how many bits of randomness a - * particular randomness source. They do this by keeping track of the - * first and second order deltas of the event timings. - * - * add_hwgenerator_randomness() is for true hardware RNGs, and will credit - * entropy as specified by the caller. If the entropy pool is full it will - * block until more entropy is needed. - * - * add_bootloader_randomness() is the same as add_hwgenerator_randomness()= or - * add_device_randomness(), depending on whether or not the configuration - * option CONFIG_RANDOM_TRUST_BOOTLOADER is set. - * - * Ensuring unpredictability at system startup - * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - * - * When any operating system starts up, it will go through a sequence - * of actions that are fairly predictable by an adversary, especially - * if the start-up does not involve interaction with a human operator. - * This reduces the actual number of bits of unpredictability in the - * entropy pool below the value in entropy_count. In order to - * counteract this effect, it helps to carry information in the - * entropy pool across shut-downs and start-ups. To do this, put the - * following lines an appropriate script which is run during the boot - * sequence: - * - * echo "Initializing random number generator..." - * random_seed=3D/var/run/random-seed - * # Carry a random seed from start-up to start-up - * # Load and then save the whole entropy pool - * if [ -f $random_seed ]; then - * cat $random_seed >/dev/urandom - * else - * touch $random_seed - * fi - * chmod 600 $random_seed - * dd if=3D/dev/urandom of=3D$random_seed count=3D1 bs=3D512 - * - * and the following lines in an appropriate script which is run as - * the system is shutdown: - * - * # Carry a random seed from shut-down to start-up - * # Save the whole entropy pool - * echo "Saving random seed..." - * random_seed=3D/var/run/random-seed - * touch $random_seed - * chmod 600 $random_seed - * dd if=3D/dev/urandom of=3D$random_seed count=3D1 bs=3D512 - * - * For example, on most modern systems using the System V init - * scripts, such code fragments would be found in - * /etc/rc.d/init.d/random. On older Linux systems, the correct script - * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0. - * - * Effectively, these commands cause the contents of the entropy pool - * to be saved at shut-down time and reloaded into the entropy pool at - * start-up. (The 'dd' in the addition to the bootup script is to - * make sure that /etc/random-seed is different for every start-up, - * even if the system crashes without executing rc.0.) Even with - * complete knowledge of the start-up activities, predicting the state - * of the entropy pool requires knowledge of the previous history of - * the system. + * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All rights= reserved. * - * Configuring the /dev/random driver under Linux - * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + * This driver produces cryptographically secure pseudorandom data. It is = divided + * into roughly 5 sections, each with a section header: * - * The /dev/random driver under Linux uses minor numbers 8 and 9 of - * the /dev/mem major number (#1). So if your system does not have - * /dev/random and /dev/urandom created already, they can be created - * by using the commands: + * - Fast key erasure RNG, the "crng". + * - Entropy accumulation and extraction routines. + * - Entropy collection routines. + * - Userspace reader/writer interfaces. + * - Sysctl interface. * - * mknod /dev/random c 1 8 - * mknod /dev/urandom c 1 9 + * The high level overview is that, there is one input pool, into which + * various pieces of data are hashed. Some of that data is then "credited"= as + * having a certain number of bits of entropy. When enough bits of entropy= are + * available, the hash is finalized and handed as a key to a stream cipher= that + * expands it indefinately for various consumers. This key is periodically + * refreshed as the various entropy collectors, described below, add data = to the + * input pool and credit it. There is currently no Fortuna-like scheduler + * involved, and the entropy estimates are, at best, conservative guesses. */ =20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt --=20 2.35.0 From nobody Sun Jun 28 06:40:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 38522C433EF for ; Fri, 11 Feb 2022 12:36:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350195AbiBKMgZ (ORCPT ); Fri, 11 Feb 2022 07:36:25 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41794 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1350149AbiBKMgO (ORCPT ); Fri, 11 Feb 2022 07:36:14 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 72B76E7F for ; Fri, 11 Feb 2022 04:36:13 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 0D9BD61D44 for ; Fri, 11 Feb 2022 12:36:13 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 280BEC340E9; Fri, 11 Feb 2022 12:36:12 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="jkUXLpA6" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644582971; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=odPvxucA4ukJ1xcX9sf1twPB7IK569mNzy/ygdtdxtc=; b=jkUXLpA6qnXejvp7WTxzbRuz2E6fIErwfBwn8eJo2dJoZbwthkj8KHgFoOm/zogJ2oEhgX 6mM/y/ePFeckjHAlXrdpt2zFyJbrL5TQireNw9AKTlTgUlMYYfyRHHDY6TFXLN5WFO+g1k hczpg5LOh0Ww39sxtiNfRe7JnclNvmM= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 02c654c0 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 11 Feb 2022 12:36:11 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH 4/9] random: group initialization wait functions Date: Fri, 11 Feb 2022 13:35:41 +0100 Message-Id: <20220211123546.474952-5-Jason@zx2c4.com> In-Reply-To: <20220211123546.474952-1-Jason@zx2c4.com> References: <20220211123546.474952-1-Jason@zx2c4.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This pulls all of the readiness waiting-focused functions into the first labeled section. No functional changes. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld --- drivers/char/random.c | 334 ++++++++++++++++++++++-------------------- 1 file changed, 174 insertions(+), 160 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 149cbd481b96..09a85a1a4458 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -59,44 +59,200 @@ #include #include =20 -enum { - POOL_BITS =3D BLAKE2S_HASH_SIZE * 8, - POOL_MIN_BITS =3D POOL_BITS /* No point in settling for less. */ -}; =20 -/* - * Static global variables - */ -static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); -static struct fasync_struct *fasync; - -static DEFINE_SPINLOCK(random_ready_list_lock); -static LIST_HEAD(random_ready_list); +/********************************************************************* + * + * Initialization and readiness waiting. + * + * Much of the RNG infrastructure is devoted to various dependencies + * being able to wait until the RNG has collected enough entropy and + * is ready for safe consumption. + * + *********************************************************************/ =20 /* * crng_init =3D 0 --> Uninitialized * 1 --> Initialized * 2 --> Initialized from input_pool * - * crng_init is protected by primary_crng->lock, and only increases + * crng_init is protected by base_crng->lock, and only increases * its value (from 0->1->2). */ static int crng_init =3D 0; #define crng_ready() (likely(crng_init > 1)) -static int crng_init_cnt =3D 0; -static void process_random_ready_list(void); -static void _get_random_bytes(void *buf, size_t nbytes); +/* Various types of waiters for crng_init->2 transition. */ +static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait); +static struct fasync_struct *fasync; +static DEFINE_SPINLOCK(random_ready_list_lock); +static LIST_HEAD(random_ready_list); =20 +/* Control how we warn userspace. */ static struct ratelimit_state unseeded_warning =3D RATELIMIT_STATE_INIT("warn_unseeded_randomness", HZ, 3); static struct ratelimit_state urandom_warning =3D RATELIMIT_STATE_INIT("warn_urandom_randomness", HZ, 3); - static int ratelimit_disable __read_mostly; - module_param_named(ratelimit_disable, ratelimit_disable, int, 0644); MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression"= ); =20 +/* + * Returns whether or not the urandom pool has been seeded and thus guaran= teed + * 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); + +/* Used by wait_for_random_bytes(), and considered an entropy collector, b= elow. */ +static void try_to_generate_entropy(void); + +/* + * Wait for the urandom pool to be seeded and thus guaranteed to supply + * cryptographically secure random numbers. This applies to: the /dev/uran= dom + * device, the get_random_bytes function, and the get_random_{u32,u64,int,= long} + * family of functions. Using any of these functions without first calling + * this function forfeits the guarantee of security. + * + * Returns: 0 if the urandom pool has been seeded. + * -ERESTARTSYS if the function was interrupted by a signal. + */ +int wait_for_random_bytes(void) +{ + if (likely(crng_ready())) + return 0; + + do { + int ret; + ret =3D wait_event_interruptible_timeout(crng_init_wait, crng_ready(), H= Z); + if (ret) + return ret > 0 ? 0 : ret; + + try_to_generate_entropy(); + } while (!crng_ready()); + + return 0; +} +EXPORT_SYMBOL(wait_for_random_bytes); + +/* + * Add a callback function that will be invoked when the nonblocking + * pool is initialised. + * + * returns: 0 if callback is successfully added + * -EALREADY if pool is already initialised (callback not called) + * -ENOENT if module for callback is not alive + */ +int add_random_ready_callback(struct random_ready_callback *rdy) +{ + struct module *owner; + unsigned long flags; + int err =3D -EALREADY; + + if (crng_ready()) + return err; + + owner =3D rdy->owner; + if (!try_module_get(owner)) + return -ENOENT; + + spin_lock_irqsave(&random_ready_list_lock, flags); + if (crng_ready()) + goto out; + + owner =3D NULL; + + list_add(&rdy->list, &random_ready_list); + err =3D 0; + +out: + spin_unlock_irqrestore(&random_ready_list_lock, flags); + + module_put(owner); + + return err; +} +EXPORT_SYMBOL(add_random_ready_callback); + +/* + * Delete a previously registered readiness callback function. + */ +void del_random_ready_callback(struct random_ready_callback *rdy) +{ + unsigned long flags; + struct module *owner =3D NULL; + + spin_lock_irqsave(&random_ready_list_lock, flags); + if (!list_empty(&rdy->list)) { + list_del_init(&rdy->list); + owner =3D rdy->owner; + } + spin_unlock_irqrestore(&random_ready_list_lock, flags); + + module_put(owner); +} +EXPORT_SYMBOL(del_random_ready_callback); + +static void process_random_ready_list(void) +{ + unsigned long flags; + struct random_ready_callback *rdy, *tmp; + + spin_lock_irqsave(&random_ready_list_lock, flags); + list_for_each_entry_safe(rdy, tmp, &random_ready_list, list) { + struct module *owner =3D rdy->owner; + + list_del_init(&rdy->list); + rdy->func(rdy); + module_put(owner); + } + spin_unlock_irqrestore(&random_ready_list_lock, flags); +} + +#define warn_unseeded_randomness(previous) \ + _warn_unseeded_randomness(__func__, (void *)_RET_IP_, (previous)) + +static void _warn_unseeded_randomness(const char *func_name, void *caller,= void **previous) +{ +#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM + const bool print_once =3D false; +#else + static bool print_once __read_mostly; +#endif + + if (print_once || crng_ready() || + (previous && (caller =3D=3D READ_ONCE(*previous)))) + return; + WRITE_ONCE(*previous, caller); +#ifndef CONFIG_WARN_ALL_UNSEEDED_RANDOM + print_once =3D true; +#endif + if (__ratelimit(&unseeded_warning)) + printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init= =3D%d\n", + func_name, caller, crng_init); +} + + +enum { + POOL_BITS =3D BLAKE2S_HASH_SIZE * 8, + POOL_MIN_BITS =3D POOL_BITS /* No point in settling for less. */ +}; + +/* + * Static global variables + */ +static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); +static struct fasync_struct *fasync; + +static int crng_init_cnt =3D 0; +static void _get_random_bytes(void *buf, size_t nbytes); + /********************************************************************** * * OS independent entropy store. Here are the functions which handle @@ -177,22 +333,6 @@ static void fast_mix(u32 pool[4]) pool[2] =3D c; pool[3] =3D d; } =20 -static void process_random_ready_list(void) -{ - unsigned long flags; - struct random_ready_callback *rdy, *tmp; - - spin_lock_irqsave(&random_ready_list_lock, flags); - list_for_each_entry_safe(rdy, tmp, &random_ready_list, list) { - struct module *owner =3D rdy->owner; - - list_del_init(&rdy->list); - rdy->func(rdy); - module_put(owner); - } - spin_unlock_irqrestore(&random_ready_list_lock, flags); -} - static void credit_entropy_bits(size_t nbits) { unsigned int entropy_count, orig, add; @@ -242,8 +382,6 @@ static DEFINE_PER_CPU(struct crng, crngs) =3D { .lock =3D INIT_LOCAL_LOCK(crngs.lock), }; =20 -static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait); - /* * crng_fast_load() can be called by code in the interrupt service * path. So we can't afford to dilly-dally. Returns the number of @@ -761,29 +899,6 @@ static bool drain_entropy(void *buf, size_t nbytes) return true; } =20 -#define warn_unseeded_randomness(previous) \ - _warn_unseeded_randomness(__func__, (void *)_RET_IP_, (previous)) - -static void _warn_unseeded_randomness(const char *func_name, void *caller,= void **previous) -{ -#ifdef CONFIG_WARN_ALL_UNSEEDED_RANDOM - const bool print_once =3D false; -#else - static bool print_once __read_mostly; -#endif - - if (print_once || crng_ready() || - (previous && (caller =3D=3D READ_ONCE(*previous)))) - return; - WRITE_ONCE(*previous, caller); -#ifndef CONFIG_WARN_ALL_UNSEEDED_RANDOM - print_once =3D true; -#endif - if (__ratelimit(&unseeded_warning)) - printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init= =3D%d\n", - func_name, caller, crng_init); -} - /* * This function is the exported kernel interface. It returns some * number of good random numbers, suitable for key generation, seeding @@ -885,107 +1000,6 @@ static void try_to_generate_entropy(void) mix_pool_bytes(&stack.now, sizeof(stack.now)); } =20 -/* - * Wait for the urandom pool to be seeded and thus guaranteed to supply - * cryptographically secure random numbers. This applies to: the /dev/uran= dom - * device, the get_random_bytes function, and the get_random_{u32,u64,int,= long} - * family of functions. Using any of these functions without first calling - * this function forfeits the guarantee of security. - * - * Returns: 0 if the urandom pool has been seeded. - * -ERESTARTSYS if the function was interrupted by a signal. - */ -int wait_for_random_bytes(void) -{ - if (likely(crng_ready())) - return 0; - - do { - int ret; - ret =3D wait_event_interruptible_timeout(crng_init_wait, crng_ready(), H= Z); - if (ret) - return ret > 0 ? 0 : ret; - - try_to_generate_entropy(); - } while (!crng_ready()); - - return 0; -} -EXPORT_SYMBOL(wait_for_random_bytes); - -/* - * Returns whether or not the urandom pool has been seeded and thus guaran= teed - * 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. - * - * returns: 0 if callback is successfully added - * -EALREADY if pool is already initialised (callback not called) - * -ENOENT if module for callback is not alive - */ -int add_random_ready_callback(struct random_ready_callback *rdy) -{ - struct module *owner; - unsigned long flags; - int err =3D -EALREADY; - - if (crng_ready()) - return err; - - owner =3D rdy->owner; - if (!try_module_get(owner)) - return -ENOENT; - - spin_lock_irqsave(&random_ready_list_lock, flags); - if (crng_ready()) - goto out; - - owner =3D NULL; - - list_add(&rdy->list, &random_ready_list); - err =3D 0; - -out: - spin_unlock_irqrestore(&random_ready_list_lock, flags); - - module_put(owner); - - return err; -} -EXPORT_SYMBOL(add_random_ready_callback); - -/* - * Delete a previously registered readiness callback function. - */ -void del_random_ready_callback(struct random_ready_callback *rdy) -{ - unsigned long flags; - struct module *owner =3D NULL; - - spin_lock_irqsave(&random_ready_list_lock, flags); - if (!list_empty(&rdy->list)) { - list_del_init(&rdy->list); - owner =3D rdy->owner; - } - spin_unlock_irqrestore(&random_ready_list_lock, flags); - - module_put(owner); -} -EXPORT_SYMBOL(del_random_ready_callback); - /* * This function will use the architecture-specific hardware random * number generator if it is available. It is not recommended for --=20 2.35.0 From nobody Sun Jun 28 06:40:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AB8A2C433F5 for ; Fri, 11 Feb 2022 12:36:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350196AbiBKMg1 (ORCPT ); Fri, 11 Feb 2022 07:36:27 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41850 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1350167AbiBKMgU (ORCPT ); Fri, 11 Feb 2022 07:36:20 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7118CF79 for ; Fri, 11 Feb 2022 04:36:18 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 02937B829E0 for ; Fri, 11 Feb 2022 12:36:17 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6E722C340E9; Fri, 11 Feb 2022 12:36:15 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="owZ6y0uA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644582974; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UObi0m49AFWopQLrqrTb4g8rmhLJoh6PBQJpnPoaY80=; b=owZ6y0uAOdaMDUWo7WUacnsePH/9ccVUkwsJ8BRFGG+fTz+FWcWoNpthxNMzGGyZrPuqmb oYH/Nbr7pyJxbQLy3JzeGDPPMoRe+d6lkiQpspiKTgDNJvUEb9umZvczpLJAHelg21vp4K uOM5p4hToivB5lWc1IrJo6SlwjZIIpA= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id d12ac8fc (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 11 Feb 2022 12:36:13 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH 5/9] random: group crng functions Date: Fri, 11 Feb 2022 13:35:42 +0100 Message-Id: <20220211123546.474952-6-Jason@zx2c4.com> In-Reply-To: <20220211123546.474952-1-Jason@zx2c4.com> References: <20220211123546.474952-1-Jason@zx2c4.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This pulls all of the crng-focused functions into the second labeled section. No functional changes. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld --- drivers/char/random.c | 865 +++++++++++++++++++++--------------------- 1 file changed, 442 insertions(+), 423 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 09a85a1a4458..d5d16185b28b 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -239,121 +239,13 @@ static void _warn_unseeded_randomness(const char *fu= nc_name, void *caller, void } =20 =20 -enum { - POOL_BITS =3D BLAKE2S_HASH_SIZE * 8, - POOL_MIN_BITS =3D POOL_BITS /* No point in settling for less. */ -}; - -/* - * Static global variables - */ -static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); -static struct fasync_struct *fasync; - -static int crng_init_cnt =3D 0; -static void _get_random_bytes(void *buf, size_t nbytes); - -/********************************************************************** - * - * OS independent entropy store. Here are the functions which handle - * storing entropy in an entropy pool. - * - **********************************************************************/ - -static struct { - struct blake2s_state hash; - spinlock_t lock; - unsigned int entropy_count; -} input_pool =3D { - .hash.h =3D { BLAKE2S_IV0 ^ (0x01010000 | BLAKE2S_HASH_SIZE), - BLAKE2S_IV1, BLAKE2S_IV2, BLAKE2S_IV3, BLAKE2S_IV4, - BLAKE2S_IV5, BLAKE2S_IV6, BLAKE2S_IV7 }, - .hash.outlen =3D BLAKE2S_HASH_SIZE, - .lock =3D __SPIN_LOCK_UNLOCKED(input_pool.lock), -}; - -static void extract_entropy(void *buf, size_t nbytes); -static bool drain_entropy(void *buf, size_t nbytes); - -static void crng_reseed(void); - -/* - * This function adds bytes into the entropy "pool". It does not - * update the entropy estimate. The caller should call - * credit_entropy_bits if this is appropriate. - */ -static void _mix_pool_bytes(const void *in, size_t nbytes) -{ - blake2s_update(&input_pool.hash, in, nbytes); -} - -static void mix_pool_bytes(const void *in, size_t nbytes) -{ - unsigned long flags; - - spin_lock_irqsave(&input_pool.lock, flags); - _mix_pool_bytes(in, nbytes); - spin_unlock_irqrestore(&input_pool.lock, flags); -} - -struct fast_pool { - unsigned long pool[16 / sizeof(long)]; - unsigned long last; - u16 reg_idx; - u8 count; -}; - -/* - * This is a fast mixing routine used by the interrupt randomness - * collector. It's hardcoded for an 128 bit pool and assumes that any - * locks that might be needed are taken by the caller. - */ -static void fast_mix(u32 pool[4]) -{ - u32 a =3D pool[0], b =3D pool[1]; - u32 c =3D pool[2], d =3D pool[3]; - - a +=3D b; c +=3D d; - b =3D rol32(b, 6); d =3D rol32(d, 27); - d ^=3D a; b ^=3D c; - - a +=3D b; c +=3D d; - b =3D rol32(b, 16); d =3D rol32(d, 14); - d ^=3D a; b ^=3D c; - - a +=3D b; c +=3D d; - b =3D rol32(b, 6); d =3D rol32(d, 27); - d ^=3D a; b ^=3D c; - - a +=3D b; c +=3D d; - b =3D rol32(b, 16); d =3D rol32(d, 14); - d ^=3D a; b ^=3D c; - - pool[0] =3D a; pool[1] =3D b; - pool[2] =3D c; pool[3] =3D d; -} - -static void credit_entropy_bits(size_t nbits) -{ - unsigned int entropy_count, orig, add; - - if (!nbits) - return; - - add =3D min_t(size_t, nbits, POOL_BITS); - - do { - orig =3D READ_ONCE(input_pool.entropy_count); - entropy_count =3D min_t(unsigned int, POOL_BITS, orig + add); - } while (cmpxchg(&input_pool.entropy_count, orig, entropy_count) !=3D ori= g); - - if (crng_init < 2 && entropy_count >=3D POOL_MIN_BITS) - crng_reseed(); -} - /********************************************************************* * - * CRNG using CHACHA20 + * Fast key erasure RNG, the "crng". + * + * These functions expand entropy from the entropy extractor into + * long streams for external consumption using the "fast key erasure" + * RNG described at . * *********************************************************************/ =20 @@ -382,70 +274,14 @@ static DEFINE_PER_CPU(struct crng, crngs) =3D { .lock =3D INIT_LOCAL_LOCK(crngs.lock), }; =20 -/* - * crng_fast_load() can be called by code in the interrupt service - * path. So we can't afford to dilly-dally. Returns the number of - * bytes processed from cp. - */ -static size_t crng_fast_load(const void *cp, size_t len) -{ - unsigned long flags; - u8 *src =3D (u8 *)cp; - size_t ret =3D 0; - - if (!spin_trylock_irqsave(&base_crng.lock, flags)) - return 0; - if (crng_init !=3D 0) { - spin_unlock_irqrestore(&base_crng.lock, flags); - return 0; - } - while (len > 0 && crng_init_cnt < CRNG_INIT_CNT_THRESH) { - base_crng.key[crng_init_cnt % sizeof(base_crng.key)] ^=3D *src; - src++; crng_init_cnt++; len--; ret++; - } - if (crng_init_cnt >=3D CRNG_INIT_CNT_THRESH) { - ++base_crng.generation; - crng_init =3D 1; - } - spin_unlock_irqrestore(&base_crng.lock, flags); - if (crng_init =3D=3D 1) - pr_notice("fast init done\n"); - return ret; -} +/* Used by crng_reseed() to extract a new seed from the input pool. */ +static bool drain_entropy(void *buf, size_t nbytes); =20 /* - * crng_slow_load() is called by add_device_randomness, which has two - * attributes. (1) We can't trust the buffer passed to it is - * guaranteed to be unpredictable (so it might not have any entropy at - * all), and (2) it doesn't have the performance constraints of - * crng_fast_load(). - * - * So, we simply hash the contents in with the current key. Finally, - * we do *not* advance crng_init_cnt since buffer we may get may be - * something like a fixed DMI table (for example), which might very - * well be unique to the machine, but is otherwise unvarying. + * This extracts a new crng key from the input pool, but only if there is a + * sufficient amount of entropy available, in order to mitigate bruteforci= ng + * of newly added bits. */ -static void crng_slow_load(const void *cp, size_t len) -{ - unsigned long flags; - struct blake2s_state hash; - - blake2s_init(&hash, sizeof(base_crng.key)); - - if (!spin_trylock_irqsave(&base_crng.lock, flags)) - return; - if (crng_init !=3D 0) { - spin_unlock_irqrestore(&base_crng.lock, flags); - return; - } - - blake2s_update(&hash, base_crng.key, sizeof(base_crng.key)); - blake2s_update(&hash, cp, len); - blake2s_final(&hash, base_crng.key); - - spin_unlock_irqrestore(&base_crng.lock, flags); -} - static void crng_reseed(void) { unsigned long flags; @@ -457,7 +293,8 @@ static void crng_reseed(void) if (!drain_entropy(key, sizeof(key))) return; =20 - /* We copy the new key into the base_crng, overwriting the old one, + /* + * We copy the new key into the base_crng, overwriting the old one, * and update the generation counter. We avoid hitting ULONG_MAX, * because the per-cpu crngs are initialized to ULONG_MAX, so this * forces new CPUs that come online to always initialize. @@ -494,13 +331,11 @@ static void crng_reseed(void) } =20 /* - * The general form here is based on a "fast key erasure RNG" from - * . It generates a ChaCha - * block using the provided key, and then immediately overwites that - * key with half the block. It returns the resultant ChaCha state to the - * user, along with the second half of the block containing 32 bytes of - * random data that may be used; random_data_len may not be greater than - * 32. + * This generates a ChaCha block using the provided key, and then + * immediately overwites that key with half the block. It returns + * the resultant ChaCha state to the user, along with the second + * half of the block containing 32 bytes of random data that may + * be used; random_data_len may not be greater than 32. */ static void crng_fast_key_erasure(u8 key[CHACHA_KEY_SIZE], u32 chacha_state[CHACHA_STATE_WORDS], @@ -533,7 +368,8 @@ static void crng_make_state(u32 chacha_state[CHACHA_STA= TE_WORDS], =20 BUG_ON(random_data_len > 32); =20 - /* For the fast path, we check whether we're ready, unlocked first, and + /* + * For the fast path, we check whether we're ready, unlocked first, and * then re-check once locked later. In the case where we're really not * ready, we do fast key erasure with the base_crng directly, because * this is what crng_{fast,slow}_load mutate during early init. @@ -551,7 +387,8 @@ static void crng_make_state(u32 chacha_state[CHACHA_STA= TE_WORDS], return; } =20 - /* If the base_crng is more than 5 minutes old, we reseed, which + /* + * If the base_crng is more than 5 minutes old, we reseed, which * in turn bumps the generation counter that we check below. */ if (unlikely(time_after(jiffies, READ_ONCE(base_crng.birth) + CRNG_RESEED= _INTERVAL))) @@ -560,7 +397,8 @@ static void crng_make_state(u32 chacha_state[CHACHA_STA= TE_WORDS], local_lock_irqsave(&crngs.lock, flags); crng =3D raw_cpu_ptr(&crngs); =20 - /* If our per-cpu crng is older than the base_crng, then it means + /* + * If our per-cpu crng is older than the base_crng, then it means * somebody reseeded the base_crng. In that case, we do fast key * erasure on the base_crng, and use its output as the new key * for our per-cpu crng. This brings us up to date with base_crng. @@ -573,7 +411,8 @@ static void crng_make_state(u32 chacha_state[CHACHA_STA= TE_WORDS], spin_unlock(&base_crng.lock); } =20 - /* Finally, when we've made it this far, our per-cpu crng has an up + /* + * Finally, when we've made it this far, our per-cpu crng has an up * to date key, and we can do fast key erasure with it to produce * some random data and a ChaCha state for the caller. All other * branches of this function are "unlikely", so most of the time we @@ -583,54 +422,433 @@ static void crng_make_state(u32 chacha_state[CHACHA_= STATE_WORDS], local_unlock_irqrestore(&crngs.lock, flags); } =20 -static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes) +/* + * This function is for crng_init < 2 only. + * + * crng_fast_load() can be called by code in the interrupt service + * path. So we can't afford to dilly-dally. Returns the number of + * bytes processed from cp. + */ +static size_t crng_fast_load(const void *cp, size_t len) +{ + static int crng_init_cnt =3D 0; + unsigned long flags; + u8 *src =3D (u8 *)cp; + size_t ret =3D 0; + + if (!spin_trylock_irqsave(&base_crng.lock, flags)) + return 0; + if (crng_init !=3D 0) { + spin_unlock_irqrestore(&base_crng.lock, flags); + return 0; + } + while (len > 0 && crng_init_cnt < CRNG_INIT_CNT_THRESH) { + base_crng.key[crng_init_cnt % sizeof(base_crng.key)] ^=3D *src; + src++; crng_init_cnt++; len--; ret++; + } + if (crng_init_cnt >=3D CRNG_INIT_CNT_THRESH) { + ++base_crng.generation; + crng_init =3D 1; + } + spin_unlock_irqrestore(&base_crng.lock, flags); + if (crng_init =3D=3D 1) + pr_notice("fast init done\n"); + return ret; +} + +/* + * This function is for crng_init < 2 only. + * + * crng_slow_load() is called by add_device_randomness, which has two + * attributes. (1) We can't trust the buffer passed to it is + * guaranteed to be unpredictable (so it might not have any entropy at + * all), and (2) it doesn't have the performance constraints of + * crng_fast_load(). + * + * So, we simply hash the contents in with the current key. Finally, + * we do *not* advance crng_init_cnt since buffer we may get may be + * something like a fixed DMI table (for example), which might very + * well be unique to the machine, but is otherwise unvarying. + */ +static void crng_slow_load(const void *cp, size_t len) +{ + unsigned long flags; + struct blake2s_state hash; + + blake2s_init(&hash, sizeof(base_crng.key)); + + if (!spin_trylock_irqsave(&base_crng.lock, flags)) + return; + if (crng_init !=3D 0) { + spin_unlock_irqrestore(&base_crng.lock, flags); + return; + } + + blake2s_update(&hash, base_crng.key, sizeof(base_crng.key)); + blake2s_update(&hash, cp, len); + blake2s_final(&hash, base_crng.key); + + spin_unlock_irqrestore(&base_crng.lock, flags); +} + +static void _get_random_bytes(void *buf, size_t nbytes) { - bool large_request =3D (nbytes > 256); - ssize_t ret =3D 0; - size_t len; u32 chacha_state[CHACHA_STATE_WORDS]; - u8 output[CHACHA_BLOCK_SIZE]; + u8 tmp[CHACHA_BLOCK_SIZE]; + size_t len; + + if (!nbytes) + return; + + len =3D min_t(size_t, 32, nbytes); + crng_make_state(chacha_state, buf, len); + nbytes -=3D len; + buf +=3D len; + + while (nbytes) { + if (nbytes < CHACHA_BLOCK_SIZE) { + chacha20_block(chacha_state, tmp); + memcpy(buf, tmp, nbytes); + memzero_explicit(tmp, sizeof(tmp)); + break; + } + + len =3D min_t(size_t, nbytes, CHACHA_BLOCK_SIZE); + chacha20_block(chacha_state, buf); + if (unlikely(chacha_state[12] =3D=3D 0)) + ++chacha_state[13]; + nbytes -=3D len; + buf +=3D len; + } + + memzero_explicit(chacha_state, sizeof(chacha_state)); +} + +/* + * This function is the exported kernel interface. It returns some + * number of good random numbers, suitable for key generation, seeding + * TCP sequence numbers, etc. It does not rely on the hardware random + * number generator. For random bytes direct from the hardware RNG + * (when available), use get_random_bytes_arch(). In order to ensure + * that the randomness provided by this function is okay, the function + * wait_for_random_bytes() should be called and return 0 at least once + * at any point prior. + */ +void get_random_bytes(void *buf, size_t nbytes) +{ + static void *previous; + + warn_unseeded_randomness(&previous); + _get_random_bytes(buf, nbytes); +} +EXPORT_SYMBOL(get_random_bytes); + +static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes) +{ + bool large_request =3D (nbytes > 256); + ssize_t ret =3D 0; + size_t len; + u32 chacha_state[CHACHA_STATE_WORDS]; + u8 output[CHACHA_BLOCK_SIZE]; + + if (!nbytes) + return 0; + + len =3D min_t(size_t, 32, nbytes); + crng_make_state(chacha_state, output, len); + + if (copy_to_user(buf, output, len)) + return -EFAULT; + nbytes -=3D len; + buf +=3D len; + ret +=3D len; + + while (nbytes) { + if (large_request && need_resched()) { + if (signal_pending(current)) { + if (ret =3D=3D 0) + ret =3D -ERESTARTSYS; + break; + } + schedule(); + } + + chacha20_block(chacha_state, output); + if (unlikely(chacha_state[12] =3D=3D 0)) + ++chacha_state[13]; + + len =3D min_t(size_t, nbytes, CHACHA_BLOCK_SIZE); + if (copy_to_user(buf, output, len)) { + ret =3D -EFAULT; + break; + } + + nbytes -=3D len; + buf +=3D len; + ret +=3D len; + } + + memzero_explicit(chacha_state, sizeof(chacha_state)); + memzero_explicit(output, sizeof(output)); + return ret; +} + +/* + * Batched entropy returns random integers. The quality of the random + * number is good as /dev/urandom. In order to ensure that the randomness + * provided by this function is okay, the function wait_for_random_bytes() + * should be called and return 0 at least once at any point prior. + */ +struct batched_entropy { + union { + /* + * We make this 1.5x a ChaCha block, so that we get the + * remaining 32 bytes from fast key erasure, plus one full + * block from the detached ChaCha state. We can increase + * the size of this later if needed so long as we keep the + * formula of (integer_blocks + 0.5) * CHACHA_BLOCK_SIZE. + */ + u64 entropy_u64[CHACHA_BLOCK_SIZE * 3 / (2 * sizeof(u64))]; + u32 entropy_u32[CHACHA_BLOCK_SIZE * 3 / (2 * sizeof(u32))]; + }; + local_lock_t lock; + unsigned long generation; + unsigned int position; +}; + + +static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) =3D { + .lock =3D INIT_LOCAL_LOCK(batched_entropy_u64.lock) +}; + +u64 get_random_u64(void) +{ + u64 ret; + unsigned long flags; + struct batched_entropy *batch; + static void *previous; + unsigned long next_gen; + + warn_unseeded_randomness(&previous); + + local_lock_irqsave(&batched_entropy_u64.lock, flags); + batch =3D raw_cpu_ptr(&batched_entropy_u64); + + next_gen =3D READ_ONCE(base_crng.generation); + if (batch->position % ARRAY_SIZE(batch->entropy_u64) =3D=3D 0 || + next_gen !=3D batch->generation) { + _get_random_bytes(batch->entropy_u64, sizeof(batch->entropy_u64)); + batch->position =3D 0; + batch->generation =3D next_gen; + } + + ret =3D batch->entropy_u64[batch->position]; + batch->entropy_u64[batch->position] =3D 0; + ++batch->position; + local_unlock_irqrestore(&batched_entropy_u64.lock, flags); + return ret; +} +EXPORT_SYMBOL(get_random_u64); + +static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32) =3D { + .lock =3D INIT_LOCAL_LOCK(batched_entropy_u32.lock) +}; + +u32 get_random_u32(void) +{ + u32 ret; + unsigned long flags; + struct batched_entropy *batch; + static void *previous; + unsigned long next_gen; + + warn_unseeded_randomness(&previous); + + local_lock_irqsave(&batched_entropy_u32.lock, flags); + batch =3D raw_cpu_ptr(&batched_entropy_u32); + + next_gen =3D READ_ONCE(base_crng.generation); + if (batch->position % ARRAY_SIZE(batch->entropy_u32) =3D=3D 0 || + next_gen !=3D batch->generation) { + _get_random_bytes(batch->entropy_u32, sizeof(batch->entropy_u32)); + batch->position =3D 0; + batch->generation =3D next_gen; + } + + ret =3D batch->entropy_u32[batch->position]; + batch->entropy_u32[batch->position] =3D 0; + ++batch->position; + local_unlock_irqrestore(&batched_entropy_u32.lock, flags); + return ret; +} +EXPORT_SYMBOL(get_random_u32); + +/** + * randomize_page - Generate a random, page aligned address + * @start: The smallest acceptable address the caller will take. + * @range: The size of the area, starting at @start, within which the + * random address must fall. + * + * If @start + @range would overflow, @range is capped. + * + * NOTE: Historical use of randomize_range, which this replaces, presumed = that + * @start was already page aligned. We now align it regardless. + * + * Return: A page aligned address within [start, start + range). On error, + * @start is returned. + */ +unsigned long randomize_page(unsigned long start, unsigned long range) +{ + if (!PAGE_ALIGNED(start)) { + range -=3D PAGE_ALIGN(start) - start; + start =3D PAGE_ALIGN(start); + } + + if (start > ULONG_MAX - range) + range =3D ULONG_MAX - start; + + range >>=3D PAGE_SHIFT; + + if (range =3D=3D 0) + return start; + + return start + (get_random_long() % range << PAGE_SHIFT); +} + +/* + * This function will use the architecture-specific hardware random + * number generator if it is available. It is not recommended for + * use. Use get_random_bytes() instead. It returns the number of + * bytes filled in. + */ +size_t __must_check get_random_bytes_arch(void *buf, size_t nbytes) +{ + size_t left =3D nbytes; + u8 *p =3D buf; + + while (left) { + unsigned long v; + size_t chunk =3D min_t(size_t, left, sizeof(unsigned long)); + + if (!arch_get_random_long(&v)) + break; + + memcpy(p, &v, chunk); + p +=3D chunk; + left -=3D chunk; + } + + return nbytes - left; +} +EXPORT_SYMBOL(get_random_bytes_arch); + +enum { + POOL_BITS =3D BLAKE2S_HASH_SIZE * 8, + POOL_MIN_BITS =3D POOL_BITS /* No point in settling for less. */ +}; + +/* + * Static global variables + */ +static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); +static struct fasync_struct *fasync; + +/********************************************************************** + * + * OS independent entropy store. Here are the functions which handle + * storing entropy in an entropy pool. + * + **********************************************************************/ + +static struct { + struct blake2s_state hash; + spinlock_t lock; + unsigned int entropy_count; +} input_pool =3D { + .hash.h =3D { BLAKE2S_IV0 ^ (0x01010000 | BLAKE2S_HASH_SIZE), + BLAKE2S_IV1, BLAKE2S_IV2, BLAKE2S_IV3, BLAKE2S_IV4, + BLAKE2S_IV5, BLAKE2S_IV6, BLAKE2S_IV7 }, + .hash.outlen =3D BLAKE2S_HASH_SIZE, + .lock =3D __SPIN_LOCK_UNLOCKED(input_pool.lock), +}; + +static void extract_entropy(void *buf, size_t nbytes); +static bool drain_entropy(void *buf, size_t nbytes); + +static void crng_reseed(void); + +/* + * This function adds bytes into the entropy "pool". It does not + * update the entropy estimate. The caller should call + * credit_entropy_bits if this is appropriate. + */ +static void _mix_pool_bytes(const void *in, size_t nbytes) +{ + blake2s_update(&input_pool.hash, in, nbytes); +} + +static void mix_pool_bytes(const void *in, size_t nbytes) +{ + unsigned long flags; + + spin_lock_irqsave(&input_pool.lock, flags); + _mix_pool_bytes(in, nbytes); + spin_unlock_irqrestore(&input_pool.lock, flags); +} + +struct fast_pool { + unsigned long pool[16 / sizeof(long)]; + unsigned long last; + u16 reg_idx; + u8 count; +}; + +/* + * This is a fast mixing routine used by the interrupt randomness + * collector. It's hardcoded for an 128 bit pool and assumes that any + * locks that might be needed are taken by the caller. + */ +static void fast_mix(u32 pool[4]) +{ + u32 a =3D pool[0], b =3D pool[1]; + u32 c =3D pool[2], d =3D pool[3]; + + a +=3D b; c +=3D d; + b =3D rol32(b, 6); d =3D rol32(d, 27); + d ^=3D a; b ^=3D c; =20 - if (!nbytes) - return 0; + a +=3D b; c +=3D d; + b =3D rol32(b, 16); d =3D rol32(d, 14); + d ^=3D a; b ^=3D c; =20 - len =3D min_t(size_t, 32, nbytes); - crng_make_state(chacha_state, output, len); + a +=3D b; c +=3D d; + b =3D rol32(b, 6); d =3D rol32(d, 27); + d ^=3D a; b ^=3D c; =20 - if (copy_to_user(buf, output, len)) - return -EFAULT; - nbytes -=3D len; - buf +=3D len; - ret +=3D len; + a +=3D b; c +=3D d; + b =3D rol32(b, 16); d =3D rol32(d, 14); + d ^=3D a; b ^=3D c; =20 - while (nbytes) { - if (large_request && need_resched()) { - if (signal_pending(current)) { - if (ret =3D=3D 0) - ret =3D -ERESTARTSYS; - break; - } - schedule(); - } + pool[0] =3D a; pool[1] =3D b; + pool[2] =3D c; pool[3] =3D d; +} =20 - chacha20_block(chacha_state, output); - if (unlikely(chacha_state[12] =3D=3D 0)) - ++chacha_state[13]; +static void credit_entropy_bits(size_t nbits) +{ + unsigned int entropy_count, orig, add; =20 - len =3D min_t(size_t, nbytes, CHACHA_BLOCK_SIZE); - if (copy_to_user(buf, output, len)) { - ret =3D -EFAULT; - break; - } + if (!nbits) + return; =20 - nbytes -=3D len; - buf +=3D len; - ret +=3D len; - } + add =3D min_t(size_t, nbits, POOL_BITS); =20 - memzero_explicit(chacha_state, sizeof(chacha_state)); - memzero_explicit(output, sizeof(output)); - return ret; + do { + orig =3D READ_ONCE(input_pool.entropy_count); + entropy_count =3D min_t(unsigned int, POOL_BITS, orig + add); + } while (cmpxchg(&input_pool.entropy_count, orig, entropy_count) !=3D ori= g); + + if (crng_init < 2 && entropy_count >=3D POOL_MIN_BITS) + crng_reseed(); } =20 /********************************************************************* @@ -899,58 +1117,6 @@ static bool drain_entropy(void *buf, size_t nbytes) return true; } =20 -/* - * This function is the exported kernel interface. It returns some - * number of good random numbers, suitable for key generation, seeding - * TCP sequence numbers, etc. It does not rely on the hardware random - * number generator. For random bytes direct from the hardware RNG - * (when available), use get_random_bytes_arch(). In order to ensure - * that the randomness provided by this function is okay, the function - * wait_for_random_bytes() should be called and return 0 at least once - * at any point prior. - */ -static void _get_random_bytes(void *buf, size_t nbytes) -{ - u32 chacha_state[CHACHA_STATE_WORDS]; - u8 tmp[CHACHA_BLOCK_SIZE]; - size_t len; - - if (!nbytes) - return; - - len =3D min_t(size_t, 32, nbytes); - crng_make_state(chacha_state, buf, len); - nbytes -=3D len; - buf +=3D len; - - while (nbytes) { - if (nbytes < CHACHA_BLOCK_SIZE) { - chacha20_block(chacha_state, tmp); - memcpy(buf, tmp, nbytes); - memzero_explicit(tmp, sizeof(tmp)); - break; - } - - len =3D min_t(size_t, nbytes, CHACHA_BLOCK_SIZE); - chacha20_block(chacha_state, buf); - if (unlikely(chacha_state[12] =3D=3D 0)) - ++chacha_state[13]; - nbytes -=3D len; - buf +=3D len; - } - - memzero_explicit(chacha_state, sizeof(chacha_state)); -} - -void get_random_bytes(void *buf, size_t nbytes) -{ - static void *previous; - - warn_unseeded_randomness(&previous); - _get_random_bytes(buf, nbytes); -} -EXPORT_SYMBOL(get_random_bytes); - /* * Each time the timer fires, we expect that we got an unpredictable * jump in the cycle counter. Even if the timer is running on another @@ -1000,33 +1166,6 @@ static void try_to_generate_entropy(void) mix_pool_bytes(&stack.now, sizeof(stack.now)); } =20 -/* - * This function will use the architecture-specific hardware random - * number generator if it is available. It is not recommended for - * use. Use get_random_bytes() instead. It returns the number of - * bytes filled in. - */ -size_t __must_check get_random_bytes_arch(void *buf, size_t nbytes) -{ - size_t left =3D nbytes; - u8 *p =3D buf; - - while (left) { - unsigned long v; - size_t chunk =3D min_t(size_t, left, sizeof(unsigned long)); - - if (!arch_get_random_long(&v)) - break; - - memcpy(p, &v, chunk); - p +=3D chunk; - left -=3D chunk; - } - - return nbytes - left; -} -EXPORT_SYMBOL(get_random_bytes_arch); - static bool trust_cpu __ro_after_init =3D IS_ENABLED(CONFIG_RANDOM_TRUST_C= PU); static int __init parse_trust_cpu(char *arg) { @@ -1389,126 +1528,6 @@ static int __init random_sysctls_init(void) device_initcall(random_sysctls_init); #endif /* CONFIG_SYSCTL */ =20 -struct batched_entropy { - union { - /* We make this 1.5x a ChaCha block, so that we get the - * remaining 32 bytes from fast key erasure, plus one full - * block from the detached ChaCha state. We can increase - * the size of this later if needed so long as we keep the - * formula of (integer_blocks + 0.5) * CHACHA_BLOCK_SIZE. - */ - u64 entropy_u64[CHACHA_BLOCK_SIZE * 3 / (2 * sizeof(u64))]; - u32 entropy_u32[CHACHA_BLOCK_SIZE * 3 / (2 * sizeof(u32))]; - }; - local_lock_t lock; - unsigned long generation; - unsigned int position; -}; - -/* - * Get a random word for internal kernel use only. The quality of the rand= om - * number is good as /dev/urandom. In order to ensure that the randomness - * provided by this function is okay, the function wait_for_random_bytes() - * should be called and return 0 at least once at any point prior. - */ -static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) =3D { - .lock =3D INIT_LOCAL_LOCK(batched_entropy_u64.lock) -}; - -u64 get_random_u64(void) -{ - u64 ret; - unsigned long flags; - struct batched_entropy *batch; - static void *previous; - unsigned long next_gen; - - warn_unseeded_randomness(&previous); - - local_lock_irqsave(&batched_entropy_u64.lock, flags); - batch =3D raw_cpu_ptr(&batched_entropy_u64); - - next_gen =3D READ_ONCE(base_crng.generation); - if (batch->position % ARRAY_SIZE(batch->entropy_u64) =3D=3D 0 || - next_gen !=3D batch->generation) { - _get_random_bytes(batch->entropy_u64, sizeof(batch->entropy_u64)); - batch->position =3D 0; - batch->generation =3D next_gen; - } - - ret =3D batch->entropy_u64[batch->position]; - batch->entropy_u64[batch->position] =3D 0; - ++batch->position; - local_unlock_irqrestore(&batched_entropy_u64.lock, flags); - return ret; -} -EXPORT_SYMBOL(get_random_u64); - -static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32) =3D { - .lock =3D INIT_LOCAL_LOCK(batched_entropy_u32.lock) -}; - -u32 get_random_u32(void) -{ - u32 ret; - unsigned long flags; - struct batched_entropy *batch; - static void *previous; - unsigned long next_gen; - - warn_unseeded_randomness(&previous); - - local_lock_irqsave(&batched_entropy_u32.lock, flags); - batch =3D raw_cpu_ptr(&batched_entropy_u32); - - next_gen =3D READ_ONCE(base_crng.generation); - if (batch->position % ARRAY_SIZE(batch->entropy_u32) =3D=3D 0 || - next_gen !=3D batch->generation) { - _get_random_bytes(batch->entropy_u32, sizeof(batch->entropy_u32)); - batch->position =3D 0; - batch->generation =3D next_gen; - } - - ret =3D batch->entropy_u32[batch->position]; - batch->entropy_u32[batch->position] =3D 0; - ++batch->position; - local_unlock_irqrestore(&batched_entropy_u32.lock, flags); - return ret; -} -EXPORT_SYMBOL(get_random_u32); - -/** - * randomize_page - Generate a random, page aligned address - * @start: The smallest acceptable address the caller will take. - * @range: The size of the area, starting at @start, within which the - * random address must fall. - * - * If @start + @range would overflow, @range is capped. - * - * NOTE: Historical use of randomize_range, which this replaces, presumed = that - * @start was already page aligned. We now align it regardless. - * - * Return: A page aligned address within [start, start + range). On error, - * @start is returned. - */ -unsigned long randomize_page(unsigned long start, unsigned long range) -{ - if (!PAGE_ALIGNED(start)) { - range -=3D PAGE_ALIGN(start) - start; - start =3D PAGE_ALIGN(start); - } - - if (start > ULONG_MAX - range) - range =3D ULONG_MAX - start; - - range >>=3D PAGE_SHIFT; - - if (range =3D=3D 0) - return start; - - return start + (get_random_long() % range << PAGE_SHIFT); -} - /* Interface for in-kernel drivers of true hardware RNGs. * Those devices may produce endless random bits and will be throttled * when our pool is full. --=20 2.35.0 From nobody Sun Jun 28 06:40:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3837BC433F5 for ; Fri, 11 Feb 2022 12:36:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350210AbiBKMgc (ORCPT ); Fri, 11 Feb 2022 07:36:32 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41848 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1350168AbiBKMgU (ORCPT ); Fri, 11 Feb 2022 07:36:20 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A1105FC1 for ; Fri, 11 Feb 2022 04:36:19 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 60FD2B829DB for ; Fri, 11 Feb 2022 12:36:18 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id AB73EC340EF; Fri, 11 Feb 2022 12:36:16 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="QLJunAoM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644582976; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sVj6bvdFI7YvBEIwX5Nyz0r9KtkUnrqsvKkKLThl8kc=; b=QLJunAoM4jAP53lDaGfaaWUemzOQYn8UXZ+0DMdVONsYclec5LLUD57YDsz1WlHc4HOlim W63ru53p5L52qhK6uEXqTfNRarorvN9plmKNzDKMznoEfBpbu40eB8KLOiXvc8I4nLX1BN 8Sni9AJ2A8uGT53hkWR+hnCAKBqj/5s= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 179aef09 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 11 Feb 2022 12:36:16 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH 6/9] random: group entropy extraction functions Date: Fri, 11 Feb 2022 13:35:43 +0100 Message-Id: <20220211123546.474952-7-Jason@zx2c4.com> In-Reply-To: <20220211123546.474952-1-Jason@zx2c4.com> References: <20220211123546.474952-1-Jason@zx2c4.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This pulls all of the entropy extraction-focused functions into the third labeled section. No functional changes. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld --- drivers/char/random.c | 216 +++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index d5d16185b28b..fbb2809423c6 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -742,23 +742,34 @@ size_t __must_check get_random_bytes_arch(void *buf, = size_t nbytes) } EXPORT_SYMBOL(get_random_bytes_arch); =20 +/********************************************************************** + * + * Entropy accumulation and extraction routines. + * + * Callers may add entropy via: + * + * static void mix_pool_bytes(const void *in, size_t nbytes) + * + * After which, if added entropy should be credited: + * + * static void credit_entropy_bits(size_t nbits) + * + * Finally, extract entropy via these two, with the latter one + * setting the entropy count to zero and extracting only if there + * is POOL_MIN_BITS entropy credited prior: + * + * static void extract_entropy(void *buf, size_t nbytes) + * static bool drain_entropy(void *buf, size_t nbytes) + * + **********************************************************************/ + enum { POOL_BITS =3D BLAKE2S_HASH_SIZE * 8, POOL_MIN_BITS =3D POOL_BITS /* No point in settling for less. */ }; =20 -/* - * Static global variables - */ +/* For notifying userspace should write into /dev/random. */ static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); -static struct fasync_struct *fasync; - -/********************************************************************** - * - * OS independent entropy store. Here are the functions which handle - * storing entropy in an entropy pool. - * - **********************************************************************/ =20 static struct { struct blake2s_state hash; @@ -772,28 +783,106 @@ static struct { .lock =3D __SPIN_LOCK_UNLOCKED(input_pool.lock), }; =20 -static void extract_entropy(void *buf, size_t nbytes); -static bool drain_entropy(void *buf, size_t nbytes); - -static void crng_reseed(void); +static void _mix_pool_bytes(const void *in, size_t nbytes) +{ + blake2s_update(&input_pool.hash, in, nbytes); +} =20 /* * This function adds bytes into the entropy "pool". It does not * update the entropy estimate. The caller should call * credit_entropy_bits if this is appropriate. */ -static void _mix_pool_bytes(const void *in, size_t nbytes) +static void mix_pool_bytes(const void *in, size_t nbytes) { - blake2s_update(&input_pool.hash, in, nbytes); + unsigned long flags; + + spin_lock_irqsave(&input_pool.lock, flags); + _mix_pool_bytes(in, nbytes); + spin_unlock_irqrestore(&input_pool.lock, flags); } =20 -static void mix_pool_bytes(const void *in, size_t nbytes) +static void credit_entropy_bits(size_t nbits) +{ + unsigned int entropy_count, orig, add; + + if (!nbits) + return; + + add =3D min_t(size_t, nbits, POOL_BITS); + + do { + orig =3D READ_ONCE(input_pool.entropy_count); + entropy_count =3D min_t(unsigned int, POOL_BITS, orig + add); + } while (cmpxchg(&input_pool.entropy_count, orig, entropy_count) !=3D ori= g); + + if (crng_init < 2 && entropy_count >=3D POOL_MIN_BITS) + crng_reseed(); +} + +/* + * This is an HKDF-like construction for using the hashed collected entropy + * as a PRF key, that's then expanded block-by-block. + */ +static void extract_entropy(void *buf, size_t nbytes) { unsigned long flags; + u8 seed[BLAKE2S_HASH_SIZE], next_key[BLAKE2S_HASH_SIZE]; + struct { + unsigned long rdseed[32 / sizeof(long)]; + size_t counter; + } block; + size_t i; + + for (i =3D 0; i < ARRAY_SIZE(block.rdseed); ++i) { + if (!arch_get_random_seed_long(&block.rdseed[i]) && + !arch_get_random_long(&block.rdseed[i])) + block.rdseed[i] =3D random_get_entropy(); + } =20 spin_lock_irqsave(&input_pool.lock, flags); - _mix_pool_bytes(in, nbytes); + + /* seed =3D HASHPRF(last_key, entropy_input) */ + blake2s_final(&input_pool.hash, seed); + + /* next_key =3D HASHPRF(seed, RDSEED || 0) */ + block.counter =3D 0; + blake2s(next_key, (u8 *)&block, seed, sizeof(next_key), sizeof(block), si= zeof(seed)); + blake2s_init_key(&input_pool.hash, BLAKE2S_HASH_SIZE, next_key, sizeof(ne= xt_key)); + spin_unlock_irqrestore(&input_pool.lock, flags); + memzero_explicit(next_key, sizeof(next_key)); + + while (nbytes) { + i =3D min_t(size_t, nbytes, BLAKE2S_HASH_SIZE); + /* output =3D HASHPRF(seed, RDSEED || ++counter) */ + ++block.counter; + blake2s(buf, (u8 *)&block, seed, i, sizeof(block), sizeof(seed)); + nbytes -=3D i; + buf +=3D i; + } + + memzero_explicit(seed, sizeof(seed)); + memzero_explicit(&block, sizeof(block)); +} + +/* + * First we make sure we have POOL_MIN_BITS of entropy in the pool, + * and then we drain all of it. Only then can we extract a new key + * with extract_entropy(). + */ +static bool drain_entropy(void *buf, size_t nbytes) +{ + unsigned int entropy_count; + do { + entropy_count =3D READ_ONCE(input_pool.entropy_count); + if (entropy_count < POOL_MIN_BITS) + return false; + } while (cmpxchg(&input_pool.entropy_count, entropy_count, 0) !=3D entrop= y_count); + extract_entropy(buf, nbytes); + wake_up_interruptible(&random_write_wait); + kill_fasync(&fasync, SIGIO, POLL_OUT); + return true; } =20 struct fast_pool { @@ -833,24 +922,6 @@ static void fast_mix(u32 pool[4]) pool[2] =3D c; pool[3] =3D d; } =20 -static void credit_entropy_bits(size_t nbits) -{ - unsigned int entropy_count, orig, add; - - if (!nbits) - return; - - add =3D min_t(size_t, nbits, POOL_BITS); - - do { - orig =3D READ_ONCE(input_pool.entropy_count); - entropy_count =3D min_t(unsigned int, POOL_BITS, orig + add); - } while (cmpxchg(&input_pool.entropy_count, orig, entropy_count) !=3D ori= g); - - if (crng_init < 2 && entropy_count >=3D POOL_MIN_BITS) - crng_reseed(); -} - /********************************************************************* * * Entropy input management @@ -1046,77 +1117,6 @@ void add_disk_randomness(struct gendisk *disk) EXPORT_SYMBOL_GPL(add_disk_randomness); #endif =20 -/********************************************************************* - * - * Entropy extraction routines - * - *********************************************************************/ - -/* - * This is an HKDF-like construction for using the hashed collected entropy - * as a PRF key, that's then expanded block-by-block. - */ -static void extract_entropy(void *buf, size_t nbytes) -{ - unsigned long flags; - u8 seed[BLAKE2S_HASH_SIZE], next_key[BLAKE2S_HASH_SIZE]; - struct { - unsigned long rdseed[32 / sizeof(long)]; - size_t counter; - } block; - size_t i; - - for (i =3D 0; i < ARRAY_SIZE(block.rdseed); ++i) { - if (!arch_get_random_seed_long(&block.rdseed[i]) && - !arch_get_random_long(&block.rdseed[i])) - block.rdseed[i] =3D random_get_entropy(); - } - - spin_lock_irqsave(&input_pool.lock, flags); - - /* seed =3D HASHPRF(last_key, entropy_input) */ - blake2s_final(&input_pool.hash, seed); - - /* next_key =3D HASHPRF(seed, RDSEED || 0) */ - block.counter =3D 0; - blake2s(next_key, (u8 *)&block, seed, sizeof(next_key), sizeof(block), si= zeof(seed)); - blake2s_init_key(&input_pool.hash, BLAKE2S_HASH_SIZE, next_key, sizeof(ne= xt_key)); - - spin_unlock_irqrestore(&input_pool.lock, flags); - memzero_explicit(next_key, sizeof(next_key)); - - while (nbytes) { - i =3D min_t(size_t, nbytes, BLAKE2S_HASH_SIZE); - /* output =3D HASHPRF(seed, RDSEED || ++counter) */ - ++block.counter; - blake2s(buf, (u8 *)&block, seed, i, sizeof(block), sizeof(seed)); - nbytes -=3D i; - buf +=3D i; - } - - memzero_explicit(seed, sizeof(seed)); - memzero_explicit(&block, sizeof(block)); -} - -/* - * First we make sure we have POOL_MIN_BITS of entropy in the pool, - * and then we drain all of it. Only then can we extract a new key - * with extract_entropy(). - */ -static bool drain_entropy(void *buf, size_t nbytes) -{ - unsigned int entropy_count; - do { - entropy_count =3D READ_ONCE(input_pool.entropy_count); - if (entropy_count < POOL_MIN_BITS) - return false; - } while (cmpxchg(&input_pool.entropy_count, entropy_count, 0) !=3D entrop= y_count); - extract_entropy(buf, nbytes); - wake_up_interruptible(&random_write_wait); - kill_fasync(&fasync, SIGIO, POLL_OUT); - return true; -} - /* * Each time the timer fires, we expect that we got an unpredictable * jump in the cycle counter. Even if the timer is running on another --=20 2.35.0 From nobody Sun Jun 28 06:40:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8C301C433F5 for ; Fri, 11 Feb 2022 12:36:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345043AbiBKMgh (ORCPT ); Fri, 11 Feb 2022 07:36:37 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41902 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1350180AbiBKMgX (ORCPT ); Fri, 11 Feb 2022 07:36:23 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFBCAF79 for ; Fri, 11 Feb 2022 04:36:21 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 74D90B829DC for ; Fri, 11 Feb 2022 12:36:20 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id E5CEBC340E9; Fri, 11 Feb 2022 12:36:18 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="Ba9UvxIX" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644582978; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GCCxgVNNqq+bM79s9of0nVi6KtJvBf5ANJURvZpy4I0=; b=Ba9UvxIXSNxPNimuPOIWC0WfkKmH1p5Cp3Sm1Lyi98qFkzxa3H3bligglWpqcJZkpqeVWO hU0uzggmbqx4y9gmDIfIT6DpGIbXQR9fjE5zeQggyWA9JdoakZBHQrQG7AMDMBo0TCJcgL acJFLAt86/CuV6DxGK55vsIEwmfjSak= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 269492a1 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 11 Feb 2022 12:36:18 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH 7/9] random: group entropy collection functions Date: Fri, 11 Feb 2022 13:35:44 +0100 Message-Id: <20220211123546.474952-8-Jason@zx2c4.com> In-Reply-To: <20220211123546.474952-1-Jason@zx2c4.com> References: <20220211123546.474952-1-Jason@zx2c4.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This pulls all of the entropy collection-focused functions into the forth labeled section. No functional changes. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld --- drivers/char/random.c | 367 +++++++++++++++++++++++------------------- 1 file changed, 205 insertions(+), 162 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index fbb2809423c6..f793bd3a1325 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -885,57 +885,112 @@ static bool drain_entropy(void *buf, size_t nbytes) return true; } =20 -struct fast_pool { - unsigned long pool[16 / sizeof(long)]; - unsigned long last; - u16 reg_idx; - u8 count; -}; +/********************************************************************** + * + * Entropy collection routines. + * + * The following exported functions are used for pushing entropy into + * the above entropy accumulation routines: + * + * void add_device_randomness(const void *buf, size_t size); + * void add_input_randomness(unsigned int type, unsigned int code, + * unsigned int value); + * void add_interrupt_randomness(int irq); + * void add_disk_randomness(struct gendisk *disk); + * void add_hwgenerator_randomness(const void *buffer, size_t count, + * size_t entropy); + * void add_bootloader_randomness(const void *buf, size_t size); + * + * add_device_randomness() adds data to the input pool that + * is likely to differ between two devices (or possibly even per boot). + * This would be things like MAC addresses or serial numbers, or the + * read-out of the RTC. This does *not* credit any actual entropy to + * the pool, but it initializes the pool to different values for devices + * that might otherwise be identical and have very little entropy + * available to them (particularly common in the embedded world). + * + * add_input_randomness() uses the input layer interrupt timing, as well + * as the event type information from the hardware. + * + * add_disk_randomness() uses what amounts to the seek time of block + * layer request events, on a per-disk_devt basis, as input to the + * entropy pool. Note that high-speed solid state drives with very low + * seek times do not make for good sources of entropy, as their seek + * times are usually fairly consistent. + * + * The above three routines try to estimate how many bits of entropy + * to credit. They do this by keeping track of the first and second + * order deltas of the event timings. + * + * add_interrupt_randomness() uses the interrupt timing as random + * inputs to the entropy pool. Using the cycle counters and the irq source + * as inputs, it feeds the input pool roughly once a second or after 64 + * interrupts, crediting 1 bit of entropy for whichever comes first. + * + * add_hwgenerator_randomness() is for true hardware RNGs, and will credit + * entropy as specified by the caller. If the entropy pool is full it will + * block until more entropy is needed. + * + * add_bootloader_randomness() is the same as add_hwgenerator_randomness()= or + * add_device_randomness(), depending on whether or not the configuration + * option CONFIG_RANDOM_TRUST_BOOTLOADER is set. + * + **********************************************************************/ + + +static bool trust_cpu __ro_after_init =3D IS_ENABLED(CONFIG_RANDOM_TRUST_C= PU); +static int __init parse_trust_cpu(char *arg) +{ + return kstrtobool(arg, &trust_cpu); +} +early_param("random.trust_cpu", parse_trust_cpu); =20 /* - * This is a fast mixing routine used by the interrupt randomness - * collector. It's hardcoded for an 128 bit pool and assumes that any - * locks that might be needed are taken by the caller. + * The first collection of entropy occurs at system boot while interrupts + * are still turned off. Here we push in RDSEED, a timestamp, and utsname(= ). + * Depending on the above configuration knob, RDSEED may be considered + * sufficient for initialization. Note that much earlier setup may already + * have pushed entropy into the input pool by the time we get here. */ -static void fast_mix(u32 pool[4]) +int __init rand_initialize(void) { - u32 a =3D pool[0], b =3D pool[1]; - u32 c =3D pool[2], d =3D pool[3]; - - a +=3D b; c +=3D d; - b =3D rol32(b, 6); d =3D rol32(d, 27); - d ^=3D a; b ^=3D c; + size_t i; + ktime_t now =3D ktime_get_real(); + bool arch_init =3D true; + unsigned long rv; =20 - a +=3D b; c +=3D d; - b =3D rol32(b, 16); d =3D rol32(d, 14); - d ^=3D a; b ^=3D c; + for (i =3D BLAKE2S_BLOCK_SIZE; i > 0; i -=3D sizeof(rv)) { + if (!arch_get_random_seed_long_early(&rv) && + !arch_get_random_long_early(&rv)) { + rv =3D random_get_entropy(); + arch_init =3D false; + } + mix_pool_bytes(&rv, sizeof(rv)); + } + mix_pool_bytes(&now, sizeof(now)); + mix_pool_bytes(utsname(), sizeof(*(utsname()))); =20 - a +=3D b; c +=3D d; - b =3D rol32(b, 6); d =3D rol32(d, 27); - d ^=3D a; b ^=3D c; + extract_entropy(base_crng.key, sizeof(base_crng.key)); + ++base_crng.generation; =20 - a +=3D b; c +=3D d; - b =3D rol32(b, 16); d =3D rol32(d, 14); - d ^=3D a; b ^=3D c; + if (arch_init && trust_cpu && crng_init < 2) { + crng_init =3D 2; + pr_notice("crng init done (trusting CPU's manufacturer)\n"); + } =20 - pool[0] =3D a; pool[1] =3D b; - pool[2] =3D c; pool[3] =3D d; + if (ratelimit_disable) { + urandom_warning.interval =3D 0; + unseeded_warning.interval =3D 0; + } + return 0; } =20 -/********************************************************************* - * - * Entropy input management - * - *********************************************************************/ - /* There is one of these per entropy source */ struct timer_rand_state { cycles_t last_time; long last_delta, last_delta2; }; =20 -#define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, }; - /* * Add device- or boot-specific data to the input pool to help * initialize it. @@ -959,8 +1014,6 @@ void add_device_randomness(const void *buf, size_t siz= e) } EXPORT_SYMBOL(add_device_randomness); =20 -static struct timer_rand_state input_timer_state =3D INIT_TIMER_RAND_STATE; - /* * This function adds entropy to the entropy "pool" by using timing * delays. It uses the timer_rand_state structure to make an estimate @@ -1022,8 +1075,9 @@ void add_input_randomness(unsigned int type, unsigned= int code, unsigned int value) { static unsigned char last_value; + static struct timer_rand_state input_timer_state =3D { INITIAL_JIFFIES }; =20 - /* ignore autorepeat and the like */ + /* Ignore autorepeat and the like. */ if (value =3D=3D last_value) return; =20 @@ -1033,6 +1087,116 @@ void add_input_randomness(unsigned int type, unsign= ed int code, } EXPORT_SYMBOL_GPL(add_input_randomness); =20 +#ifdef CONFIG_BLOCK +void add_disk_randomness(struct gendisk *disk) +{ + if (!disk || !disk->random) + return; + /* First major is 1, so we get >=3D 0x200 here. */ + add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); +} +EXPORT_SYMBOL_GPL(add_disk_randomness); + +void rand_initialize_disk(struct gendisk *disk) +{ + struct timer_rand_state *state; + + /* + * If kzalloc returns null, we just won't use that entropy + * source. + */ + state =3D kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); + if (state) { + state->last_time =3D INITIAL_JIFFIES; + disk->random =3D state; + } +} +#endif + +/* + * Interface for in-kernel drivers of true hardware RNGs. + * Those devices may produce endless random bits and will be throttled + * when our pool is full. + */ +void add_hwgenerator_randomness(const void *buffer, size_t count, + size_t entropy) +{ + if (unlikely(crng_init =3D=3D 0)) { + size_t ret =3D crng_fast_load(buffer, count); + mix_pool_bytes(buffer, ret); + count -=3D ret; + buffer +=3D ret; + if (!count || crng_init =3D=3D 0) + return; + } + + /* + * Throttle writing if we're above the trickle threshold. + * We'll be woken up again once below POOL_MIN_BITS, when + * the calling thread is about to terminate, or once + * CRNG_RESEED_INTERVAL has elapsed. + */ + wait_event_interruptible_timeout(random_write_wait, + !system_wq || kthread_should_stop() || + input_pool.entropy_count < POOL_MIN_BITS, + CRNG_RESEED_INTERVAL); + mix_pool_bytes(buffer, count); + credit_entropy_bits(entropy); +} +EXPORT_SYMBOL_GPL(add_hwgenerator_randomness); + +/* + * Handle random seed passed by bootloader. + * If the seed is trustworthy, it would be regarded as hardware RNGs. Othe= rwise + * it would be regarded as device data. + * The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER. + */ +void add_bootloader_randomness(const void *buf, size_t size) +{ + if (IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER)) + add_hwgenerator_randomness(buf, size, size * 8); + else + add_device_randomness(buf, size); +} +EXPORT_SYMBOL_GPL(add_bootloader_randomness); + +struct fast_pool { + unsigned long pool[16 / sizeof(long)]; + unsigned long last; + u16 reg_idx; + u8 count; +}; + +/* + * This is a fast mixing routine used by the interrupt randomness + * collector. It's hardcoded for an 128 bit pool and assumes that any + * locks that might be needed are taken by the caller. + */ +static void fast_mix(u32 pool[4]) +{ + u32 a =3D pool[0], b =3D pool[1]; + u32 c =3D pool[2], d =3D pool[3]; + + a +=3D b; c +=3D d; + b =3D rol32(b, 6); d =3D rol32(d, 27); + d ^=3D a; b ^=3D c; + + a +=3D b; c +=3D d; + b =3D rol32(b, 16); d =3D rol32(d, 14); + d ^=3D a; b ^=3D c; + + a +=3D b; c +=3D d; + b =3D rol32(b, 6); d =3D rol32(d, 27); + d ^=3D a; b ^=3D c; + + a +=3D b; c +=3D d; + b =3D rol32(b, 16); d =3D rol32(d, 14); + d ^=3D a; b ^=3D c; + + pool[0] =3D a; pool[1] =3D b; + pool[2] =3D c; pool[3] =3D d; +} + static DEFINE_PER_CPU(struct fast_pool, irq_randomness); =20 static u32 get_reg(struct fast_pool *f, struct pt_regs *regs) @@ -1079,7 +1243,8 @@ void add_interrupt_randomness(int irq) fast_pool->count =3D 0; fast_pool->last =3D now; =20 - /* Technically this call means that we're using a spinlock_t + /* + * Technically this call means that we're using a spinlock_t * in the IRQ handler, which isn't terrific for PREEMPT_RT. * However, this only happens during boot, and then never * again, so we live with it. @@ -1101,22 +1266,11 @@ void add_interrupt_randomness(int irq) =20 fast_pool->count =3D 0; =20 - /* award one bit for the contents of the fast pool */ + /* Award one bit for the contents of the fast pool. */ credit_entropy_bits(1); } EXPORT_SYMBOL_GPL(add_interrupt_randomness); =20 -#ifdef CONFIG_BLOCK -void add_disk_randomness(struct gendisk *disk) -{ - if (!disk || !disk->random) - return; - /* first major is 1, so we get >=3D 0x200 here */ - add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); -} -EXPORT_SYMBOL_GPL(add_disk_randomness); -#endif - /* * Each time the timer fires, we expect that we got an unpredictable * jump in the cycle counter. Even if the timer is running on another @@ -1166,73 +1320,6 @@ static void try_to_generate_entropy(void) mix_pool_bytes(&stack.now, sizeof(stack.now)); } =20 -static bool trust_cpu __ro_after_init =3D IS_ENABLED(CONFIG_RANDOM_TRUST_C= PU); -static int __init parse_trust_cpu(char *arg) -{ - return kstrtobool(arg, &trust_cpu); -} -early_param("random.trust_cpu", parse_trust_cpu); - -/* - * Note that setup_arch() may call add_device_randomness() - * long before we get here. This allows seeding of the pools - * with some platform dependent data very early in the boot - * process. But it limits our options here. We must use - * statically allocated structures that already have all - * initializations complete at compile time. We should also - * take care not to overwrite the precious per platform data - * we were given. - */ -int __init rand_initialize(void) -{ - size_t i; - ktime_t now =3D ktime_get_real(); - bool arch_init =3D true; - unsigned long rv; - - for (i =3D BLAKE2S_BLOCK_SIZE; i > 0; i -=3D sizeof(rv)) { - if (!arch_get_random_seed_long_early(&rv) && - !arch_get_random_long_early(&rv)) { - rv =3D random_get_entropy(); - arch_init =3D false; - } - mix_pool_bytes(&rv, sizeof(rv)); - } - mix_pool_bytes(&now, sizeof(now)); - mix_pool_bytes(utsname(), sizeof(*(utsname()))); - - extract_entropy(base_crng.key, sizeof(base_crng.key)); - ++base_crng.generation; - - if (arch_init && trust_cpu && crng_init < 2) { - crng_init =3D 2; - pr_notice("crng init done (trusting CPU's manufacturer)\n"); - } - - if (ratelimit_disable) { - urandom_warning.interval =3D 0; - unseeded_warning.interval =3D 0; - } - return 0; -} - -#ifdef CONFIG_BLOCK -void rand_initialize_disk(struct gendisk *disk) -{ - struct timer_rand_state *state; - - /* - * If kzalloc returns null, we just won't use that entropy - * source. - */ - state =3D kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) { - state->last_time =3D INITIAL_JIFFIES; - disk->random =3D state; - } -} -#endif - static ssize_t urandom_read(struct file *file, char __user *buf, size_t nb= ytes, loff_t *ppos) { @@ -1527,47 +1614,3 @@ static int __init random_sysctls_init(void) } device_initcall(random_sysctls_init); #endif /* CONFIG_SYSCTL */ - -/* Interface for in-kernel drivers of true hardware RNGs. - * Those devices may produce endless random bits and will be throttled - * when our pool is full. - */ -void add_hwgenerator_randomness(const void *buffer, size_t count, - size_t entropy) -{ - if (unlikely(crng_init =3D=3D 0)) { - size_t ret =3D crng_fast_load(buffer, count); - mix_pool_bytes(buffer, ret); - count -=3D ret; - buffer +=3D ret; - if (!count || crng_init =3D=3D 0) - return; - } - - /* Throttle writing if we're above the trickle threshold. - * We'll be woken up again once below POOL_MIN_BITS, when - * the calling thread is about to terminate, or once - * CRNG_RESEED_INTERVAL has elapsed. - */ - wait_event_interruptible_timeout(random_write_wait, - !system_wq || kthread_should_stop() || - input_pool.entropy_count < POOL_MIN_BITS, - CRNG_RESEED_INTERVAL); - mix_pool_bytes(buffer, count); - credit_entropy_bits(entropy); -} -EXPORT_SYMBOL_GPL(add_hwgenerator_randomness); - -/* Handle random seed passed by bootloader. - * If the seed is trustworthy, it would be regarded as hardware RNGs. Othe= rwise - * it would be regarded as device data. - * The decision is controlled by CONFIG_RANDOM_TRUST_BOOTLOADER. - */ -void add_bootloader_randomness(const void *buf, size_t size) -{ - if (IS_ENABLED(CONFIG_RANDOM_TRUST_BOOTLOADER)) - add_hwgenerator_randomness(buf, size, size * 8); - else - add_device_randomness(buf, size); -} -EXPORT_SYMBOL_GPL(add_bootloader_randomness); --=20 2.35.0 From nobody Sun Jun 28 06:40:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4518DC433F5 for ; Fri, 11 Feb 2022 12:36:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350224AbiBKMgk (ORCPT ); Fri, 11 Feb 2022 07:36:40 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41958 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1350198AbiBKMg0 (ORCPT ); Fri, 11 Feb 2022 07:36:26 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 17ADBFC2 for ; Fri, 11 Feb 2022 04:36:24 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id C2541B829DF for ; Fri, 11 Feb 2022 12:36:22 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2CC9FC340E9; Fri, 11 Feb 2022 12:36:21 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="pbHJBPrX" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644582980; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=K6+huIJjfj/t+DigUHYU4QErBjCfT1MuACGpOG09eJk=; b=pbHJBPrXt4PyF1wCw0rnRE9ePoNLtE17mq3QBFXVVNZtweoPwhsMatMnv8ona2GhPRZW1k wMQAaV/mrGZm2XzfH2RaaM4M7b4rhrwAuF29cUdA29dfbszdaTDTsAZL0Qjb4mt7oSItLf 8OeKtBSf125OP8gCY3OdPstoBqYoqco= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id e133e010 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 11 Feb 2022 12:36:20 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH 8/9] random: group userspace read/write functions Date: Fri, 11 Feb 2022 13:35:45 +0100 Message-Id: <20220211123546.474952-9-Jason@zx2c4.com> In-Reply-To: <20220211123546.474952-1-Jason@zx2c4.com> References: <20220211123546.474952-1-Jason@zx2c4.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This pulls all of the userspace read/write-focused functions into the fifth labeled section. No functional changes. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld --- drivers/char/random.c | 124 ++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 48 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index f793bd3a1325..a4229474d7fa 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1320,30 +1320,60 @@ static void try_to_generate_entropy(void) mix_pool_bytes(&stack.now, sizeof(stack.now)); } =20 -static ssize_t urandom_read(struct file *file, char __user *buf, size_t nb= ytes, - loff_t *ppos) +/********************************************************************** + * + * Userspace reader/writer interfaces. + * + * getrandom(2) is the primary modern interface into the RNG and should + * be used in preference to anything else. + * + * Reading from /dev/random has the same functionality as calling + * getrandom(2) with flags=3D0. In earlier versions, however, it had + * vastly different semantics and should therefore be avoided, to + * prevent backwards compatibility issues. + * + * Reading from /dev/urandom has the same functionality as calling + * getrandom(2) with flags=3DGRND_INSECURE. Because it does not block + * waiting for the RNG to be ready, it should not be used. + * + * Writing to either /dev/random or /dev/urandom adds entropy to + * the input pool but does not credit it. + * + * Polling on /dev/random indicates when the RNG is initialized, on + * the read side, and when it wants new entropy, on the write side. + * + * Both /dev/random and /dev/urandom have the same set of ioctls for + * adding entropy, getting the entropy count, zeroing the count, and + * reseeding the crng. + * + **********************************************************************/ + +SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, unsigned int, + flags) { - static int maxwarn =3D 10; + if (flags & ~(GRND_NONBLOCK | GRND_RANDOM | GRND_INSECURE)) + return -EINVAL; =20 - if (!crng_ready() && maxwarn > 0) { - maxwarn--; - if (__ratelimit(&urandom_warning)) - pr_notice("%s: uninitialized urandom read (%zd bytes read)\n", - current->comm, nbytes); - } + /* + * Requesting insecure and blocking randomness at the same time makes + * no sense. + */ + if ((flags & (GRND_INSECURE | GRND_RANDOM)) =3D=3D (GRND_INSECURE | GRND_= RANDOM)) + return -EINVAL; =20 - return get_random_bytes_user(buf, nbytes); -} + if (count > INT_MAX) + count =3D INT_MAX; =20 -static ssize_t random_read(struct file *file, char __user *buf, size_t nby= tes, - loff_t *ppos) -{ - int ret; + if (!(flags & GRND_INSECURE) && !crng_ready()) { + int ret; =20 - ret =3D wait_for_random_bytes(); - if (ret !=3D 0) - return ret; - return get_random_bytes_user(buf, nbytes); + if (flags & GRND_NONBLOCK) + return -EAGAIN; + ret =3D wait_for_random_bytes(); + if (unlikely(ret)) + return ret; + } + return get_random_bytes_user(buf, count); } =20 static __poll_t random_poll(struct file *file, poll_table *wait) @@ -1395,6 +1425,32 @@ static ssize_t random_write(struct file *file, const= char __user *buffer, return (ssize_t)count; } =20 +static ssize_t urandom_read(struct file *file, char __user *buf, size_t nb= ytes, + loff_t *ppos) +{ + static int maxwarn =3D 10; + + if (!crng_ready() && maxwarn > 0) { + maxwarn--; + if (__ratelimit(&urandom_warning)) + pr_notice("%s: uninitialized urandom read (%zd bytes read)\n", + current->comm, nbytes); + } + + return get_random_bytes_user(buf, nbytes); +} + +static ssize_t random_read(struct file *file, char __user *buf, size_t nby= tes, + loff_t *ppos) +{ + int ret; + + ret =3D wait_for_random_bytes(); + if (ret !=3D 0) + return ret; + return get_random_bytes_user(buf, nbytes); +} + static long random_ioctl(struct file *f, unsigned int cmd, unsigned long a= rg) { int size, ent_count; @@ -1403,7 +1459,7 @@ static long random_ioctl(struct file *f, unsigned int= cmd, unsigned long arg) =20 switch (cmd) { case RNDGETENTCNT: - /* inherently racy, no point locking */ + /* Inherently racy, no point locking. */ if (put_user(input_pool.entropy_count, p)) return -EFAULT; return 0; @@ -1479,34 +1535,6 @@ const struct file_operations urandom_fops =3D { .llseek =3D noop_llseek, }; =20 -SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, unsigned int, - flags) -{ - if (flags & ~(GRND_NONBLOCK | GRND_RANDOM | GRND_INSECURE)) - return -EINVAL; - - /* - * Requesting insecure and blocking randomness at the same time makes - * no sense. - */ - if ((flags & (GRND_INSECURE | GRND_RANDOM)) =3D=3D (GRND_INSECURE | GRND_= RANDOM)) - return -EINVAL; - - if (count > INT_MAX) - count =3D INT_MAX; - - if (!(flags & GRND_INSECURE) && !crng_ready()) { - int ret; - - if (flags & GRND_NONBLOCK) - return -EAGAIN; - ret =3D wait_for_random_bytes(); - if (unlikely(ret)) - return ret; - } - return get_random_bytes_user(buf, count); -} - /******************************************************************** * * Sysctl interface --=20 2.35.0 From nobody Sun Jun 28 06:40:30 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A99CBC433EF for ; Fri, 11 Feb 2022 12:36:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343923AbiBKMgp (ORCPT ); Fri, 11 Feb 2022 07:36:45 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41960 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1350201AbiBKMg0 (ORCPT ); Fri, 11 Feb 2022 07:36:26 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DAD39FC6 for ; Fri, 11 Feb 2022 04:36:24 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 749F161D69 for ; Fri, 11 Feb 2022 12:36:24 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 783A0C340E9; Fri, 11 Feb 2022 12:36:23 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="bfaYytb2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644582982; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2HUlSTdAvSnpP+trRFyAY30tAXEfW/0+t8cww6KDvIw=; b=bfaYytb2rMbbJq5+eMcKANtkCa/+TZLn6ofkPnHlVr5raz7oVl2pXBCBuWRDCFZb6SAfzA C/fdc68/yxlEnB8rzN361hnT5TyMJSf+Xf7BoCNtkPnYE0/K5m1jJ3EUcjZXz/ZvZpyhei ydvXL9+6USu43RnS7CYGHFoy3DC9p/A= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 57cb0514 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 11 Feb 2022 12:36:22 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH 9/9] random: group sysctl functions Date: Fri, 11 Feb 2022 13:35:46 +0100 Message-Id: <20220211123546.474952-10-Jason@zx2c4.com> In-Reply-To: <20220211123546.474952-1-Jason@zx2c4.com> References: <20220211123546.474952-1-Jason@zx2c4.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This pulls all of the sysctl-focused functions into the sixth labeled section. No functional changes. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld --- drivers/char/random.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index a4229474d7fa..bff77654910c 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1537,7 +1537,25 @@ const struct file_operations urandom_fops =3D { =20 /******************************************************************** * - * Sysctl interface + * Sysctl interface. + * + * These are mostly unused legacy knobs with dummy values to not break + * userspace. Still in use, however, are: + * + * - /proc/sys/kernel/random/boot_id - a UUID representing the current + * boot. + * + * - /proc/sys/kernel/random/uuid - a random UUID, fresh each time. + * + * - /proc/sys/kernel/random/poolsize - the total amount of entropy + * that the input pool can hold. + * + * - /proc/sys/kernel/random/write_wakeup_threshold - the amount of + * entropy in the input pool below which write polls to + * /dev/random will unblock, requesting more entropy. This is + * currently the same value as the previous "poolsize" sysctl. It + * is writable to avoid breaking old userspaces, but writing to it + * does not change any behavior of the RNG. * ********************************************************************/ =20 @@ -1545,8 +1563,8 @@ const struct file_operations urandom_fops =3D { =20 #include =20 -static int random_min_urandom_seed =3D 60; -static int random_write_wakeup_bits =3D POOL_MIN_BITS; +static int sysctl_random_min_urandom_seed =3D 60; +static int sysctl_random_write_wakeup_bits =3D POOL_MIN_BITS; static int sysctl_poolsize =3D POOL_BITS; static char sysctl_bootid[16]; =20 @@ -1603,14 +1621,14 @@ static struct ctl_table random_table[] =3D { }, { .procname =3D "write_wakeup_threshold", - .data =3D &random_write_wakeup_bits, + .data =3D &sysctl_random_write_wakeup_bits, .maxlen =3D sizeof(int), .mode =3D 0644, .proc_handler =3D proc_dointvec, }, { .procname =3D "urandom_min_reseed_secs", - .data =3D &random_min_urandom_seed, + .data =3D &sysctl_random_min_urandom_seed, .maxlen =3D sizeof(int), .mode =3D 0644, .proc_handler =3D proc_dointvec, @@ -1641,4 +1659,4 @@ static int __init random_sysctls_init(void) return 0; } device_initcall(random_sysctls_init); -#endif /* CONFIG_SYSCTL */ +#endif --=20 2.35.0