linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Stephan Müller" <smueller@chronox.de>
To: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-crypto@vger.kernel.org, LKML <linux-kernel@vger.kernel.org>,
	linux-api@vger.kernel.org,
	"Eric W. Biederman" <ebiederm@xmission.com>,
	"Alexander E. Patrakov" <patrakov@gmail.com>,
	"Ahmed S. Darwish" <darwish.07@gmail.com>,
	"Theodore Y. Ts'o" <tytso@mit.edu>, Willy Tarreau <w@1wt.eu>,
	Matthew Garrett <mjg59@srcf.ucam.org>,
	Vito Caputo <vcaputo@pengaru.com>,
	Andreas Dilger <adilger.kernel@dilger.ca>,
	Jan Kara <jack@suse.cz>, Ray Strode <rstrode@redhat.com>,
	William Jon McCann <mccann@jhu.edu>,
	zhangjs <zachary@baishancloud.com>,
	Andy Lutomirski <luto@kernel.org>,
	Florian Weimer <fweimer@redhat.com>,
	Lennart Poettering <mzxreary@0pointer.de>,
	Nicolai Stange <nstange@suse.de>,
	"Peter, Matthias" <matthias.peter@bsi.bund.de>,
	Marcelo Henrique Cerri <marcelo.cerri@canonical.com>,
	Roman Drahtmueller <draht@schaltsekun.de>,
	Neil Horman <nhorman@redhat.com>,
	Randy Dunlap <rdunlap@infradead.org>,
	Julia Lawall <julia.lawall@inria.fr>,
	Dan Carpenter <dan.carpenter@oracle.com>,
	Andy Lavr <andy.lavr@gmail.com>,
	ebiggers@kernel.org
Subject: [PATCH v35 04/13] LRNG - add switchable DRNG support
Date: Fri, 18 Sep 2020 11:49:30 +0200	[thread overview]
Message-ID: <2767509.e9J7NaK4W3@positron.chronox.de> (raw)
In-Reply-To: <5667034.lOV4Wx5bFT@positron.chronox.de>

The DRNG switch support allows replacing the DRNG mechanism of the
LRNG. The switching support rests on the interface definition of
include/linux/lrng.h. A new DRNG is implemented by filling in the
interface defined in this header file.

In addition to the DRNG, the extension also has to provide a hash
implementation that is used to hash the entropy pool for random number
extraction.

Note: It is permissible to implement a DRNG whose operations may sleep.
However, the hash function must not sleep.

The switchable DRNG support allows replacing the DRNG at runtime.
However, only one DRNG extension is allowed to be loaded at any given
time. Before replacing it with another DRNG implementation, the possibly
existing DRNG extension must be unloaded.

The switchable DRNG extension activates the new DRNG during load time.
It is expected, however, that such a DRNG switch would be done only once
by an administrator to load the intended DRNG implementation.

It is permissible to compile DRNG extensions either as kernel modules or
statically. The initialization of the DRNG extension should be performed
with a late_initcall to ensure the extension is available when user
space starts but after all other initialization completed.
The initialization is performed by registering the function call data
structure with the lrng_set_drng_cb function. In order to unload the
DRNG extension, lrng_set_drng_cb must be invoked with the NULL
parameter.

The DRNG extension should always provide a security strength that is at
least as strong as LRNG_DRNG_SECURITY_STRENGTH_BITS.

The hash extension must not sleep and must not maintain a separate
state.

CC: "Eric W. Biederman" <ebiederm@xmission.com>
CC: "Alexander E. Patrakov" <patrakov@gmail.com>
CC: "Ahmed S. Darwish" <darwish.07@gmail.com>
CC: "Theodore Y. Ts'o" <tytso@mit.edu>
CC: Willy Tarreau <w@1wt.eu>
CC: Matthew Garrett <mjg59@srcf.ucam.org>
CC: Vito Caputo <vcaputo@pengaru.com>
CC: Andreas Dilger <adilger.kernel@dilger.ca>
CC: Jan Kara <jack@suse.cz>
CC: Ray Strode <rstrode@redhat.com>
CC: William Jon McCann <mccann@jhu.edu>
CC: zhangjs <zachary@baishancloud.com>
CC: Andy Lutomirski <luto@kernel.org>
CC: Florian Weimer <fweimer@redhat.com>
CC: Lennart Poettering <mzxreary@0pointer.de>
CC: Nicolai Stange <nstange@suse.de>
Reviewed-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
Reviewed-by: Roman Drahtmueller <draht@schaltsekun.de>
Tested-by: Roman Drahtmüller <draht@schaltsekun.de>
Tested-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
Tested-by: Neil Horman <nhorman@redhat.com>
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 drivers/char/lrng/Kconfig       |   7 ++
 drivers/char/lrng/Makefile      |   1 +
 drivers/char/lrng/lrng_switch.c | 203 ++++++++++++++++++++++++++++++++
 3 files changed, 211 insertions(+)
 create mode 100644 drivers/char/lrng/lrng_switch.c

diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig
index fbbcf2ef43b6..e211fcf5aa8b 100644
--- a/drivers/char/lrng/Kconfig
+++ b/drivers/char/lrng/Kconfig
@@ -69,4 +69,11 @@ config LRNG_COLLECTION_SIZE
 	default 512 if LRNG_COLLECTION_SIZE_512
 	default 1024 if LRNG_COLLECTION_SIZE_1024
 
+menuconfig LRNG_DRNG_SWITCH
+	bool "Support DRNG runtime switching"
+	help
+	  The Linux RNG per default uses a ChaCha20 DRNG that is
+	  accessible via the external interfaces. With this configuration
+	  option other DRNGs can be selected and loaded at runtime.
+
 endif # LRNG
diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile
index ac97f0b11cb7..0eb4a6849c88 100644
--- a/drivers/char/lrng/Makefile
+++ b/drivers/char/lrng/Makefile
@@ -10,3 +10,4 @@ obj-y				+= lrng_pool.o lrng_aux.o \
 
 obj-$(CONFIG_NUMA)		+= lrng_numa.o
 obj-$(CONFIG_SYSCTL)		+= lrng_proc.o
+obj-$(CONFIG_LRNG_DRNG_SWITCH)	+= lrng_switch.o
diff --git a/drivers/char/lrng/lrng_switch.c b/drivers/char/lrng/lrng_switch.c
new file mode 100644
index 000000000000..cbaf5cd544aa
--- /dev/null
+++ b/drivers/char/lrng/lrng_switch.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * LRNG DRNG switching support
+ *
+ * Copyright (C) 2016 - 2020, Stephan Mueller <smueller@chronox.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/lrng.h>
+
+#include "lrng_internal.h"
+
+static int lrng_drng_switch(struct lrng_drng *drng_store,
+			    const struct lrng_crypto_cb *cb, int node)
+{
+	const struct lrng_crypto_cb *old_cb;
+	unsigned long flags = 0, flags2 = 0;
+	int ret;
+	u8 seed[LRNG_DRNG_SECURITY_STRENGTH_BYTES];
+	void *new_drng = cb->lrng_drng_alloc(LRNG_DRNG_SECURITY_STRENGTH_BYTES);
+	void *old_drng, *new_hash, *old_hash;
+	u32 current_security_strength;
+	bool sl = false, reset_drng = !lrng_get_available();
+
+	if (IS_ERR(new_drng)) {
+		pr_warn("could not allocate new DRNG for NUMA node %d (%ld)\n",
+			node, PTR_ERR(new_drng));
+		return PTR_ERR(new_drng);
+	}
+
+	new_hash = cb->lrng_hash_alloc();
+	if (IS_ERR(new_hash)) {
+		pr_warn("could not allocate new LRNG pool hash (%ld)\n",
+			PTR_ERR(new_hash));
+		cb->lrng_drng_dealloc(new_drng);
+		return PTR_ERR(new_hash);
+	}
+
+	if (cb->lrng_hash_digestsize(new_hash) > LRNG_MAX_DIGESTSIZE) {
+		pr_warn("digest size of newly requested hash too large\n");
+		cb->lrng_hash_dealloc(new_hash);
+		cb->lrng_drng_dealloc(new_drng);
+		return -EINVAL;
+	}
+
+	current_security_strength = lrng_security_strength();
+	lrng_drng_lock(drng_store, &flags);
+
+	/*
+	 * Pull from existing DRNG to seed new DRNG regardless of seed status
+	 * of old DRNG -- the entropy state for the DRNG is left unchanged which
+	 * implies that als the new DRNG is reseeded when deemed necessary. This
+	 * seeding of the new DRNG shall only ensure that the new DRNG has the
+	 * same entropy as the old DRNG.
+	 */
+	ret = drng_store->crypto_cb->lrng_drng_generate_helper(
+				drng_store->drng, seed, sizeof(seed));
+	lrng_drng_unlock(drng_store, &flags);
+
+	if (ret < 0) {
+		reset_drng = true;
+		pr_warn("getting random data from DRNG failed for NUMA node %d (%d)\n",
+			node, ret);
+	} else {
+		/* seed new DRNG with data */
+		ret = cb->lrng_drng_seed_helper(new_drng, seed, ret);
+		if (ret < 0) {
+			reset_drng = true;
+			pr_warn("seeding of new DRNG failed for NUMA node %d (%d)\n",
+				node, ret);
+		} else {
+			pr_debug("seeded new DRNG of NUMA node %d instance from old DRNG instance\n",
+				 node);
+		}
+	}
+
+	mutex_lock(&drng_store->lock);
+	write_lock_irqsave(&drng_store->hash_lock, flags2);
+	/*
+	 * If we switch the DRNG from the initial ChaCha20 DRNG to something
+	 * else, there is a lock transition from spin lock to mutex (see
+	 * lrng_drng_is_atomic and how the lock is taken in lrng_drng_lock).
+	 * Thus, we need to take both locks during the transition phase.
+	 */
+	if (lrng_drng_is_atomic(drng_store)) {
+		spin_lock_irqsave(&drng_store->spin_lock, flags);
+		sl = true;
+	} else {
+		__acquire(&drng_store->spin_lock);
+	}
+
+	if (reset_drng)
+		lrng_drng_reset(drng_store);
+
+	old_drng = drng_store->drng;
+	old_cb = drng_store->crypto_cb;
+	drng_store->drng = new_drng;
+	drng_store->crypto_cb = cb;
+
+	old_hash = drng_store->hash;
+	drng_store->hash = new_hash;
+	pr_info("Entropy pool read-hash allocated for DRNG for NUMA node %d\n",
+		node);
+
+	lrng_set_digestsize(cb->lrng_hash_digestsize(new_hash));
+
+	/* Reseed if previous LRNG security strength was insufficient */
+	if (current_security_strength < lrng_security_strength())
+		drng_store->force_reseed = true;
+
+	if (sl)
+		spin_unlock_irqrestore(&drng_store->spin_lock, flags);
+	else
+		__release(&drng_store->spin_lock);
+	write_unlock_irqrestore(&drng_store->hash_lock, flags2);
+	mutex_unlock(&drng_store->lock);
+
+	/* ChaCha20 serves as atomic instance left untouched. */
+	if (old_drng != &chacha20) {
+		old_cb->lrng_drng_dealloc(old_drng);
+		old_cb->lrng_hash_dealloc(old_hash);
+	}
+
+	pr_info("DRNG of NUMA node %d switched\n", node);
+
+	return 0;
+}
+
+/*
+ * Switch the existing DRNG instances with new using the new crypto callbacks.
+ * The caller must hold the lrng_crypto_cb_update lock.
+ */
+static int lrng_drngs_switch(const struct lrng_crypto_cb *cb)
+{
+	struct lrng_drng **lrng_drng = lrng_drng_instances();
+	struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
+	int ret = 0;
+
+	/* Update DRNG */
+	if (lrng_drng) {
+		u32 node;
+
+		for_each_online_node(node) {
+			if (lrng_drng[node])
+				ret = lrng_drng_switch(lrng_drng[node], cb,
+						       node);
+		}
+	} else {
+		ret = lrng_drng_switch(lrng_drng_init, cb, 0);
+	}
+
+	if (!ret)
+		lrng_set_available();
+
+	return 0;
+}
+
+/**
+ * lrng_set_drng_cb - Register new cryptographic callback functions for DRNG
+ * The registering implies that all old DRNG states are replaced with new
+ * DRNG states.
+ *
+ * @cb: Callback functions to be registered -- if NULL, use the default
+ *	callbacks pointing to the ChaCha20 DRNG.
+ *
+ * Return:
+ * * 0 on success
+ * * < 0 on error
+ */
+int lrng_set_drng_cb(const struct lrng_crypto_cb *cb)
+{
+	struct lrng_drng *lrng_drng_init = lrng_drng_init_instance();
+	int ret;
+
+	if (!cb)
+		cb = &lrng_cc20_crypto_cb;
+
+	mutex_lock(&lrng_crypto_cb_update);
+
+	/*
+	 * If a callback other than the default is set, allow it only to be
+	 * set back to the default callback. This ensures that multiple
+	 * different callbacks can be registered at the same time. If a
+	 * callback different from the current callback and the default
+	 * callback shall be set, the current callback must be deregistered
+	 * (e.g. the kernel module providing it must be unloaded) and the new
+	 * implementation can be registered.
+	 */
+	if ((cb != &lrng_cc20_crypto_cb) &&
+	    (lrng_drng_init->crypto_cb != &lrng_cc20_crypto_cb)) {
+		pr_warn("disallow setting new cipher callbacks, unload the old callbacks first!\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = lrng_drngs_switch(cb);
+
+out:
+	mutex_unlock(&lrng_crypto_cb_update);
+	return ret;
+}
+EXPORT_SYMBOL(lrng_set_drng_cb);
-- 
2.26.2





  parent reply	other threads:[~2020-09-18 10:13 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-20  8:25 [PATCH v32 00/12] /dev/random - a new approach with full SP800-90B compliance Stephan Müller
2020-08-20  8:39 ` [PATCH v32 01/12] Linux Random Number Generator Stephan Müller
2020-08-20 11:46   ` kernel test robot
2020-08-20 12:31     ` Stephan Müller
2020-08-20  8:40 ` [PATCH v32 02/12] LRNG - allocate one DRNG instance per NUMA node Stephan Müller
2020-08-20  8:40 ` [PATCH v32 03/12] LRNG - sysctls and /proc interface Stephan Müller
2020-08-20  8:41 ` [PATCH v32 04/12] LRNG - add switchable DRNG support Stephan Müller
2020-08-20  8:42 ` [PATCH v32 05/12] crypto: DRBG - externalize DRBG functions for LRNG Stephan Müller
2020-08-20  8:42 ` [PATCH v32 06/12] LRNG - add SP800-90A DRBG extension Stephan Müller
2020-08-20 12:07   ` kernel test robot
2020-08-20 12:27     ` Stephan Müller
2020-08-20  8:43 ` [PATCH v32 07/12] LRNG - add kernel crypto API PRNG extension Stephan Müller
2020-08-20 12:32   ` kernel test robot
2020-08-20  8:43 ` [PATCH v32 08/12] crypto: provide access to a static Jitter RNG state Stephan Müller
2020-08-20  8:44 ` [PATCH v32 09/12] LRNG - add Jitter RNG fast noise source Stephan Müller
2020-08-20  8:44 ` [PATCH v32 10/12] LRNG - add SP800-90B compliant health tests Stephan Müller
2020-08-20  8:45 ` [PATCH v32 11/12] LRNG - add interface for gathering of raw entropy Stephan Müller
2020-08-20 12:47   ` kernel test robot
2020-08-20  8:45 ` [PATCH v32 12/12] LRNG - add power-on and runtime self-tests Stephan Müller
2020-08-21  5:37 ` [PATCH v33 00/12] /dev/random - a new approach with full SP800-90B compliance Stephan Müller
2020-08-21  5:38   ` [PATCH v33 01/12] Linux Random Number Generator Stephan Müller
2020-08-21 19:42     ` kernel test robot
2020-08-22  4:49       ` Stephan Müller
2020-08-22  3:34     ` kernel test robot
2020-08-26 14:27     ` kernel test robot
2020-08-26 14:22       ` Stephan Mueller
2020-08-21  5:39   ` [PATCH v33 02/12] LRNG - allocate one DRNG instance per NUMA node Stephan Müller
2020-08-21  5:39   ` [PATCH v33 03/12] LRNG - sysctls and /proc interface Stephan Müller
2020-08-23  7:10     ` kernel test robot
2020-08-21  5:40   ` [PATCH v33 04/12] LRNG - add switchable DRNG support Stephan Müller
2020-08-21  5:40   ` [PATCH v33 05/12] crypto: DRBG - externalize DRBG functions for LRNG Stephan Müller
2020-08-21  5:41   ` [PATCH v33 06/12] LRNG - add SP800-90A DRBG extension Stephan Müller
2020-08-21  5:42   ` [PATCH v33 07/12] LRNG - add kernel crypto API PRNG extension Stephan Müller
2020-08-21  5:42   ` [PATCH v33 08/12] crypto: provide access to a static Jitter RNG state Stephan Müller
2020-08-21  5:42   ` [PATCH v33 09/12] LRNG - add Jitter RNG fast noise source Stephan Müller
2020-08-21  5:43   ` [PATCH v33 10/12] LRNG - add SP800-90B compliant health tests Stephan Müller
2020-08-21  5:43   ` [PATCH v33 11/12] LRNG - add interface for gathering of raw entropy Stephan Müller
2020-08-21  5:44   ` [PATCH v33 12/12] LRNG - add power-on and runtime self-tests Stephan Müller
2020-08-23 14:50     ` kernel test robot
2020-08-25  7:21   ` [PATCH v34 00/12] /dev/random - a new approach with full SP800-90B compliance Stephan Müller
2020-08-25  7:22     ` [PATCH v34 01/12] Linux Random Number Generator Stephan Müller
2020-08-25 11:28       ` kernel test robot
2020-08-25 11:51         ` Stephan Mueller
2020-08-31  9:24       ` kernel test robot
2020-08-25  7:23     ` [PATCH v34 02/12] LRNG - allocate one DRNG instance per NUMA node Stephan Müller
2020-08-25  7:23     ` [PATCH v34 03/12] LRNG - sysctls and /proc interface Stephan Müller
2020-08-25  7:24     ` [PATCH v34 04/12] LRNG - add switchable DRNG support Stephan Müller
2020-08-31 10:03       ` kernel test robot
2020-08-25  7:24     ` [PATCH v34 05/12] crypto: DRBG - externalize DRBG functions for LRNG Stephan Müller
2020-08-25  7:25     ` [PATCH v34 06/12] LRNG - add SP800-90A DRBG extension Stephan Müller
2020-08-25  7:25     ` [PATCH v34 07/12] LRNG - add kernel crypto API PRNG extension Stephan Müller
2020-08-25  7:26     ` [PATCH v34 08/12] crypto: provide access to a static Jitter RNG state Stephan Müller
2020-08-25  7:26     ` [PATCH v34 09/12] LRNG - add Jitter RNG fast noise source Stephan Müller
2020-08-25  7:27     ` [PATCH v34 10/12] LRNG - add SP800-90B compliant health tests Stephan Müller
2020-08-25  7:27     ` [PATCH v34 11/12] LRNG - add interface for gathering of raw entropy Stephan Müller
2020-08-25  7:27     ` [PATCH v34 12/12] LRNG - add power-on and runtime self-tests Stephan Müller
2020-09-18  9:47   ` [PATCH v35 00/13] /dev/random - a new approach Stephan Müller
2020-09-18  9:48     ` [PATCH v35 01/13] Linux Random Number Generator Stephan Müller
2020-09-18 13:02       ` kernel test robot
2020-09-20 16:49         ` Stephan Mueller
2020-09-18  9:48     ` [PATCH v35 02/13] LRNG - allocate one DRNG instance per NUMA node Stephan Müller
2020-09-18  9:49     ` [PATCH v35 03/13] LRNG - sysctls and /proc interface Stephan Müller
2020-09-18  9:49     ` Stephan Müller [this message]
2020-09-18  9:49     ` [PATCH v35 05/13] LRNG - add common generic hash support Stephan Müller
2020-09-18  9:50     ` [PATCH v35 06/13] crypto: DRBG - externalize DRBG functions for LRNG Stephan Müller
2020-09-18  9:50     ` [PATCH v35 07/13] LRNG - add SP800-90A DRBG extension Stephan Müller
2020-09-18  9:51     ` [PATCH v35 08/13] LRNG - add kernel crypto API PRNG extension Stephan Müller
2020-09-18  9:51     ` [PATCH v35 09/13] crypto: provide access to a static Jitter RNG state Stephan Müller
2020-09-18  9:51     ` [PATCH v35 10/13] LRNG - add Jitter RNG fast noise source Stephan Müller
2020-09-18  9:52     ` [PATCH v35 11/13] LRNG - add SP800-90B compliant health tests Stephan Müller
2020-09-18  9:53     ` [PATCH v35 12/13] LRNG - add interface for gathering of raw entropy Stephan Müller
2020-09-18  9:53     ` [PATCH v35 13/13] LRNG - add power-on and runtime self-tests Stephan Müller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2767509.e9J7NaK4W3@positron.chronox.de \
    --to=smueller@chronox.de \
    --cc=adilger.kernel@dilger.ca \
    --cc=andy.lavr@gmail.com \
    --cc=arnd@arndb.de \
    --cc=dan.carpenter@oracle.com \
    --cc=darwish.07@gmail.com \
    --cc=draht@schaltsekun.de \
    --cc=ebiederm@xmission.com \
    --cc=ebiggers@kernel.org \
    --cc=fweimer@redhat.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jack@suse.cz \
    --cc=julia.lawall@inria.fr \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=marcelo.cerri@canonical.com \
    --cc=matthias.peter@bsi.bund.de \
    --cc=mccann@jhu.edu \
    --cc=mjg59@srcf.ucam.org \
    --cc=mzxreary@0pointer.de \
    --cc=nhorman@redhat.com \
    --cc=nstange@suse.de \
    --cc=patrakov@gmail.com \
    --cc=rdunlap@infradead.org \
    --cc=rstrode@redhat.com \
    --cc=tytso@mit.edu \
    --cc=vcaputo@pengaru.com \
    --cc=w@1wt.eu \
    --cc=zachary@baishancloud.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).