Received: by 2002:a25:31c3:0:0:0:0:0 with SMTP id x186csp6580517ybx; Mon, 11 Nov 2019 11:16:43 -0800 (PST) X-Google-Smtp-Source: APXvYqzCuWm5KLPzXY5IbL1LFfaRITACivI4Hnz344t5zqTC8RdaK/YohUXgTwVC5/i9Nff7yUdf X-Received: by 2002:aa7:c453:: with SMTP id n19mr29143506edr.103.1573499803290; Mon, 11 Nov 2019 11:16:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1573499803; cv=none; d=google.com; s=arc-20160816; b=MLxkq/P+EYHsPFdZCSk6WLwGMdXfUtm/88yioTZAKS/ptgMZo5ox5lLnNUI3dTl9ad +n/V7p5qgEfVTGEWIBv3GauhhtTtzUel/sAUAtN8mRoGWnlWigiPJ+pZwy0Vrl04T3Rk EH6xuRc1nbe6GV5mluSoVs5I6i0NJwl40XLko6LiVm9dp8mayrN13FQc4tNJFrKzlsoG F3TY5MuhbkqfDkrRe00lO74hLMonGYaqXSWt/LNOAp/ANcQCDe10tdXLS8x1pR7/CxhU QbUZjc2qYRyM80ag1SQ07TYlm2SMHxGw4vf3qubetU/IqCdoKPmn/MYD+8bPiRMHgb70 maug== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=XJfsX2VkyNZQQ+vfPz0V1XanViAq2gWBoWST0GuF5ls=; b=qrA2eQgWPnwctvafTm/vcXFCqk2ztW7jyFtVi3nbZPGEYmqQ2iHU9UgrZtmvAPUO73 ss5gF5EYrRpxvD4eHoTK5TSx6KMq1meuov05rqlCfSYeERT3oRRwVsK/OOACS3fC+Sps PYYRbI/Iqy6pUcE1MqdDy3OIgDsi1c2hMa3GaG4sa5Y7cBAYMxu+Es0Qh35YCmC+czJu g7AvZRfxrZVPsau4cBWYNCBhrC7tHM09/Q42e6bink5k9xsG2FtyGe+25SOY+jwn0nFn Rg2ZIMpdmBRbcnaa2c8c0ddmrxJ/McIUc0bgl5FJJV4MPmPl/JcnPFgk/NocngpVFXGU 7wfg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@chronox.de header.s=strato-dkim-0002 header.b=rC+fZ6Dd; spf=pass (google.com: best guess record for domain of linux-crypto-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i31si11889702eda.147.2019.11.11.11.16.18; Mon, 11 Nov 2019 11:16:43 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-crypto-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@chronox.de header.s=strato-dkim-0002 header.b=rC+fZ6Dd; spf=pass (google.com: best guess record for domain of linux-crypto-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727027AbfKKTOI (ORCPT + 99 others); Mon, 11 Nov 2019 14:14:08 -0500 Received: from mo4-p04-ob.smtp.rzone.de ([85.215.255.122]:30221 "EHLO mo4-p04-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726821AbfKKTOI (ORCPT ); Mon, 11 Nov 2019 14:14:08 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1573499643; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: X-RZG-CLASS-ID:X-RZG-AUTH:From:Subject:Sender; bh=XJfsX2VkyNZQQ+vfPz0V1XanViAq2gWBoWST0GuF5ls=; b=rC+fZ6DdX4pfdbSFtzqTygNfWayaNxQB8/3aM/fikircKFBHx24y76LNjiNFubKGNE yyDKfPBtMR7WyNUpO2tky+A0RzZRFuS9uRYGY9X2EAk/7AlsaaK+qbuxyYq0gV2Krlwg oninkFFGm7t1K+OO1j3bB3YpSF/VRjOSjimheBT4GXdt1nqDnIvmEpp4kaGZrrMR9wwn 0kJBJnZzuhl17gfU0+/9lpc/sofwhTtS/Xsb+TNfiLCDCD5E1zBL9ysoqMkeYpD9olFS mKe+0qmw/oAGKxy6hRXk1601Ey43a7eAh1mOgmIQ3V44Oa9w83OWLKQV0HOfwfQmePyV SO/g== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9zmgLKehaO2hZDSTWbgzIOA==" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 44.29.0 AUTH) with ESMTPSA id N09a57vABJCw3XW (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (curve secp521r1 with 521 ECDH bits, eq. 15360 bits RSA)) (Client did not present a certificate); Mon, 11 Nov 2019 20:12:58 +0100 (CET) From: Stephan =?ISO-8859-1?Q?M=FCller?= To: Arnd Bergmann Cc: Greg Kroah-Hartman , linux-crypto@vger.kernel.org, LKML , linux-api@vger.kernel.org, "Eric W. Biederman" , "Alexander E. Patrakov" , "Ahmed S. Darwish" , "Theodore Y. Ts'o" , Willy Tarreau , Matthew Garrett , Vito Caputo , Andreas Dilger , Jan Kara , Ray Strode , William Jon McCann , zhangjs , Andy Lutomirski , Florian Weimer , Lennart Poettering , Nicolai Stange , "Peter, Matthias" , Marcelo Henrique Cerri , Roman Drahtmueller , Neil Horman Subject: [PATCH v24 04/12] LRNG - add switchable DRNG support Date: Mon, 11 Nov 2019 19:20:40 +0100 Message-ID: <3626571.EnKpNK2LR4@positron.chronox.de> In-Reply-To: <6157374.ptSnyUpaCn@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="iso-8859-1" Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org 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. CC: "Eric W. Biederman" CC: "Alexander E. Patrakov" CC: "Ahmed S. Darwish" CC: "Theodore Y. Ts'o" CC: Willy Tarreau CC: Matthew Garrett CC: Vito Caputo CC: Andreas Dilger CC: Jan Kara CC: Ray Strode CC: William Jon McCann CC: zhangjs CC: Andy Lutomirski CC: Florian Weimer CC: Lennart Poettering CC: Nicolai Stange Reviewed-by: Marcelo Henrique Cerri Reviewed-by: Roman Drahtmueller Tested-by: Roman Drahtm=FCller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller =2D-- drivers/char/lrng/Kconfig | 7 ++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_switch.c | 198 ++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 drivers/char/lrng/lrng_switch.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index edf8be6aa0b1..a468d8292bac 100644 =2D-- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -52,4 +52,11 @@ config LRNG_POOL_SIZE default 4 if LRNG_POOL_SIZE_65536 default 5 if LRNG_POOL_SIZE_131072 =20 +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 b6240b73e33d..6bac97638767 100644 =2D-- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -10,3 +10,4 @@ obj-y +=3D lrng_pool.o lrng_aux.o \ =20 obj-$(CONFIG_NUMA) +=3D lrng_numa.o obj-$(CONFIG_SYSCTL) +=3D lrng_proc.o +obj-$(CONFIG_LRNG_DRNG_SWITCH) +=3D lrng_switch.o diff --git a/drivers/char/lrng/lrng_switch.c b/drivers/char/lrng/lrng_switc= h.c new file mode 100644 index 000000000000..55eb4ed73258 =2D-- /dev/null +++ b/drivers/char/lrng/lrng_switch.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG DRNG switching support + * + * Copyright (C) 2016 - 2019, Stephan Mueller + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include + +#include "lrng_internal.h" + +static void lrng_sdrng_switch(struct lrng_sdrng *sdrng_store, + const struct lrng_crypto_cb *cb, int node) +{ + const struct lrng_crypto_cb *old_cb; + unsigned long flags =3D 0; + int ret; + u8 seed[LRNG_DRNG_SECURITY_STRENGTH_BYTES]; + void *new_sdrng =3D + cb->lrng_drng_alloc(LRNG_DRNG_SECURITY_STRENGTH_BYTES); + void *old_sdrng, *new_hash =3D NULL, *old_hash =3D NULL; + bool sl =3D false, reset_sdrng =3D !lrng_get_available(); + + if (IS_ERR(new_sdrng)) { + pr_warn("could not allocate new secondary DRNG for NUMA node " + "%d (%ld)\n", node, PTR_ERR(new_sdrng)); + return; + } + +#ifndef CONFIG_LRNG_TRNG_SUPPORT + new_hash =3D cb->lrng_hash_alloc(seed, sizeof(seed)); +#endif /* CONFIG_LRNG_TRNG_SUPPORT */ + 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_sdrng); + return; + } + + lrng_sdrng_lock(sdrng_store, &flags); + + /* + * Pull from existing DRNG to seed new DRNG regardless of seed status + * of old DRNG -- the entropy state for the secondary 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 =3D sdrng_store->crypto_cb->lrng_drng_generate_helper( + sdrng_store->sdrng, seed, sizeof(seed)); + lrng_sdrng_unlock(sdrng_store, &flags); + + if (ret < 0) { + reset_sdrng =3D true; + pr_warn("getting random data from secondary DRNG failed for " + "NUMA node %d (%d)\n", node, ret); + } else { + /* seed new DRNG with data */ + ret =3D cb->lrng_drng_seed_helper(new_sdrng, seed, ret); + if (ret < 0) { + reset_sdrng =3D true; + pr_warn("seeding of new secondary DRNG failed for NUMA " + "node %d (%d)\n", node, ret); + } else { + pr_debug("seeded new secondary DRNG of NUMA node %d " + "instance from old secondary DRNG instance\n", + node); + } + } + + mutex_lock(&sdrng_store->lock); + /* + * If we switch the secondary DRNG from the initial ChaCha20 DRNG to + * something else, there is a lock transition from spin lock to mutex + * (see lrng_sdrng_is_atomic and how the lock is taken in + * lrng_sdrng_lock). Thus, we need to take both locks during the + * transition phase. + */ + if (lrng_sdrng_is_atomic(sdrng_store)) { + spin_lock_irqsave(&sdrng_store->spin_lock, flags); + sl =3D true; + } + + if (reset_sdrng) + lrng_sdrng_reset(sdrng_store); + + old_sdrng =3D sdrng_store->sdrng; + old_cb =3D sdrng_store->crypto_cb; + sdrng_store->sdrng =3D new_sdrng; + sdrng_store->crypto_cb =3D cb; + + if (new_hash) { + old_hash =3D sdrng_store->hash; + sdrng_store->hash =3D new_hash; + pr_info("Entropy pool read-hash allocated for DRNG for NUMA " + "node %d\n", node); + } + + if (sl) + spin_unlock_irqrestore(&sdrng_store->spin_lock, flags); + mutex_unlock(&sdrng_store->lock); + + /* Secondary ChaCha20 serves as atomic instance left untouched. */ + if (old_sdrng !=3D &secondary_chacha20) { + old_cb->lrng_drng_dealloc(old_sdrng); + if (old_hash) + old_cb->lrng_hash_dealloc(old_hash); + } + + pr_info("secondary DRNG of NUMA node %d switched\n", node); +} + +/** + * Switch the existing DRNG instances with new using the new crypto callba= cks. + * The caller must hold the lrng_crypto_cb_update lock. + */ +static int lrng_drngs_switch(const struct lrng_crypto_cb *cb) +{ + struct lrng_sdrng **lrng_sdrng =3D lrng_sdrng_instances(); + struct lrng_sdrng *lrng_sdrng_init =3D lrng_sdrng_init_instance(); + int ret =3D lrng_trng_switch(cb); + + if (ret) + return ret; + + /* Update secondary DRNG */ + if (lrng_sdrng) { + u32 node; + + for_each_online_node(node) { + if (lrng_sdrng[node]) + lrng_sdrng_switch(lrng_sdrng[node], cb, node); + } + } else + lrng_sdrng_switch(lrng_sdrng_init, cb, 0); + + lrng_set_available(); + + return 0; +} + +/** + * lrng_set_drng_cb - Register new cryptographic callback functions for DR= NG + * 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_sdrng *lrng_sdrng_init =3D lrng_sdrng_init_instance(); + int ret; + + if (!cb) + cb =3D &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 !=3D &lrng_cc20_crypto_cb) && + (lrng_sdrng_init->crypto_cb !=3D &lrng_cc20_crypto_cb)) { + pr_warn("disallow setting new cipher callbacks, unload the old " + "callbacks first!\n"); + ret =3D -EINVAL; + goto out; + } + + ret =3D lrng_drngs_switch(cb); + +out: + mutex_unlock(&lrng_crypto_cb_update); + return ret; +} +EXPORT_SYMBOL(lrng_set_drng_cb); =2D-=20 2.23.0