From nobody Sun Jun 28 06:40:43 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 9EE9BC433F5 for ; Sat, 12 Feb 2022 12:23:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234784AbiBLMXg (ORCPT ); Sat, 12 Feb 2022 07:23:36 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41146 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229506AbiBLMXe (ORCPT ); Sat, 12 Feb 2022 07:23:34 -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 5387A24BE5 for ; Sat, 12 Feb 2022 04:23:31 -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 F010BB80691 for ; Sat, 12 Feb 2022 12:23:29 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1F84FC340E7; Sat, 12 Feb 2022 12:23:28 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="ODF4alSn" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668607; 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=ODF4alSnFZv0Vo4Y4ftU0BsLfvKnCmUXAh/Npp+RBclNrjOVgiFcdmKEdF5xfO/oLXF0Or zagaFN0cmyyCYV9qKnCgY/c8xV4lrB1UILRDAXHQ7lyqe6CySrY5dllGfTt7aYBri7YqyC 9xeZDxs0PXmCtuZQK1JjN61X5GFNyiw= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 5cdef4b8 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:27 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH v2 01/10] random: introduce drain_entropy() helper to declutter crng_reseed() Date: Sat, 12 Feb 2022 13:23:09 +0100 Message-Id: <20220212122318.623435-2-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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:43 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 E3B50C433EF for ; Sat, 12 Feb 2022 12:23:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234858AbiBLMXl (ORCPT ); Sat, 12 Feb 2022 07:23:41 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41172 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234788AbiBLMXh (ORCPT ); Sat, 12 Feb 2022 07:23:37 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DE01A26107 for ; Sat, 12 Feb 2022 04:23:33 -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 7426CB80691 for ; Sat, 12 Feb 2022 12:23:32 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id B8EAFC340E7; Sat, 12 Feb 2022 12:23:30 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="dQfub2nP" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668609; 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=dQfub2nPsXvqJ9dkmA9p8S497UZownITrhL1mhP12zvoQwNcGXVTKSNGGuqxWCh1c8ZX5R 92v1yqZWHOB6TquxPwr4wx23iPOgTliBOlymZy+dG6VmtFpEButDUXc+mzR1+FqL1AZFl7 h0Wa2Fb02nrPfagWbzb2hE+zNUjMCA8= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 6485056d (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:29 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH v2 02/10] random: remove useless header comment Date: Sat, 12 Feb 2022 13:23:10 +0100 Message-Id: <20220212122318.623435-3-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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 Reviewed-by: Eric Biggers --- 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:43 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 CE9A6C4332F for ; Sat, 12 Feb 2022 12:23:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234815AbiBLMXk (ORCPT ); Sat, 12 Feb 2022 07:23:40 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41168 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229506AbiBLMXg (ORCPT ); Sat, 12 Feb 2022 07:23:36 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B1E7D26104 for ; Sat, 12 Feb 2022 04:23:33 -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 3152960DB4 for ; Sat, 12 Feb 2022 12:23:33 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 52AE8C340EB; Sat, 12 Feb 2022 12:23:32 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="gn1LM65x" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668611; 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=J/8yLwagpOGE8KLuzvBKf6qvWRtBMqmj3atts0qnQVI=; b=gn1LM65xX4stV85DckA5lqVnDaT7Anc58zjf0/E5JlwAUW+TNZ94dCb47sJTEGx5nhqpd6 Y9P+1yRrsnwD/sZGEod7wo+6r6weyEojSbUWix5GZQd8jKMkFW94W4sM9xQkYh6U/SkIF3 4ixyCMcZilsjYI1ywMtUvO3G1moqqfQ= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 5796ac43 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:31 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" Subject: [PATCH v2 03/10] random: remove whitespace and reorder includes Date: Sat, 12 Feb 2022 13:23:11 +0100 Message-Id: <20220212122318.623435-4-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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 is purely cosmetic. Future work involves figuring out which of these headers we need and which we don't. Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld Reviewed-by: Eric Biggers --- drivers/char/random.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 436b146b33be..7bb18422705a 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -193,11 +193,10 @@ #include #include #include +#include #include #include - #include -#include #include #include #include --=20 2.35.0 From nobody Sun Jun 28 06:40:43 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 C99A5C433F5 for ; Sat, 12 Feb 2022 12:23:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234903AbiBLMXo (ORCPT ); Sat, 12 Feb 2022 07:23:44 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41198 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234810AbiBLMXj (ORCPT ); Sat, 12 Feb 2022 07:23:39 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3903D26130 for ; Sat, 12 Feb 2022 04:23:36 -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 BC77660D36 for ; Sat, 12 Feb 2022 12:23:35 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id CF305C340E7; Sat, 12 Feb 2022 12:23:34 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="oE3TUbAx" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668613; 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=jqlgXM82ulm0PWxX/S81Iwz6HBp4WblEfh/digKfBwg=; b=oE3TUbAxMG90vifz8dmX06gVGdiGfrYKLPzcnUV5Ceh1V9maAxvPqC92LrplaPBV1kxjff ztbUHQ8k4SzmMQV0lyFz0UJf1gw9iXqYlqInbKDaYeqPkWzfphELdcp1xVmZYwMs0btjag xbZVzFoJ2a+urXpTS1AlNOiB4OmeGwI= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 1c3d421e (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:33 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH v2 04/10] random: group initialization wait functions Date: Sat, 12 Feb 2022 13:23:12 +0100 Message-Id: <20220212122318.623435-5-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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 | 335 ++++++++++++++++++++++-------------------- 1 file changed, 174 insertions(+), 161 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 7bb18422705a..499ad32e3060 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -201,44 +201,199 @@ #include #include =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 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 @@ -319,22 +474,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; @@ -384,8 +523,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 @@ -903,29 +1040,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 @@ -1027,107 +1141,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:43 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 CAD1FC433F5 for ; Sat, 12 Feb 2022 12:23:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234933AbiBLMXr (ORCPT ); Sat, 12 Feb 2022 07:23:47 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41400 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229506AbiBLMXo (ORCPT ); Sat, 12 Feb 2022 07:23:44 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EABE226AD9 for ; Sat, 12 Feb 2022 04:23:38 -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 5DEC860D36 for ; Sat, 12 Feb 2022 12:23:38 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6DA20C340E7; Sat, 12 Feb 2022 12:23:37 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="oKd1FVBq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668616; 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=jEFWmMdmSM2u3OlUR5r5iPCfmz7oLX+27KlnpVqivWw=; b=oKd1FVBq9PBGYmZNZ5KHHp6fuFVk3FiPb0f8MFhKMId7RHAYyA8beMQ7hLbT79BHT5+iWk oDawdgivNBSyFv+2HuCi2blTJNLM/aH+5gakH8mHzJUiIOR574NbMUYKpB8Oe8oagoc8Lk D67vI5p8Ft9WbClvXta8C8Jew2aVGm4= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 85851cdf (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:35 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH v2 05/10] random: group crng functions Date: Sat, 12 Feb 2022 13:23:13 +0100 Message-Id: <20220212122318.623435-6-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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 499ad32e3060..737d70f1ead5 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -380,121 +380,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 @@ -523,70 +415,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; @@ -598,7 +434,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. @@ -635,13 +472,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], @@ -674,7 +509,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. @@ -692,7 +528,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))) @@ -701,7 +538,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. @@ -714,7 +552,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 @@ -724,54 +563,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 /********************************************************************* @@ -1040,58 +1258,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 @@ -1141,33 +1307,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) { @@ -1530,126 +1669,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:43 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 81D47C433FE for ; Sat, 12 Feb 2022 12:23:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234963AbiBLMXw (ORCPT ); Sat, 12 Feb 2022 07:23:52 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41376 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234902AbiBLMXq (ORCPT ); Sat, 12 Feb 2022 07:23:46 -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 2130526104 for ; Sat, 12 Feb 2022 04:23:42 -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 BC533B8069C for ; Sat, 12 Feb 2022 12:23:40 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 096F9C340EB; Sat, 12 Feb 2022 12:23:38 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="kixXmu13" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668618; 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=sdC/QVqfmi2fwu0h3ZARyEerNxhIEz48jbZbRvd2iUU=; b=kixXmu13PxrZnXxbmxPTipcaX55qSIR3MeXPu4quZ6a58MfM+uFm0pWqu4VeWQb3imM/HM FviIsDm13rbIlYzDb1v/qksgxAUlW8PArDEjqpMKN3cVkJJ7k5Ths+EFOZEIpM7dLaW3hM FQshNBybRWf13LA4sDmDZcaLfDGrriQ= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 6d161da7 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:38 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH v2 06/10] random: group entropy extraction functions Date: Sat, 12 Feb 2022 13:23:14 +0100 Message-Id: <20220212122318.623435-7-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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 | 217 +++++++++++++++++++++--------------------- 1 file changed, 109 insertions(+), 108 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 737d70f1ead5..8d1ed01c5a9f 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -883,23 +883,35 @@ 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; @@ -913,28 +925,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 { @@ -974,24 +1064,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 @@ -1187,77 +1259,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:43 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 2187FC433F5 for ; Sat, 12 Feb 2022 12:23:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233356AbiBLMX5 (ORCPT ); Sat, 12 Feb 2022 07:23:57 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41362 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234810AbiBLMXs (ORCPT ); Sat, 12 Feb 2022 07:23:48 -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 D28302715E for ; Sat, 12 Feb 2022 04:23:44 -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 53C8EB803F7 for ; Sat, 12 Feb 2022 12:23:43 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id C56BFC340E7; Sat, 12 Feb 2022 12:23:41 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="H3YWib8r" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668620; 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=i9lFgRy8qRS2D3Sx9jxxHR3PyBRWjBz5BdSIsLn3l6A=; b=H3YWib8rgrVihxrkqcBuHB9zN/kfdXIzLRintmk4+qN3M7w+NuY/0EshzHeREn3YFEuzDo fopDt0ywF6C9ZwGfmJWcuFAlJKNgVfBQ3OY9YhFQzTmjvdWW6buZjeL2Rd44B3l7wAEhFn phs/3qjrqfKBN2XvP64MeybyTo/y89c= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 13da860b (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:40 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH v2 07/10] random: group entropy collection functions Date: Sat, 12 Feb 2022 13:23:15 +0100 Message-Id: <20220212122318.623435-8-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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 8d1ed01c5a9f..d878c8506af9 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1027,57 +1027,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. @@ -1101,8 +1156,6 @@ void add_device_randomness(const void *buf, size_t si= ze) } 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 @@ -1164,8 +1217,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 @@ -1175,6 +1229,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) @@ -1221,7 +1385,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. @@ -1243,22 +1408,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 @@ -1308,73 +1462,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) { @@ -1669,47 +1756,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:43 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 9D38EC433EF for ; Sat, 12 Feb 2022 12:24:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235174AbiBLMYK (ORCPT ); Sat, 12 Feb 2022 07:24:10 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41386 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234917AbiBLMXu (ORCPT ); Sat, 12 Feb 2022 07:23:50 -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 518C727168 for ; Sat, 12 Feb 2022 04:23:46 -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 EF5C4B80735 for ; Sat, 12 Feb 2022 12:23:44 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 63AF0C340F0; Sat, 12 Feb 2022 12:23:43 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="kAGOg18e" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668622; 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=DKIyEOMgPV9hNg7dPpb9e9c9iQsgX08siVTCmaCVzxw=; b=kAGOg18ea7tSzf63lWezD2Ho80hTibZq1a1TUWrTU5Aud2hPnRVhOBn6Odp8ZdKnQU0ikv IRn36uliKLYk5492LlkDW65bnH04su/vdzNxeLSrPxPZbBeY0xQmf/wpT3d5dUNc8s2jNB VH2rC4ybYVIFeAxvkZ6N0TkT2JWr6gs= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 790e2be9 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:42 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH v2 08/10] random: group userspace read/write functions Date: Sat, 12 Feb 2022 13:23:16 +0100 Message-Id: <20220212122318.623435-9-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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 | 125 ++++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 48 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index d878c8506af9..b2af2dc96d20 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1462,30 +1462,61 @@ 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) @@ -1537,6 +1568,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; @@ -1545,7 +1602,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; @@ -1621,34 +1678,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:43 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 55B39C433EF for ; Sat, 12 Feb 2022 12:24:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235054AbiBLMYM (ORCPT ); Sat, 12 Feb 2022 07:24:12 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41594 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234868AbiBLMXv (ORCPT ); Sat, 12 Feb 2022 07:23:51 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 64A0E26AEE for ; Sat, 12 Feb 2022 04:23:47 -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 ECC3C60DD7 for ; Sat, 12 Feb 2022 12:23:46 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id F1A82C340E7; Sat, 12 Feb 2022 12:23:45 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="Lkk5yfOB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668624; 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=1Eoo9ySP03OmQh4+xMpPbnYZz6lR1PXVZ6II7xXSFf0=; b=Lkk5yfOBYtydDraGDyxjFHDxVtU3sZs0th0KvkXCTzLFgVFkPowKYaR9ozFwGXIrvgbOrG kFCacPIXI88RO7OtJ6JqFOrIGBW4XCNtlGyZRSVUSaqDLY+3YD/yL5NNaHNrJP6JHWhVHG efgqvJgMs8+N4jHATZVJsGuWBhgNp9I= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id 9f620fc4 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:44 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH v2 09/10] random: group sysctl functions Date: Sat, 12 Feb 2022 13:23:17 +0100 Message-Id: <20220212122318.623435-10-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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 | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index b2af2dc96d20..a32176a46691 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1678,9 +1678,34 @@ const struct file_operations urandom_fops =3D { .llseek =3D noop_llseek, }; =20 + /******************************************************************** * - * Sysctl interface + * Sysctl interface. + * + * These are partly unused legacy knobs with dummy values to not break + * userspace and partly still useful things. They are usually accessible + * in /proc/sys/kernel/random/ and are as follows: + * + * - boot_id - a UUID representing the current boot. + * + * - uuid - a random UUID, different each time the file is read. + * + * - poolsize - the number of bits of entropy that the input pool can + * hold, tied to the POOL_BITS constant. + * + * - entropy_avail - the number of bits of entropy currently in the + * input pool. Always <=3D poolsize. + * + * - write_wakeup_threshold - the amount of entropy in the input pool + * below which write polls to /dev/random will unblock, requesting + * more entropy, tied to the POOL_MIN_BITS constant. It is writable + * to avoid breaking old userspaces, but writing to it does not + * change any behavior of the RNG. + * + * - urandom_min_reseed_secs - fixed to the meaningless value "60". + * It is writable to avoid breaking old userspaces, but writing + * to it does not change any behavior of the RNG. * ********************************************************************/ =20 @@ -1688,8 +1713,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 @@ -1746,14 +1771,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, @@ -1784,4 +1809,4 @@ static int __init random_sysctls_init(void) return 0; } device_initcall(random_sysctls_init); -#endif /* CONFIG_SYSCTL */ +#endif --=20 2.35.0 From nobody Sun Jun 28 06:40:43 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 C8D44C433F5 for ; Sat, 12 Feb 2022 12:24:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234942AbiBLMYO (ORCPT ); Sat, 12 Feb 2022 07:24:14 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:41522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235024AbiBLMYD (ORCPT ); Sat, 12 Feb 2022 07:24:03 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 85CF227173 for ; Sat, 12 Feb 2022 04:23:50 -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 36624B8009F for ; Sat, 12 Feb 2022 12:23:49 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 94BB0C340E7; Sat, 12 Feb 2022 12:23:47 +0000 (UTC) Authentication-Results: smtp.kernel.org; dkim=pass (1024-bit key) header.d=zx2c4.com header.i=@zx2c4.com header.b="AcTGm1/v" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zx2c4.com; s=20210105; t=1644668626; 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=Ah62yBWjKDWezvtLCNByDe7+ng8YR5sjlAm6MH6qkbw=; b=AcTGm1/vA8SsdMhK8EH4erFVoGn6HOoHxZ6boFjFU8EGFZOTowlIbRTASvTkizlsDuTqqC a56XvFAWSp3bLBtuaIqh5b4uZBJzusgo2mJ9+8t7dB/nbUiBbeigaSzhEgteGQdt0s2Rh8 8cixy0fWShrZ61jsEJwJb88BvelpHQw= Received: by mail.zx2c4.com (ZX2C4 Mail Server) with ESMTPSA id b3f7e688 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Sat, 12 Feb 2022 12:23:46 +0000 (UTC) From: "Jason A. Donenfeld" To: linux-kernel@vger.kernel.org, linux@dominikbrodowski.net Cc: "Jason A. Donenfeld" , Theodore Ts'o Subject: [PATCH v2 10/10] random: rewrite header introductory comment Date: Sat, 12 Feb 2022 13:23:18 +0100 Message-Id: <20220212122318.623435-11-Jason@zx2c4.com> In-Reply-To: <20220212122318.623435-1-Jason@zx2c4.com> References: <20220212122318.623435-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" Now that we've re-documented the various sections, we can remove the outdated text here and replace it with a high-level overview. Cc: Theodore Ts'o Cc: Dominik Brodowski Signed-off-by: Jason A. Donenfeld Reviewed-by: Eric Biggers --- drivers/char/random.c | 183 +++++------------------------------------- 1 file changed, 21 insertions(+), 162 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index a32176a46691..6ffa779b7ed8 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -2,168 +2,27 @@ /* * 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. - * - * 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 - * - * 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: - * - * mknod /dev/random c 1 8 - * mknod /dev/urandom c 1 9 + * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All rights= reserved. + * + * This driver produces cryptographically secure pseudorandom data. It is = divided + * into roughly six sections, each with a section header: + * + * - Initialization and readiness waiting. + * - Fast key erasure RNG, the "crng". + * - Entropy accumulation and extraction routines. + * - Entropy collection routines. + * - Userspace reader/writer interfaces. + * - Sysctl interface. + * + * 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 indefinitely 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, which can lead to malicious entropy sources causing a prematu= re + * reseed, and the entropy estimates are, at best, conservative guesses. */ =20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt --=20 2.35.0