From patchwork Wed Apr 15 10:10:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 197866 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E03D5C3815B for ; Wed, 15 Apr 2020 10:37:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B3685206D9 for ; Wed, 15 Apr 2020 10:37:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="MrVBETcW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2408780AbgDOKhM (ORCPT ); Wed, 15 Apr 2020 06:37:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58462 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2408661AbgDOKcH (ORCPT ); Wed, 15 Apr 2020 06:32:07 -0400 Received: from mo6-p04-ob.smtp.rzone.de (mo6-p04-ob.smtp.rzone.de [IPv6:2a01:238:20a:202:5304::10]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 32F4FC061A0E; Wed, 15 Apr 2020 03:32:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1586946725; 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=Sgr3v6dugvxga2hSTRCXcLr7eMIcwuyjEkWnP4wunHI=; b=MrVBETcW+0M3A3Us/xXfy9ElaDSRH6u9RDKaj7ry/gNZqbdhJDnOeI6TjfarwJEJyX VIwIjoaRcGsWK1kHzPsqpkv/HKwfvsto58nK/R7iS7WBcyNncW3X38hVPJZGnR2fwLiQ n+G+TVSl0HHarb2wYMF5s+shi/JW7ZwVKVXlkPtKt1Qrv+gyVrzheZ7HPui4VXF6r9Wv QlWRkdERESd7O0wjZJbfM0A7NcWwDXAh/ma9yhP8YaYz+xcf7uqZuxBdAx3PUlwQItAW TayF7bOtuKyNQvblhttU11hbh0z65s2x/doaTIXoU3VA+1oQruFHQWGwI5iEZFlOkNy/ Z7PA== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPZIvSaiyU=" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.4.0 DYNA|AUTH) with ESMTPSA id 404ef0w3FAJv12C (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 15 Apr 2020 12:19:57 +0200 (CEST) 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 , Randy Dunlap , Julia Lawall , Dan Carpenter Subject: [PATCH v30 02/12] LRNG - allocate one DRNG instance per NUMA node Date: Wed, 15 Apr 2020 12:10:46 +0200 Message-ID: <20413735.rLLoclF7Ky@positron.chronox.de> In-Reply-To: <11836144.hkEK2qVKZC@positron.chronox.de> References: <11836144.hkEK2qVKZC@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org In order to improve NUMA-locality when serving getrandom(2) requests, allocate one DRNG instance per node. The DRNG instance that is present right from the start of the kernel is reused as the first per-NUMA-node DRNG. For all remaining online NUMA nodes a new DRNG instance is allocated. During boot time, the multiple DRNG instances are seeded sequentially. With this, the first DRNG instance (referenced as the initial DRNG in the code) is completely seeded with 256 bits of entropy before the next DRNG instance is completely seeded. When random numbers are requested, the NUMA-node-local DRNG is checked whether it has been already fully seeded. If this is not the case, the initial DRNG is used to serve the request. 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üller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Makefile | 2 + drivers/char/lrng/lrng_internal.h | 5 ++ drivers/char/lrng/lrng_numa.c | 101 ++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 drivers/char/lrng/lrng_numa.c diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index 1d2a0211973d..0a32f22c2c1a 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -7,3 +7,5 @@ obj-y += lrng_pool.o lrng_aux.o \ lrng_sw_noise.o lrng_archrandom.o \ lrng_drng.o lrng_chacha20.o \ lrng_interfaces.o \ + +obj-$(CONFIG_NUMA) += lrng_numa.o diff --git a/drivers/char/lrng/lrng_internal.h b/drivers/char/lrng/lrng_internal.h index edf38121ec65..ecb0a7ad5e7e 100644 --- a/drivers/char/lrng/lrng_internal.h +++ b/drivers/char/lrng/lrng_internal.h @@ -246,8 +246,13 @@ int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen); void lrng_drng_force_reseed(void); void lrng_drng_seed_work(struct work_struct *dummy); +#ifdef CONFIG_NUMA +struct lrng_drng **lrng_drng_instances(void); +void lrng_drngs_numa_alloc(void); +#else /* CONFIG_NUMA */ static inline struct lrng_drng **lrng_drng_instances(void) { return NULL; } static inline void lrng_drngs_numa_alloc(void) { return; } +#endif /* CONFIG_NUMA */ /************************** Health Test linking code **************************/ diff --git a/drivers/char/lrng/lrng_numa.c b/drivers/char/lrng/lrng_numa.c new file mode 100644 index 000000000000..947c5b3ed517 --- /dev/null +++ b/drivers/char/lrng/lrng_numa.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG NUMA support + * + * Copyright (C) 2016 - 2020, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include "lrng_internal.h" + +static struct lrng_drng **lrng_drng __read_mostly = NULL; + +struct lrng_drng **lrng_drng_instances(void) +{ + return lrng_drng; +} + +/* Allocate the data structures for the per-NUMA node DRNGs */ +static void _lrng_drngs_numa_alloc(struct work_struct *work) +{ + struct lrng_drng **drngs; + struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); + u32 node; + bool init_drng_used = false; + + mutex_lock(&lrng_crypto_cb_update); + + /* per-NUMA-node DRNGs are already present */ + if (lrng_drng) + goto unlock; + + drngs = kcalloc(nr_node_ids, sizeof(void *), GFP_KERNEL|__GFP_NOFAIL); + for_each_online_node(node) { + struct lrng_drng *drng; + + if (!init_drng_used) { + drngs[node] = lrng_drng_init; + init_drng_used = true; + continue; + } + + drng = kmalloc_node(sizeof(struct lrng_drng), + GFP_KERNEL|__GFP_NOFAIL, node); + memset(drng, 0, sizeof(lrng_drng)); + + drng->crypto_cb = lrng_drng_init->crypto_cb; + drng->drng = drng->crypto_cb->lrng_drng_alloc( + LRNG_DRNG_SECURITY_STRENGTH_BYTES); + if (IS_ERR(drng->drng)) { + kfree(drng); + goto err; + } + + mutex_init(&drng->lock); + spin_lock_init(&drng->spin_lock); + + /* + * No reseeding of NUMA DRNGs from previous DRNGs as this + * would complicate the code. Let it simply reseed. + */ + lrng_drng_reset(drng); + drngs[node] = drng; + + lrng_pool_inc_numa_node(); + pr_info("DRNG for NUMA node %d allocated\n", node); + } + + /* Ensure that all NUMA nodes receive changed memory here. */ + mb(); + + if (!cmpxchg(&lrng_drng, NULL, drngs)) + goto unlock; + +err: + for_each_online_node(node) { + struct lrng_drng *drng = drngs[node]; + + if (drng == lrng_drng_init) + continue; + + if (drng) { + drng->crypto_cb->lrng_drng_dealloc(drng->drng); + kfree(drng); + } + } + kfree(drngs); + +unlock: + mutex_unlock(&lrng_crypto_cb_update); +} + +static DECLARE_WORK(lrng_drngs_numa_alloc_work, _lrng_drngs_numa_alloc); + +void lrng_drngs_numa_alloc(void) +{ + schedule_work(&lrng_drngs_numa_alloc_work); +} From patchwork Wed Apr 15 10:11:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 197869 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E184CC2BA19 for ; Wed, 15 Apr 2020 10:33:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B80A8206D9 for ; Wed, 15 Apr 2020 10:33:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="Y90gRVEA" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2408580AbgDOKcW (ORCPT ); Wed, 15 Apr 2020 06:32:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58460 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2408660AbgDOKcH (ORCPT ); Wed, 15 Apr 2020 06:32:07 -0400 Received: from mo6-p04-ob.smtp.rzone.de (mo6-p04-ob.smtp.rzone.de [IPv6:2a01:238:20a:202:5304::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 07989C061A0C; Wed, 15 Apr 2020 03:32:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1586946725; 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=u6xlOooibfE9v+VmKfACjmHTfW5komSO8oNdl0Cm6pY=; b=Y90gRVEAuV1YtRJx3J38XhJsSF2WHQf+XBuZ1kX/HLHCzbIJ5xVYempxfQF0BhU+g7 Wh8P/f19jPqP5j3n5Cyvb9ydHUVoEj+qpIJBfXjLODbMqSVrUROpW5TsuLk/m63iTdc0 m8xnEZyeFcIcrhrpoNXZIITE7HO03dBudowpquuIfDINSBmRKkRoKZVQArSF7jNF1Yo5 2O7iH6isl/UEi73AYBA9FyqE/mQiqBTX73r3bFNTwe7XkQ539pE3bXoLZeP7aad2xbaS SjqK0bK9Z307fj8/3upGGEgDLKmiFh7cdeK6YbraYkQ3OkgdLPC2nqn5tJiLDVVoO6cA TNaw== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPZIvSaiyU=" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.4.0 DYNA|AUTH) with ESMTPSA id 404ef0w3FAJu12B (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 15 Apr 2020 12:19:56 +0200 (CEST) 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 , Randy Dunlap , Julia Lawall , Dan Carpenter Subject: [PATCH v30 03/12] LRNG - sysctls and /proc interface Date: Wed, 15 Apr 2020 12:11:15 +0200 Message-ID: <6193794.JRBo1frAlU@positron.chronox.de> In-Reply-To: <11836144.hkEK2qVKZC@positron.chronox.de> References: <11836144.hkEK2qVKZC@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The LRNG sysctl interface provides the same controls as the existing /dev/random implementation. These sysctls behave identically and are implemented identically. The goal is to allow a possible merge of the existing /dev/random implementation with this implementation which implies that this patch tries have a very close similarity. Yet, all sysctls are documented at [1]. In addition, it provides the file lrng_type which provides details about the LRNG: - the name of the DRNG that produces the random numbers for /dev/random, /dev/urandom, getrandom(2) - the hash used to produce random numbers from the entropy pool - the number of secondary DRNG instances - indicator whether the LRNG operates SP800-90B compliant - indicator whether a high-resolution timer is identified - only with a high-resolution timer the interrupt noise source will deliver sufficient entropy - indicator whether the LRNG has been minimally seeded (i.e. is the secondary DRNG seeded with at least 128 bits of of entropy) - indicator whether the LRNG has been fully seeded (i.e. is the secondary DRNG seeded with at least 256 bits of entropy) [1] https://www.chronox.de/lrng.html 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üller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_interfaces.c | 1 - drivers/char/lrng/lrng_internal.h | 4 + drivers/char/lrng/lrng_proc.c | 163 ++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 drivers/char/lrng/lrng_proc.c diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index 0a32f22c2c1a..e69c176f0161 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -9,3 +9,4 @@ obj-y += lrng_pool.o lrng_aux.o \ lrng_interfaces.o \ obj-$(CONFIG_NUMA) += lrng_numa.o +obj-$(CONFIG_SYSCTL) += lrng_proc.o diff --git a/drivers/char/lrng/lrng_interfaces.c b/drivers/char/lrng/lrng_interfaces.c index 57e9a68e69bd..79a502517ccd 100644 --- a/drivers/char/lrng/lrng_interfaces.c +++ b/drivers/char/lrng/lrng_interfaces.c @@ -34,7 +34,6 @@ static DECLARE_WAIT_QUEUE_HEAD(lrng_write_wait); static DECLARE_WAIT_QUEUE_HEAD(lrng_init_wait); static struct fasync_struct *fasync; -struct ctl_table random_table[]; /********************************** Helper ***********************************/ /* Is the DRNG seed level too low? */ diff --git a/drivers/char/lrng/lrng_internal.h b/drivers/char/lrng/lrng_internal.h index ecb0a7ad5e7e..f65fc6647e8a 100644 --- a/drivers/char/lrng/lrng_internal.h +++ b/drivers/char/lrng/lrng_internal.h @@ -116,7 +116,11 @@ void lrng_cc20_init_state(struct chacha20_state *state); /********************************** /proc *************************************/ +#ifdef CONFIG_SYSCTL +void lrng_pool_inc_numa_node(void); +#else static inline void lrng_pool_inc_numa_node(void) { } +#endif /****************************** LRNG interfaces *******************************/ diff --git a/drivers/char/lrng/lrng_proc.c b/drivers/char/lrng/lrng_proc.c new file mode 100644 index 000000000000..f4ee01f61925 --- /dev/null +++ b/drivers/char/lrng/lrng_proc.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG proc and sysctl interfaces + * + * Copyright (C) 2016 - 2020, Stephan Mueller + */ + +#include +#include +#include +#include +#include + +#include "lrng_internal.h" + +/* + * This function is used to return both the bootid UUID, and random + * UUID. The difference is in whether table->data is NULL; if it is, + * then a new UUID is generated and returned to the user. + * + * If the user accesses this via the proc interface, the UUID will be + * returned as an ASCII string in the standard UUID format; if via the + * sysctl system call, as 16 bytes of binary data. + */ +static int lrng_proc_do_uuid(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table fake_table; + unsigned char buf[64], tmp_uuid[16], *uuid; + + uuid = table->data; + if (!uuid) { + uuid = tmp_uuid; + generate_random_uuid(uuid); + } else { + static DEFINE_SPINLOCK(bootid_spinlock); + + spin_lock(&bootid_spinlock); + if (!uuid[8]) + generate_random_uuid(uuid); + spin_unlock(&bootid_spinlock); + } + + sprintf(buf, "%pU", uuid); + + fake_table.data = buf; + fake_table.maxlen = sizeof(buf); + + return proc_dostring(&fake_table, write, buffer, lenp, ppos); +} + +static int lrng_proc_do_entropy(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table fake_table; + int entropy_count; + + entropy_count = lrng_avail_entropy(); + + fake_table.data = &entropy_count; + fake_table.maxlen = sizeof(entropy_count); + + return proc_dointvec(&fake_table, write, buffer, lenp, ppos); +} + +static int lrng_sysctl_poolsize = LRNG_POOL_SIZE_BITS; +static int lrng_min_write_thresh; +static int lrng_max_write_thresh = LRNG_POOL_SIZE_BITS; +static char lrng_sysctl_bootid[16]; +static int lrng_drng_reseed_max_min; + +struct ctl_table random_table[] = { + { + .procname = "poolsize", + .data = &lrng_sysctl_poolsize, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = proc_dointvec, + }, + { + .procname = "entropy_avail", + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = lrng_proc_do_entropy, + }, + { + .procname = "write_wakeup_threshold", + .data = &lrng_write_wakeup_bits, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &lrng_min_write_thresh, + .extra2 = &lrng_max_write_thresh, + }, + { + .procname = "boot_id", + .data = &lrng_sysctl_bootid, + .maxlen = 16, + .mode = 0444, + .proc_handler = lrng_proc_do_uuid, + }, + { + .procname = "uuid", + .maxlen = 16, + .mode = 0444, + .proc_handler = lrng_proc_do_uuid, + }, + { + .procname = "urandom_min_reseed_secs", + .data = &lrng_drng_reseed_max_time, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + .extra1 = &lrng_drng_reseed_max_min, + }, + { } +}; + +/* Number of online DRNGs */ +static u32 numa_drngs = 1; + +void lrng_pool_inc_numa_node(void) +{ + numa_drngs++; +} + +static int lrng_proc_type_show(struct seq_file *m, void *v) +{ + struct lrng_drng *lrng_drng_init = lrng_drng_init_instance(); + unsigned long flags = 0; + unsigned char buf[300]; + + lrng_drng_lock(lrng_drng_init, &flags); + snprintf(buf, sizeof(buf), + "DRNG name: %s\n" + "Hash for reading entropy pool: %s\n" + "DRNG security strength: %d bits\n" + "number of DRNG instances: %u\n" + "SP800-90B compliance: %s\n" + "High-resolution timer: %s\n" + "LRNG minimally seeded: %s\n" + "LRNG fully seeded: %s\n", + lrng_drng_init->crypto_cb->lrng_drng_name(), + lrng_drng_init->crypto_cb->lrng_hash_name(), + LRNG_DRNG_SECURITY_STRENGTH_BITS, numa_drngs, + lrng_sp80090b_compliant() ? "true" : "false", + lrng_pool_highres_timer() ? "true" : "false", + lrng_state_min_seeded() ? "true" : "false", + lrng_state_fully_seeded() ? "true" : "false"); + lrng_drng_unlock(lrng_drng_init, &flags); + + seq_write(m, buf, strlen(buf)); + + return 0; +} + +static int __init lrng_proc_type_init(void) +{ + proc_create_single("lrng_type", 0444, NULL, &lrng_proc_type_show); + return 0; +} + +module_init(lrng_proc_type_init); From patchwork Wed Apr 15 10:11:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 197867 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 311A8C2BA19 for ; Wed, 15 Apr 2020 10:36:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F2C0420784 for ; Wed, 15 Apr 2020 10:36:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="hKhjwFXJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2408775AbgDOKgg (ORCPT ); Wed, 15 Apr 2020 06:36:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58470 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2408664AbgDOKcI (ORCPT ); Wed, 15 Apr 2020 06:32:08 -0400 Received: from mo6-p04-ob.smtp.rzone.de (mo6-p04-ob.smtp.rzone.de [IPv6:2a01:238:20a:202:5304::7]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DF79CC061A41; Wed, 15 Apr 2020 03:32:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1586946726; 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=KhTFfcOaj7+qWGEevJKA0xLp9ZlvwHL5xiETOukUSWE=; b=hKhjwFXJM/SAJ8hb6sdveQRDGSSJzAOXeBL1d5d5SKwCAvCXM+6kVMI06XLySRKf+o LVhZiv0yteoJy96R9BOAgj91EN6jA2cjyFPunU/lCj0ICV+IlIhjElnMBLgTGr1dUOIj wa3fVOSOy2oS5Ff8H/+jEK70V2jKYviz8E/4ZJSKiePbwzG4/Mp9NBLlAcqN0TW51Y8B ZxePBT2gb5Bc2aRiqWS3Cv2i4WeVLWe4w7YFVyPec4H4qZ1d5pv2uD3g2vjVA8EeNnEK tXT2s7h6wxlvwENjCeWePhex+t1/F1PXCRv9xq+NLQDYPztNLNrejtMsixpcKRatOkB4 ls+Q== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPZIvSaiyU=" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.4.0 DYNA|AUTH) with ESMTPSA id 404ef0w3FAJt128 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 15 Apr 2020 12:19:55 +0200 (CEST) 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 , Randy Dunlap , Julia Lawall , Dan Carpenter Subject: [PATCH v30 04/12] LRNG - add switchable DRNG support Date: Wed, 15 Apr 2020 12:11:38 +0200 Message-ID: <6655942.8Xx1TYOAxx@positron.chronox.de> In-Reply-To: <11836144.hkEK2qVKZC@positron.chronox.de> References: <11836144.hkEK2qVKZC@positron.chronox.de> MIME-Version: 1.0 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üller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 7 ++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_switch.c | 182 ++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 drivers/char/lrng/lrng_switch.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index 56f13efd3592..cb701bb0b8b6 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -64,4 +64,11 @@ config LRNG_POOL_SIZE default 7 if LRNG_POOL_SIZE_65536 default 8 if LRNG_POOL_SIZE_131072 +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 e69c176f0161..31cfe87c999e 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..7101bda9d7aa --- /dev/null +++ b/drivers/char/lrng/lrng_switch.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG DRNG switching support + * + * Copyright (C) 2016 - 2020, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include + +#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; + 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; + 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(seed, sizeof(seed)); + 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); + } + + 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); + /* + * 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; + } + + 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); + + if (sl) + spin_unlock_irqrestore(&drng_store->spin_lock, flags); + 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); From patchwork Wed Apr 15 10:13:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 197865 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7DFB7C2BB55 for ; Wed, 15 Apr 2020 10:42:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 568B820737 for ; Wed, 15 Apr 2020 10:42:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="GIxKv/5i" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2393900AbgDOKmJ (ORCPT ); Wed, 15 Apr 2020 06:42:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57136 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S2896489AbgDOKXv (ORCPT ); Wed, 15 Apr 2020 06:23:51 -0400 Received: from mo6-p03-ob.smtp.rzone.de (mo6-p03-ob.smtp.rzone.de [IPv6:2a01:238:20a:202:5303::6]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1F1F7C03C1AB; Wed, 15 Apr 2020 03:22:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1586946176; 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=UsEDbLiAgf2IAri8d26iHU8c22m1vnVqWvSP369qGBo=; b=GIxKv/5i/9ho7vJ/xmygrtVIbDJWQ7HhWwCNGK5/c36FZpSMmeY5Wj7xfNvfTzBPIG HVN7c1CN4MJMFvfPWQqn9UsHcuQRCVLvYOYc3qNCq4a8j5BLsuKRNDgLSCQ2SAevtvv6 3q6t4hpHy2xXNMcZ7vVaWfmmohe49UoSWf3R/JS2Ndbjgejp82OKi09Rs2LEokvnxhZC cGrwXOyGnVucmQAaARE+ePoK+zSkX9Eae9/itn2OOaggIBBxtWHV1ieM7UZW40oC7RSn 40dVdCRRTOgzSOTMgTMiSPAOWtFSVDQsKofjDclBEVjaLSaWSxqpgZeP6UKM0HMfDl8q hFpA== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPZIvSaiyU=" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.4.0 DYNA|AUTH) with ESMTPSA id 404ef0w3FAJl122 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 15 Apr 2020 12:19:47 +0200 (CEST) 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 , Randy Dunlap , Julia Lawall , Dan Carpenter Subject: [PATCH v30 09/12] LRNG - add Jitter RNG fast noise source Date: Wed, 15 Apr 2020 12:13:57 +0200 Message-ID: <6523697.NaLa7ryNbq@positron.chronox.de> In-Reply-To: <11836144.hkEK2qVKZC@positron.chronox.de> References: <11836144.hkEK2qVKZC@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The Jitter RNG fast noise source implemented as part of the kernel crypto API is queried for 256 bits of entropy at the time the seed buffer managed by the LRNG is about to be filled. 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üller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 12 +++++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_jent.c | 88 +++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 drivers/char/lrng/lrng_jent.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index 7afc965a4d52..4684e838f011 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -94,4 +94,16 @@ config LRNG_KCAPI provided by the selected kernel crypto API RNG. endif # LRNG_DRNG_SWITCH +config LRNG_JENT + bool "Enable Jitter RNG as LRNG Seed Source" + depends on CRYPTO + select CRYPTO_JITTERENTROPY + help + The Linux RNG may use the Jitter RNG as noise source. Enabling + this option enables the use of the Jitter RNG. Its default + entropy level is 16 bits of entropy per 256 data bits delivered + by the Jitter RNG. This entropy level can be changed at boot + time or at runtime with the lrng_base.jitterrng configuration + variable. + endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index 94b2dfb2dfdb..4f5b6f38f0c4 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_SYSCTL) += lrng_proc.o obj-$(CONFIG_LRNG_DRNG_SWITCH) += lrng_switch.o obj-$(CONFIG_LRNG_DRBG) += lrng_drbg.o obj-$(CONFIG_LRNG_KCAPI) += lrng_kcapi.o +obj-$(CONFIG_LRNG_JENT) += lrng_jent.o diff --git a/drivers/char/lrng/lrng_jent.c b/drivers/char/lrng/lrng_jent.c new file mode 100644 index 000000000000..225505271fcb --- /dev/null +++ b/drivers/char/lrng/lrng_jent.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG Fast Noise Source: Jitter RNG + * + * Copyright (C) 2016 - 2020, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include "lrng_internal.h" + +/* + * Estimated entropy of data is a 16th of LRNG_DRNG_SECURITY_STRENGTH_BITS. + * Albeit a full entropy assessment is provided for the noise source indicating + * that it provides high entropy rates and considering that it deactivates + * when it detects insufficient hardware, the chosen under estimation of + * entropy is considered to be acceptable to all reviewers. + */ +static u32 jitterrng = LRNG_DRNG_SECURITY_STRENGTH_BITS>>4; +module_param(jitterrng, uint, 0644); +MODULE_PARM_DESC(jitterrng, "Entropy in bits of 256 data bits from Jitter RNG noise source"); + +/** + * lrng_get_jent() - Get Jitter RNG entropy + * + * @outbuf: buffer to store entropy + * @outbuflen: length of buffer + * + * Return: + * * > 0 on success where value provides the added entropy in bits + * * 0 if no fast source was available + */ +static struct rand_data *lrng_jent_state; + +u32 lrng_get_jent(u8 *outbuf, unsigned int outbuflen) +{ + int ret; + u32 ent_bits = jitterrng; + unsigned long flags; + static DEFINE_SPINLOCK(lrng_jent_lock); + static int lrng_jent_initialized = 0; + + spin_lock_irqsave(&lrng_jent_lock, flags); + + if (!ent_bits || (lrng_jent_initialized == -1)) { + spin_unlock_irqrestore(&lrng_jent_lock, flags); + return 0; + } + + if (!lrng_jent_initialized) { + lrng_jent_state = jent_lrng_entropy_collector(); + if (!lrng_jent_state) { + jitterrng = 0; + lrng_jent_initialized = -1; + spin_unlock_irqrestore(&lrng_jent_lock, flags); + pr_info("Jitter RNG unusable on current system\n"); + return 0; + } + lrng_jent_initialized = 1; + pr_debug("Jitter RNG working on current system\n"); + } + ret = jent_read_entropy(lrng_jent_state, outbuf, outbuflen); + spin_unlock_irqrestore(&lrng_jent_lock, flags); + + if (ret) { + pr_debug("Jitter RNG failed with %d\n", ret); + return 0; + } + + /* Obtain entropy statement */ + if (outbuflen != LRNG_DRNG_SECURITY_STRENGTH_BYTES) + ent_bits = (ent_bits * outbuflen<<3) / + LRNG_DRNG_SECURITY_STRENGTH_BITS; + /* Cap entropy to buffer size in bits */ + ent_bits = min_t(u32, ent_bits, outbuflen<<3); + pr_debug("obtained %u bits of entropy from Jitter RNG noise source\n", + ent_bits); + + return ent_bits; +} + +u32 lrng_jent_entropylevel(void) +{ + return min_t(u32, jitterrng, LRNG_DRNG_SECURITY_STRENGTH_BITS); +} From patchwork Wed Apr 15 10:14:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 197864 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8811C2BA19 for ; Wed, 15 Apr 2020 10:43:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 29DE420737 for ; Wed, 15 Apr 2020 10:43:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="GL2ETJs5" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2896480AbgDOKnV (ORCPT ); Wed, 15 Apr 2020 06:43:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57146 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S2896479AbgDOKXi (ORCPT ); Wed, 15 Apr 2020 06:23:38 -0400 Received: from mo6-p02-ob.smtp.rzone.de (mo6-p02-ob.smtp.rzone.de [IPv6:2a01:238:20a:202:5302::6]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A2745C03C1AA; Wed, 15 Apr 2020 03:22:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1586946170; 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=hwS+x/N5sydmJA2FCwk6A+EN+suF8ZGXBUS8yhutk64=; b=GL2ETJs5cI6/lzkYaFA383WdxmnDNqDkpAKRyfZNZAUNcpBW9sLCd2IypAIlfQLHVv NQlWkOhQfebDu5pvDOQDkb8O1mmn6RZs/a+iygQMQBdG9Li0sbdPw/YtuiC32UAC+sAp 5G5/PzcN8wVvEH8AukvoyJAg4B+PVKh0+dd9jHFoKhOAngK8OQIZKtcYUO1QRgKh7Mon ZOO+/2augkM39wCTOB6En8QghL9VJiIP1ke4SBvgwJSFD92Xx1sr12GzNDcuDm1VKb4i vePmFEFyIgzocxY5/kiQLrGTB3kH84/t/MVdABV6TsnA85g+c70nFaPb20flnRRIdov3 eOEQ== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPZIvSaiyU=" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.4.0 DYNA|AUTH) with ESMTPSA id 404ef0w3FAJj11z (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 15 Apr 2020 12:19:45 +0200 (CEST) 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 , Randy Dunlap , Julia Lawall , Dan Carpenter Subject: [PATCH v30 11/12] LRNG - add interface for gathering of raw entropy Date: Wed, 15 Apr 2020 12:14:49 +0200 Message-ID: <4946330.IVaNDfpqxB@positron.chronox.de> In-Reply-To: <11836144.hkEK2qVKZC@positron.chronox.de> References: <11836144.hkEK2qVKZC@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The test interface allows a privileged process to capture the raw unconditioned noise that is collected by the LRNG for statistical analysis. Such testing allows the analysis how much entropy the interrupt noise source provides on a given platform. Extracted noise data is not used to seed the LRNG. This is a test interface and not appropriate for production systems. Yet, the interface is considered to be sufficiently secured for production systems. Access to the data is given through the lrng_raw debugfs file. The data buffer should be multiples of sizeof(u32) to fill the entire buffer. Using the option lrng_testing.boot_test=1 the raw noise of the first 1000 entropy events since boot can be sampled. This test interface allows generating the data required for analysis whether the LRNG is in compliance with SP800-90B sections 3.1.3 and 3.1.4. 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: Roman Drahtmueller Tested-by: Roman Drahtmüller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 16 ++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_testing.c | 269 +++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+) create mode 100644 drivers/char/lrng/lrng_testing.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index 323c657f7005..014ee82df79a 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -162,4 +162,20 @@ config LRNG_APT_CUTOFF default 325 if !LRNG_APT_BROKEN default 32 if LRNG_APT_BROKEN +config LRNG_TESTING + bool "Enable entropy test interface to LRNG noise source" + depends on DEBUG_FS + help + The test interface allows a privileged process to capture + the raw unconditioned noise that is collected by the LRNG + for statistical analysis. Extracted noise data is not used + to seed the LRNG. + + The raw noise data can be obtained using the lrng_raw + debugfs file. Using the option lrng_testing.boot_test=1 + the raw noise of the first 1000 entropy events since boot + can be sampled. + + If unsure, say N. + endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index c3008763dd14..b2ce1979dc4b 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_LRNG_DRBG) += lrng_drbg.o obj-$(CONFIG_LRNG_KCAPI) += lrng_kcapi.o obj-$(CONFIG_LRNG_JENT) += lrng_jent.o obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o +obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o diff --git a/drivers/char/lrng/lrng_testing.c b/drivers/char/lrng/lrng_testing.c new file mode 100644 index 000000000000..996fc665a0a0 --- /dev/null +++ b/drivers/char/lrng/lrng_testing.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Linux Random Number Generator (LRNG) Raw entropy collection tool + * + * Copyright (C) 2019 - 2020, Stephan Mueller + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lrng_internal.h" + +#define LRNG_TESTING_RINGBUFFER_SIZE 1024 +#define LRNG_TESTING_RINGBUFFER_MASK (LRNG_TESTING_RINGBUFFER_SIZE - 1) + +static u32 lrng_testing_rb[LRNG_TESTING_RINGBUFFER_SIZE]; +static u32 lrng_rb_reader = 0; +static u32 lrng_rb_writer = 0; +static atomic_t lrng_testing_enabled = ATOMIC_INIT(0); + +static DECLARE_WAIT_QUEUE_HEAD(lrng_raw_read_wait); +static DEFINE_SPINLOCK(lrng_raw_lock); + +/* + * 0 ==> No boot test, gathering of runtime data allowed + * 1 ==> Boot test enabled and ready for collecting data, gathering runtime + * data is disabled + * 2 ==> Boot test completed and disabled, gathering of runtime data is + * disabled + */ +static u32 boot_test = 0; +module_param(boot_test, uint, 0644); +MODULE_PARM_DESC(boot_test, "Enable gathering boot time entropy of the first entropy events"); + +static inline void lrng_raw_entropy_reset(void) +{ + unsigned long flags; + + spin_lock_irqsave(&lrng_raw_lock, flags); + lrng_rb_reader = 0; + lrng_rb_writer = 0; + spin_unlock_irqrestore(&lrng_raw_lock, flags); +} + +static void lrng_raw_entropy_init(void) +{ + /* + * The boot time testing implies we have a running test. If the + * caller wants to clear it, he has to unset the boot_test flag + * at runtime via sysfs to enable regular runtime testing + */ + if (boot_test) + return; + + lrng_raw_entropy_reset(); + atomic_set(&lrng_testing_enabled, 1); + pr_warn("Enabling raw entropy collection\n"); +} + +static void lrng_raw_entropy_fini(void) +{ + if (boot_test) + return; + + atomic_set(&lrng_testing_enabled, 0); + lrng_raw_entropy_reset(); + pr_warn("Disabling raw entropy collection\n"); +} + +bool lrng_raw_entropy_store(u32 value) +{ + unsigned long flags; + + if (!atomic_read(&lrng_testing_enabled) && (boot_test != 1)) + return false; + + spin_lock_irqsave(&lrng_raw_lock, flags); + + /* + * Disable entropy testing for boot time testing after ring buffer + * is filled. + */ + if (boot_test) { + if (lrng_rb_writer > LRNG_TESTING_RINGBUFFER_SIZE) { + boot_test = 2; + pr_warn_once("Boot time entropy collection test disabled\n"); + spin_unlock_irqrestore(&lrng_raw_lock, flags); + return false; + } + + if (lrng_rb_writer == 1) + pr_warn("Boot time entropy collection test enabled\n"); + } + + lrng_testing_rb[lrng_rb_writer & LRNG_TESTING_RINGBUFFER_MASK] = value; + lrng_rb_writer++; + + spin_unlock_irqrestore(&lrng_raw_lock, flags); + + if (wq_has_sleeper(&lrng_raw_read_wait)) + wake_up_interruptible(&lrng_raw_read_wait); + + return true; +} + +static inline bool lrng_raw_have_data(void) +{ + return ((lrng_rb_writer & LRNG_TESTING_RINGBUFFER_MASK) != + (lrng_rb_reader & LRNG_TESTING_RINGBUFFER_MASK)); +} + +static int lrng_raw_entropy_reader(u8 *outbuf, u32 outbuflen) +{ + unsigned long flags; + int collected_data = 0; + + lrng_raw_entropy_init(); + + while (outbuflen) { + spin_lock_irqsave(&lrng_raw_lock, flags); + + /* We have no data or reached the writer. */ + if (!lrng_rb_writer || (lrng_rb_writer == lrng_rb_reader)) { + + spin_unlock_irqrestore(&lrng_raw_lock, flags); + + /* + * Now we gathered all boot data, enable regular data + * collection. + */ + if (boot_test) { + boot_test = 0; + goto out; + } + + wait_event_interruptible(lrng_raw_read_wait, + lrng_raw_have_data()); + if (signal_pending(current)) { + collected_data = -ERESTARTSYS; + goto out; + } + + continue; + } + + /* We copy out word-wise */ + if (outbuflen < sizeof(u32)) { + spin_unlock_irqrestore(&lrng_raw_lock, flags); + goto out; + } + + memcpy(outbuf, &lrng_testing_rb[lrng_rb_reader], sizeof(u32)); + lrng_rb_reader++; + + spin_unlock_irqrestore(&lrng_raw_lock, flags); + + outbuf += sizeof(u32); + outbuflen -= sizeof(u32); + collected_data += sizeof(u32); + } + +out: + lrng_raw_entropy_fini(); + return collected_data; +} + +/************************************************************************** + * Debugfs interface + **************************************************************************/ +static int lrng_raw_extract_user(char __user *buf, size_t nbytes) +{ + u8 *tmp, *tmp_aligned; + int ret = 0, large_request = (nbytes > 256); + + /* + * The intention of this interface is for collecting at least + * 1000 samples due to the SP800-90B requirements. So, we make no + * effort in avoiding allocating more memory that actually needed + * by the user. Hence, we allocate sufficient memory to always hold + * that amount of data. + */ + tmp = kmalloc(LRNG_TESTING_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + tmp_aligned = PTR_ALIGN(tmp, sizeof(u32)); + + while (nbytes) { + int i; + + if (large_request && need_resched()) { + if (signal_pending(current)) { + if (ret == 0) + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + i = min_t(int, nbytes, LRNG_TESTING_RINGBUFFER_SIZE); + i = lrng_raw_entropy_reader(tmp_aligned, i); + if (i <= 0) { + if (i < 0) + ret = i; + break; + } + if (copy_to_user(buf, tmp_aligned, i)) { + ret = -EFAULT; + break; + } + + nbytes -= i; + buf += i; + ret += i; + } + + kzfree(tmp); + return ret; +} + +/* DebugFS operations and definition of the debugfs files */ +static ssize_t lrng_raw_read(struct file *file, char __user *to, + size_t count, loff_t *ppos) +{ + loff_t pos = *ppos; + int ret; + + if (!count) + return 0; + + ret = lrng_raw_extract_user(to, count); + if (ret < 0) + return ret; + + count -= ret; + *ppos = pos + count; + + return ret; +} + +static const struct file_operations lrng_raw_name_fops = { + .owner = THIS_MODULE, + .read = lrng_raw_read, +}; + +static int __init lrng_raw_init(void) +{ + struct dentry *lrng_raw_debugfs_root; + + lrng_raw_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + debugfs_create_file_unsafe("lrng_raw", 0400, lrng_raw_debugfs_root, + NULL, &lrng_raw_name_fops); + + return 0; +} + +module_init(lrng_raw_init); From patchwork Wed Apr 15 10:15:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 197870 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E00A3C2BA19 for ; Wed, 15 Apr 2020 10:24:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 98F3620775 for ; Wed, 15 Apr 2020 10:24:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=chronox.de header.i=@chronox.de header.b="EYIh+scL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2408540AbgDOKYO (ORCPT ); Wed, 15 Apr 2020 06:24:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57144 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S2896478AbgDOKXi (ORCPT ); Wed, 15 Apr 2020 06:23:38 -0400 X-Greylist: delayed 100 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Wed, 15 Apr 2020 03:22:56 PDT Received: from mo6-p02-ob.smtp.rzone.de (mo6-p02-ob.smtp.rzone.de [IPv6:2a01:238:20a:202:5302::12]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A26E9C03C1A9; Wed, 15 Apr 2020 03:22:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1586946170; 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=uID27P7UBs+ac8lGMHFlPPg4bheYCYELqovkG8UTKT0=; b=EYIh+scLlnpJ09ZWALouew5D4IURHvqQlvJbX3t9y/ztQexAACl8Bc51C4iw8sBEZR XPqLnYMRYt85T/rBgUcMJ96CSkgF9OZC+CHekzB4+ZzXerugzxyWzTSFiJTlR7lGhmzG VK47LMy3OcTziuvPn51vC8x1MasLq9N9Pl7BMjHoDXxvovOpgVNYVBKknBPB6J9bWMdT RW14WrxBLdREE5kZQjIM34JAz6j/0eIAqC/53qTozbWwqhxFCjjPinpt39jogZw2Iv0c zheCzAtJ+oPFLk85+nEKN16xJCfJ9YYbDuklO5WnBs70a+B4GgR87W2PH0jPxvsUj6Oc 4QwA== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPZIvSaiyU=" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 46.4.0 DYNA|AUTH) with ESMTPSA id 404ef0w3FAJg11x (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Wed, 15 Apr 2020 12:19:42 +0200 (CEST) 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 , Randy Dunlap , Julia Lawall , Dan Carpenter Subject: [PATCH v30 12/12] LRNG - add power-on and runtime self-tests Date: Wed, 15 Apr 2020 12:15:14 +0200 Message-ID: <5750631.lOMUDkFQkn@positron.chronox.de> In-Reply-To: <11836144.hkEK2qVKZC@positron.chronox.de> References: <11836144.hkEK2qVKZC@positron.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Parts of the LRNG are already covered by self-tests, including: * Self-test of SP800-90A DRBG provided by the Linux kernel crypto API. * Self-test of the PRNG provided by the Linux kernel crypto API. * Raw noise source data testing including SP800-90B compliant tests when enabling CONFIG_LRNG_HEALTH_TESTS This patch adds the self-tests for the remaining critical functions of the LRNG that are essential to maintain entropy and provide cryptographic strong random numbers. The following self-tests are implemented: * Self-test of the time array maintenance. This test verifies whether the time stamp array management to store multiple values in one integer implements a concatenation of the data. * Self-test of the LFSR operation. This test injects a monotonic increasing counter into the LFSR. After completion of the injection of the counter, 3 pool words are compared with known good values. The known good values are calculated with the newly-developed tool lfsr_testvector_generation provided as part of the LRNG test tool set at [1]. * Self-test of the Hash_DF operation ensures that this function operates compliant to the specification. The self-test performs a Hash_DF operation of a zeroized entropy pool state. The test vectors are generated using the newly-developed tool hash_df_testvector_generation provided as part of the LRNG test tool set at [1]. * Self-test of the ChaCha20 DRNG is based on the self-tests that are already present and implemented with the stand-alone user space ChaCha20 DRNG implementation available at [2]. The self-tests cover different use cases of the DRNG seeded with known seed data. The status of the LRNG self-tests is provided with the selftest_status SysFS file. If the file contains a zero, the self-tests passed. The value 0xffffffff means that the self-tests were not executed. Any other value indicates a self-test failure. The self-test may be compiled to panic the system if the self-test fails. All self-tests operate on private state data structures. This implies that none of the self-tests have any impact on the regular LRNG operations. This allows the self-tests to be repeated at runtime by writing anything into the selftest_status SysFS file. [1] https://www.chronox.de/lrng.html [2] https://www.chronox.de/chacha20.html 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 CC: Marcelo Henrique Cerri CC: Neil Horman Signed-off-by: Stephan Mueller --- drivers/char/lrng/Kconfig | 25 ++ drivers/char/lrng/Makefile | 1 + drivers/char/lrng/lrng_selftest.c | 437 ++++++++++++++++++++++++++++++ 3 files changed, 463 insertions(+) create mode 100644 drivers/char/lrng/lrng_selftest.c diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index 014ee82df79a..896726138651 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -178,4 +178,29 @@ config LRNG_TESTING If unsure, say N. +config LRNG_SELFTEST + bool "Enable power-on and on-demand self-tests" + help + The power-on self-tests are executed during boot time + covering the ChaCha20 DRNG, the LFSR processing and the + time stamp management of the LRNG. + + The on-demand self-tests are triggered by writing any + value into the SysFS file selftest_status. At the same + time, when reading this file, the test status is + returned. A zero indicates that all tests were executed + successfully. + + If unsure, say Y. + +if LRNG_SELFTEST + +config LRNG_SELFTEST_PANIC + bool "Panic the kernel upon self-test failure" + help + If the option is enabled, the kernel is terminated if an + LRNG power-on self-test failure is detected. + +endif # LRNG_SELFTEST + endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index b2ce1979dc4b..92219c565f66 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_LRNG_KCAPI) += lrng_kcapi.o obj-$(CONFIG_LRNG_JENT) += lrng_jent.o obj-$(CONFIG_LRNG_HEALTH_TESTS) += lrng_health.o obj-$(CONFIG_LRNG_TESTING) += lrng_testing.o +obj-$(CONFIG_LRNG_SELFTEST) += lrng_selftest.o diff --git a/drivers/char/lrng/lrng_selftest.c b/drivers/char/lrng/lrng_selftest.c new file mode 100644 index 000000000000..5d83ab6d4d71 --- /dev/null +++ b/drivers/char/lrng/lrng_selftest.c @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * LRNG power-on and on-demand self-test + * + * Copyright (C) 2016 - 2020, Stephan Mueller + */ + +/* + * In addition to the self-tests below, the following LRNG components + * are covered with self-tests during regular operation: + * + * * power-on self-test: SP800-90A DRBG provided by the Linux kernel crypto API + * * power-on self-test: PRNG provided by the Linux kernel crypto API + * * runtime test: Raw noise source data testing including SP800-90B compliant + * tests when enabling CONFIG_LRNG_HEALTH_TESTS + * + * Additional developer tests present with LRNG code: + * * SP800-90B APT and RCT test enforcement validation when enabling + * CONFIG_LRNG_APT_BROKEN or CONFIG_LRNG_RCT_BROKEN. + * * Collection of raw entropy from the interrupt noise source when enabling + * CONFIG_LRNG_TESTING and pulling the data from the kernel with the provided + * interface. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +#include "lrng_chacha20.h" +#include "lrng_internal.h" +#include "lrng_lfsr.h" +#include "lrng_sw_noise.h" + +#define LRNG_SELFTEST_PASSED 0 +#define LRNG_SEFLTEST_ERROR_TIME (1 << 0) +#define LRNG_SEFLTEST_ERROR_LFSR (1 << 1) +#define LRNG_SEFLTEST_ERROR_CHACHA20 (1 << 2) +#define LRNG_SEFLTEST_ERROR_HASHDF (1 << 3) +#define LRNG_SELFTEST_NOT_EXECUTED 0xffffffff + +static u32 lrng_time_selftest[LRNG_TIME_ARRAY_SIZE]; + +static unsigned int lrng_selftest_status = LRNG_SELFTEST_NOT_EXECUTED; + +static inline void lrng_selftest_bswap32(u32 *ptr, u32 words) +{ + u32 i; + + /* Byte-swap data which is an LE representation */ + for (i = 0; i < words; i++) { + *ptr = cpu_to_le32(*ptr); + ptr++; + } +} + +static inline void lrng_time_process_selftest_insert(u32 time) +{ + static u32 lrng_time_selftest_ptr = 0; + u32 ptr = lrng_time_selftest_ptr++ & LRNG_TIME_WORD_MASK; + + lrng_time_selftest[lrng_time_idx2array(ptr)] |= + lrng_time_slot_val(time & LRNG_TIME_SLOTSIZE_MASK, + lrng_time_idx2slot(ptr)); +} + +static unsigned int lrng_time_process_selftest(void) +{ + u32 time; + u32 idx_zero_compare = (0 << 0) | (1 << 8) | (2 << 16) | (3 << 24); + u32 idx_one_compare = (4 << 0) | (5 << 8) | (6 << 16) | (7 << 24); + u32 idx_last_compare = ((LRNG_TIME_NUM_VALUES - 4) << 0) | + ((LRNG_TIME_NUM_VALUES - 3) << 8) | + ((LRNG_TIME_NUM_VALUES - 2) << 16) | + ((LRNG_TIME_NUM_VALUES - 1) << 24); + + (void)idx_one_compare; + + for (time = 0; time < LRNG_TIME_NUM_VALUES; time++) + lrng_time_process_selftest_insert(time); + + if ((lrng_time_selftest[0] != idx_zero_compare) || +#if (LRNG_TIME_ARRAY_SIZE > 1) + (lrng_time_selftest[1] != idx_one_compare) || +#endif + (lrng_time_selftest[LRNG_TIME_ARRAY_SIZE - 1] != idx_last_compare)) + { + pr_err("LRNG time array self-test FAILED\n"); + return LRNG_SEFLTEST_ERROR_TIME; + } + + return LRNG_SELFTEST_PASSED; +} + +/* + * The test vectors are generated with the lfsr_testvector_generation tool + * provided as part of the test tool set of the LRNG. + */ +static unsigned int lrng_pool_lfsr_selftest(void) +{ + /* + * First, 67th and last entry of entropy pool. + * + * The 67th entry is picked because this one is the first to receive + * an entry. As we start with 1 to inject into the LFSR, the + * 67th entry should be equal to rol(1, 7) >> 3 considering that + * all other values of the LFSR are zero and the the twist value of 0 + * is applied. + */ + static const u32 lrng_lfsr_selftest_result[][3] = { + { 0xf56df24a, 0x00000010, 0x0e014939 }, + { 0x4b130726, 0x00000010, 0x2802f509 }, + { 0x87279152, 0x00000010, 0x00150000 }, + { 0x0b67f997, 0x00000010, 0x00150000 }, + { 0x4fea174f, 0x00000010, 0xcbf4a6ae }, + { 0x77149108, 0x00000010, 0x77bfadf2 }, + { 0x1e96037e, 0x00000010, 0x18017e79 }, + { 0xc84acef2, 0x00000010, 0x6345f7a8 }, + { 0x6a2eb6df, 0x00000010, 0x03950000 }, + }; + struct lrng_pool *lrng_pool, *lrng_pool_aligned; + u32 i, ret = LRNG_SELFTEST_PASSED; + + BUILD_BUG_ON(ARRAY_SIZE(lrng_lfsr_selftest_result) < + CONFIG_LRNG_POOL_SIZE); + + lrng_pool = kzalloc(sizeof(struct lrng_pool) + LRNG_KCAPI_ALIGN, + GFP_KERNEL); + if (!lrng_pool) + return LRNG_SEFLTEST_ERROR_LFSR; + lrng_pool_aligned = PTR_ALIGN(lrng_pool, sizeof(u32)); + + for (i = 1; i <= LRNG_POOL_SIZE; i++) + _lrng_pool_lfsr_u32(lrng_pool_aligned, i); + + if ((atomic_read_u32(&lrng_pool_aligned->pool[0]) != + lrng_lfsr_selftest_result[CONFIG_LRNG_POOL_SIZE][0]) || + (atomic_read_u32(&lrng_pool_aligned->pool[67 & + (LRNG_POOL_SIZE - 1)]) != + lrng_lfsr_selftest_result[CONFIG_LRNG_POOL_SIZE][1]) || + (atomic_read_u32(&lrng_pool_aligned->pool[LRNG_POOL_SIZE - 1]) != + lrng_lfsr_selftest_result[CONFIG_LRNG_POOL_SIZE][2])) { + pr_err("LRNG LFSR self-test FAILED\n"); + ret = LRNG_SEFLTEST_ERROR_LFSR; + } + + kfree(lrng_pool); + return ret; +} + +/* + * The test vectors are generated with the hash_df_testvector_generation tool + * provided as part of the test tool set of the LRNG. + */ +static unsigned int lrng_hash_df_selftest(void) +{ + const struct lrng_crypto_cb *crypto_cb = &lrng_cc20_crypto_cb; + + /* + * The size of 44 bytes is chosen arbitrarily. Yet, this size should + * ensure that we have at least two hash blocks plus some fraction + * of a hash block generated. + */ + static const u8 lrng_hash_df_selftest_result[][44] = { + { + 0x65, 0x48, 0xc4, 0xb3, 0x4d, 0x9c, 0xec, 0xd7, + 0x69, 0x72, 0xf7, 0x8b, 0x35, 0x23, 0xa8, 0x9a, + 0xb2, 0xe8, 0x83, 0xf8, 0xba, 0x32, 0x76, 0xae, + 0xed, 0xe2, 0x94, 0x6a, 0x93, 0x99, 0x6e, 0xce, + 0xd5, 0xb5, 0xc5, 0x16, 0xa7, 0x8d, 0xc8, 0xd3, + 0xe9, 0xdd, 0x4f, 0xca, + }, { + 0x50, 0xcc, 0x6f, 0xe9, 0x40, 0x20, 0x40, 0x3e, + 0xce, 0x42, 0x3e, 0x30, 0x87, 0xf1, 0x3d, 0x60, + 0x75, 0xdd, 0x4f, 0x33, 0x06, 0x75, 0xbf, 0x5e, + 0x4c, 0x88, 0xc0, 0x60, 0x0f, 0x9d, 0xf9, 0xa5, + 0x63, 0xb1, 0xac, 0xc7, 0x32, 0x22, 0x60, 0xea, + 0x88, 0xe7, 0x61, 0x8b, + }, { + 0x09, 0x96, 0xbe, 0x89, 0x16, 0x5e, 0x41, 0x82, + 0xf3, 0xab, 0xf6, 0x11, 0xef, 0x45, 0x0e, 0x87, + 0x72, 0x38, 0x40, 0xe4, 0x21, 0x0b, 0x1c, 0x45, + 0x25, 0x9c, 0x26, 0x34, 0x7e, 0xad, 0x25, 0x33, + 0xf2, 0xb0, 0xc5, 0xa7, 0x0b, 0x38, 0xd9, 0x89, + 0x02, 0x08, 0xa2, 0x5b, + }, { + 0x10, 0x5b, 0xf4, 0x5b, 0xa9, 0xfc, 0x83, 0x2d, + 0x82, 0xf8, 0xa1, 0x17, 0x34, 0xe2, 0x67, 0xb7, + 0x95, 0xe2, 0x63, 0x2d, 0x1b, 0xf6, 0x59, 0x05, + 0x49, 0x9a, 0x3f, 0xa1, 0x16, 0xf7, 0x42, 0xd1, + 0x9c, 0x29, 0x5e, 0x31, 0xc9, 0x42, 0xf8, 0x9d, + 0x9b, 0x35, 0xd2, 0x30, + }, { + 0x1e, 0x43, 0xfe, 0x8a, 0x66, 0x53, 0x2d, 0x94, + 0x68, 0xbe, 0xfc, 0xc6, 0xfa, 0x95, 0x4a, 0xca, + 0xa7, 0x54, 0xcd, 0x92, 0xc9, 0xca, 0xcc, 0x4f, + 0xb2, 0xc5, 0xc5, 0xb6, 0x17, 0xd7, 0xb5, 0x41, + 0xa0, 0x8e, 0xef, 0x75, 0x00, 0x96, 0x8e, 0x13, + 0x8c, 0x9f, 0xd6, 0xce, + }, { + 0x70, 0x14, 0x94, 0x45, 0xa3, 0xb6, 0xac, 0xef, + 0x22, 0xe3, 0xe4, 0x2a, 0x38, 0x8c, 0x0e, 0x45, + 0x17, 0x61, 0x4e, 0x1d, 0xb3, 0xaf, 0xc1, 0xee, + 0x60, 0x31, 0x4d, 0xdc, 0xe1, 0x83, 0x8b, 0x85, + 0x97, 0x27, 0x30, 0x24, 0x57, 0xc2, 0xfd, 0xc0, + 0x99, 0x4b, 0xad, 0xb1, + }, { + 0x12, 0x87, 0x51, 0x68, 0x28, 0xab, 0xa9, 0xd1, + 0x91, 0x64, 0x5e, 0x38, 0x7f, 0xf3, 0xaf, 0xd5, + 0x93, 0xbc, 0x31, 0xfd, 0xae, 0x19, 0x45, 0xd7, + 0x1f, 0xe8, 0x0c, 0x24, 0xa6, 0x6d, 0x09, 0x0b, + 0x17, 0x44, 0xdb, 0xce, 0x1c, 0x0a, 0xdb, 0x73, + 0x7a, 0x91, 0x33, 0x4c, + }, { + 0x14, 0x81, 0x76, 0x37, 0x27, 0x19, 0x8d, 0x71, + 0xcc, 0x2e, 0xa3, 0x71, 0x92, 0x46, 0x6e, 0x3a, + 0xac, 0x87, 0xd6, 0x1e, 0xa7, 0xa9, 0x2e, 0x1e, + 0xd9, 0x6c, 0xea, 0xbe, 0x1a, 0x2e, 0xe9, 0x8a, + 0x96, 0x2a, 0xe3, 0xee, 0xd2, 0x25, 0xb2, 0xae, + 0xc6, 0xba, 0xe7, 0xef, + }, { + 0x58, 0x78, 0xce, 0xcb, 0xcf, 0x61, 0xc2, 0x3d, + 0x00, 0x80, 0x74, 0x57, 0x56, 0x44, 0xc7, 0xe2, + 0x9a, 0xed, 0x30, 0x02, 0x3f, 0x9a, 0xf5, 0xcc, + 0xf7, 0x7b, 0x40, 0xf7, 0x10, 0x97, 0x8d, 0x8f, + 0x58, 0xa4, 0x80, 0x88, 0x87, 0x30, 0x87, 0x7b, + 0xac, 0x2e, 0xce, 0x0d, + } + }; + struct lrng_pool *lrng_pool, *lrng_pool_aligned; + u8 hash_df[sizeof(lrng_hash_df_selftest_result[0])] + __aligned(sizeof(u32)); + u32 generated; + int ret = 0; + + BUILD_BUG_ON(ARRAY_SIZE(lrng_hash_df_selftest_result) < + CONFIG_LRNG_POOL_SIZE); + /* Calculated data needs to be byte-swapped */ + BUILD_BUG_ON(sizeof(lrng_hash_df_selftest_result[0]) % sizeof(32)); + + lrng_pool = kzalloc(sizeof(struct lrng_pool) + LRNG_KCAPI_ALIGN, + GFP_KERNEL); + if (!lrng_pool) + return LRNG_SEFLTEST_ERROR_HASHDF; + lrng_pool_aligned = PTR_ALIGN(lrng_pool, sizeof(u32)); + + generated = __lrng_pool_hash_df(crypto_cb, NULL, lrng_pool_aligned, + hash_df, sizeof(hash_df) << 3); + + lrng_selftest_bswap32((u32 *)hash_df, + sizeof(lrng_hash_df_selftest_result[0]) / sizeof(u32)); + + if ((generated >> 3) != sizeof(hash_df) || + memcmp(hash_df, lrng_hash_df_selftest_result[CONFIG_LRNG_POOL_SIZE], + sizeof(hash_df))) { + pr_err("LRNG Hash DF self-test FAILED\n"); + ret = LRNG_SEFLTEST_ERROR_HASHDF; + } + + kfree(lrng_pool); + return ret; +} + +/* + * The test vectors were generated using the ChaCha20 DRNG from + * https://www.chronox.de/chacha20.html + */ +static unsigned int lrng_chacha20_drng_selftest(void) +{ + const struct lrng_crypto_cb *crypto_cb = &lrng_cc20_crypto_cb; + u8 seed[CHACHA_KEY_SIZE * 2] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }; + struct chacha20_block chacha20; + int ret; + u8 outbuf[CHACHA_KEY_SIZE * 2] __aligned(sizeof(u32)); + + /* + * Expected result when ChaCha20 DRNG state is zero: + * * constants are set to "expand 32-byte k" + * * remaining state is 0 + * and pulling one half ChaCha20 DRNG block. + */ + static const u8 expected_halfblock[CHACHA_KEY_SIZE] = { + 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, + 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, + 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, + 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7 }; + + /* + * Expected result when ChaCha20 DRNG state is zero: + * * constants are set to "expand 32-byte k" + * * remaining state is 0 + * followed by a reseed with two keyblocks + * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + * 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + * 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + * 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + * 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + * 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + * 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f + * and pulling one ChaCha20 DRNG block. + */ + static const u8 expected_oneblock[CHACHA_KEY_SIZE * 2] = { + 0xf5, 0xb4, 0xb6, 0x5a, 0xec, 0xcd, 0x5a, 0x65, + 0x87, 0x56, 0xe3, 0x86, 0x51, 0x54, 0xfc, 0x90, + 0x56, 0xff, 0x5e, 0xae, 0x58, 0xf2, 0x01, 0x88, + 0xb1, 0x7e, 0xb8, 0x2e, 0x17, 0x9a, 0x27, 0xe6, + 0x86, 0xb3, 0xed, 0x33, 0xf7, 0xb9, 0x06, 0x05, + 0x8a, 0x2d, 0x1a, 0x93, 0xc9, 0x0b, 0x80, 0x04, + 0x03, 0xaa, 0x60, 0xaf, 0xd5, 0x36, 0x40, 0x11, + 0x67, 0x89, 0xb1, 0x66, 0xd5, 0x88, 0x62, 0x6d }; + + /* + * Expected result when ChaCha20 DRNG state is zero: + * * constants are set to "expand 32-byte k" + * * remaining state is 0 + * followed by a reseed with one key block plus one byte + * 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + * 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + * 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + * 0x20 + * and pulling less than one ChaCha20 DRNG block. + */ + static const u8 expected_block_nonalinged[CHACHA_KEY_SIZE + 4] = { + 0x9d, 0xdd, 0x4f, 0xbe, 0x97, 0xcd, 0x8e, 0x15, + 0xb3, 0xc4, 0x1a, 0x17, 0x49, 0x29, 0x32, 0x7c, + 0xb3, 0x84, 0xa4, 0x9b, 0xa7, 0x14, 0xb3, 0xc1, + 0x5b, 0x3b, 0xfb, 0xa1, 0xe4, 0x23, 0x42, 0x8e, + 0x08, 0x1f, 0x53, 0xa2 }; + + BUILD_BUG_ON(sizeof(seed) % sizeof(u32)); + + memset(&chacha20, 0, sizeof(chacha20)); + lrng_cc20_init_rfc7539(&chacha20); + lrng_selftest_bswap32((u32 *)seed, sizeof(seed) / sizeof(u32)); + + /* Generate with zero state */ + ret = crypto_cb->lrng_drng_generate_helper(&chacha20, outbuf, + sizeof(expected_halfblock)); + if (ret != sizeof(expected_halfblock)) + goto err; + if (memcmp(outbuf, expected_halfblock, sizeof(expected_halfblock))) + goto err; + + /* Clear state of DRNG */ + memset(&chacha20.key.u[0], 0, 48); + + /* Reseed with 2 key blocks */ + ret = crypto_cb->lrng_drng_seed_helper(&chacha20, seed, + sizeof(expected_oneblock)); + if (ret < 0) + goto err; + ret = crypto_cb->lrng_drng_generate_helper(&chacha20, outbuf, + sizeof(expected_oneblock)); + if (ret != sizeof(expected_oneblock)) + goto err; + if (memcmp(outbuf, expected_oneblock, sizeof(expected_oneblock))) + goto err; + + /* Clear state of DRNG */ + memset(&chacha20.key.u[0], 0, 48); + + /* Reseed with 1 key block and one byte */ + ret = crypto_cb->lrng_drng_seed_helper(&chacha20, seed, + sizeof(expected_block_nonalinged)); + if (ret < 0) + goto err; + ret = crypto_cb->lrng_drng_generate_helper(&chacha20, outbuf, + sizeof(expected_block_nonalinged)); + if (ret != sizeof(expected_block_nonalinged)) + goto err; + if (memcmp(outbuf, expected_block_nonalinged, + sizeof(expected_block_nonalinged))) + goto err; + + return LRNG_SELFTEST_PASSED; + +err: + pr_err("LRNG ChaCha20 DRNG self-test FAILED\n"); + return LRNG_SEFLTEST_ERROR_CHACHA20; +} + +static int lrng_selftest(void) +{ + unsigned int ret = lrng_time_process_selftest(); + + ret |= lrng_pool_lfsr_selftest(); + ret |= lrng_chacha20_drng_selftest(); + ret |= lrng_hash_df_selftest(); + + if (ret) { + if (IS_ENABLED(CONFIG_LRNG_SELFTEST_PANIC)) + panic("LRNG self-tests failed: %u\n", ret); + } else { + pr_info("LRNG self-tests passed\n"); + } + + lrng_selftest_status = ret; + + if (lrng_selftest_status) + return -EFAULT; + return 0; +} + +#ifdef CONFIG_SYSFS +/* Re-perform self-test when any value is written to the sysfs file. */ +static int lrng_selftest_sysfs_set(const char *val, + const struct kernel_param *kp) +{ + return lrng_selftest(); +} + +static const struct kernel_param_ops lrng_selftest_sysfs = { + .set = lrng_selftest_sysfs_set, + .get = param_get_uint, +}; +module_param_cb(selftest_status, &lrng_selftest_sysfs, &lrng_selftest_status, + 0644); +#endif /* CONFIG_SYSFS */ + +static int __init lrng_selftest_init(void) +{ + return lrng_selftest(); +} + +module_init(lrng_selftest_init);