Received: by 2002:a25:7ec1:0:0:0:0:0 with SMTP id z184csp987280ybc; Sat, 23 Nov 2019 12:41:52 -0800 (PST) X-Google-Smtp-Source: APXvYqy6NpC339b2s5efLlHRC2iE8jHP52Uu35EUF/YHTAf4Wj4UZUw9Xw6Oktqrta2+bsOqJBIB X-Received: by 2002:a17:906:12d3:: with SMTP id l19mr27636780ejb.165.1574541712071; Sat, 23 Nov 2019 12:41:52 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1574541712; cv=none; d=google.com; s=arc-20160816; b=E3ou9yX+eubOdWEFQuwMEyeu7ohcFkoqoSJoEG6E7iUrVJ+Xahrfng8nTndbb5ssKW evj/60fBcAKUOPNEwxlaO7Jog1SDdF9wiECmIM6vK7hUFlfnopJoeSn/lx1AyGaFJKhU KlY7mGuFvUSQPK4AvyoRx1uKIBf0T3dC2QuS+6U1VSGYJijW5blDCmw7Hmsu3vGs0hZ/ Cs8xybtRu8WqQFN6U1B1gPzEB8tqFI46rGeGUFq1Bb55MsfwoxszgMmqa3o2JTyGCXdl BlWN1x3ly23B9N9sHI46HdmwJw8P5vbAqXQc4cEo7bQO0rrqqL7TKXgkEi2X8tvk63xn Nkyw== 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=hNEjiDimYRZ64sBt17mfpqbaaOALcpilHA9DMXjGvYQ=; b=rMCo8zzs/Uq78iChsrRvP8g0W05IvTiaJaQSCipB8/JXJm0zUHMq1OMHHAhDHxZVvn JAqSABrdWfI+kaylo29tzZlLj0AiE68JOeDWJijWMoVXwaGio+8us2VAiekMVGJ2zmyc RSM0I3IhSrDxiMD3u1KucTSb/fudg7s14RoDwXTJWVAX5hEatJbXZWN5XXnKWS6iQNFz MZOdLtEqJKeBR+VsTVaRgbEH9mJJ01Q3vTO/+W7Dvbyh4MVCKmbuQyZdb3l6eFs0M/PE q78cmNJcAKeoiEhTpweZgXXNZbIsKVGchxVGko5KX4UVy6WNXf5BHuJVIr0iDe9z9E/k Rblg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@chronox.de header.s=strato-dkim-0002 header.b=JCp+przu; 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 s21si1376601eju.82.2019.11.23.12.41.26; Sat, 23 Nov 2019 12:41:52 -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=JCp+przu; 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 S1727370AbfKWUk3 (ORCPT + 99 others); Sat, 23 Nov 2019 15:40:29 -0500 Received: from mo4-p02-ob.smtp.rzone.de ([85.215.255.80]:28284 "EHLO mo4-p02-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727149AbfKWUjx (ORCPT ); Sat, 23 Nov 2019 15:39:53 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1574541587; 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=hNEjiDimYRZ64sBt17mfpqbaaOALcpilHA9DMXjGvYQ=; b=JCp+przupe+8EEfBgqrELNij72Y2RGpKaZg2ztg3P/hoNvCnptvtiKgr7cNkAx3lyN 7VzsFCI6WWeK7G0XjeuL4U1P4GEpoxg/xbO825Fi/mSvP4YLUYxUTN0E7f8Q/z3s5Jkl sPa8EsUPFQhUhVQ+Bp++Ri0qnEkPYzEgkcD3RA4Ymqnqm6zdG1n8OxintyDt/eff39fa K5xN464KWdToDBwaYXQbgjaVwIqJPlBnSKpaKzBwxWftBAogJO9g7VhvRYgsV7qhqolN h2wd0w3janyngeNnJMxRlOKEsOnL4alhzR5jifK+NhThxcZxy1uAwI8x8c+/YtYzbPcQ KhSg== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzHHXDaJfSfWrhX" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 44.29.0 DYNA|AUTH) with ESMTPSA id N09a57vANKcR3yP (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); Sat, 23 Nov 2019 21:38:27 +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 , Randy Dunlap Subject: [PATCH v26 12/12] LRNG - add interface for gathering of raw entropy Date: Sat, 23 Nov 2019 21:35:23 +0100 Message-ID: <3742813.K7GG538zxB@positron.chronox.de> In-Reply-To: <2722222.P16TYeLAVu@positron.chronox.de> References: <6157374.ptSnyUpaCn@positron.chronox.de> <2787174.DQlWHN5GGo@positron.chronox.de> <2722222.P16TYeLAVu@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 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=3D1 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=FCller Tested-by: Marcelo Henrique Cerri Tested-by: Neil Horman Signed-off-by: Stephan Mueller =2D-- 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 e6ca3acc1e48..9335761cb2ba 100644 =2D-- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -169,4 +169,20 @@ config LRNG_APT_CUTOFF default 325 if !LRNG_APT_BROKEN default 32 if LRNG_APT_BROKEN =20 +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=3D1 + 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 0713e9c0aa6e..c0b6cc4301fe 100644 =2D-- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_LRNG_KCAPI) +=3D lrng_kcapi.o obj-$(CONFIG_LRNG_JENT) +=3D lrng_jent.o obj-$(CONFIG_LRNG_TRNG_SUPPORT) +=3D lrng_trng.o obj-$(CONFIG_LRNG_HEALTH_TESTS) +=3D lrng_health.o +obj-$(CONFIG_LRNG_TESTING) +=3D lrng_testing.o diff --git a/drivers/char/lrng/lrng_testing.c b/drivers/char/lrng/lrng_test= ing.c new file mode 100644 index 000000000000..718a24660773 =2D-- /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, 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 =3D 0; +static u32 lrng_rb_writer =3D 0; +static atomic_t lrng_testing_enabled =3D ATOMIC_INIT(0); + +static DECLARE_WAIT_QUEUE_HEAD(lrng_raw_read_wait); +static DEFINE_SPINLOCK(lrng_raw_lock); + +/* + * 0 =3D=3D> No boot test, gathering of runtime data allowed + * 1 =3D=3D> Boot test enabled and ready for collecting data, gathering ru= ntime + * data is disabled + * 2 =3D=3D> Boot test completed and disabled, gathering of runtime data is + * disabled + */ +static u32 boot_test =3D 0; +module_param(boot_test, uint, 0644); +MODULE_PARM_DESC(boot_test, "Enable gathering boot time entropy of the fir= st" + " entropy events"); + +static inline void lrng_raw_entropy_reset(void) +{ + unsigned long flags; + + spin_lock_irqsave(&lrng_raw_lock, flags); + lrng_rb_reader =3D 0; + lrng_rb_writer =3D 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 !=3D 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 =3D 2; + pr_warn_once("Boot time entropy collection test " + "disabled\n"); + spin_unlock_irqrestore(&lrng_raw_lock, flags); + return false; + } + + if (lrng_rb_writer =3D=3D 1) + pr_warn("Boot time entropy collection test enabled\n"); + } + + lrng_testing_rb[lrng_rb_writer & LRNG_TESTING_RINGBUFFER_MASK] =3D 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) !=3D + (lrng_rb_reader & LRNG_TESTING_RINGBUFFER_MASK)); +} + +static int lrng_raw_entropy_reader(u8 *outbuf, u32 outbuflen) +{ + unsigned long flags; + int collected_data =3D 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 =3D=3D 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 =3D 0; + goto out; + } + + wait_event_interruptible(lrng_raw_read_wait, + lrng_raw_have_data()); + if (signal_pending(current)) { + collected_data =3D -ERESTARTSYS; + goto out; + } + + continue; + } + + /* We copy out word-wise */ + if (outbuflen < sizeof(u32)) + goto out; + + memcpy(outbuf, &lrng_testing_rb[lrng_rb_reader], sizeof(u32)); + lrng_rb_reader++; + + spin_unlock_irqrestore(&lrng_raw_lock, flags); + + outbuf +=3D sizeof(u32); + outbuflen -=3D sizeof(u32); + collected_data +=3D 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 =3D 0, large_request =3D (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 =3D kmalloc(LRNG_TESTING_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + tmp_aligned =3D PTR_ALIGN(tmp, sizeof(u32)); + + while (nbytes) { + int i; + + if (large_request && need_resched()) { + if (signal_pending(current)) { + if (ret =3D=3D 0) + ret =3D -ERESTARTSYS; + break; + } + schedule(); + } + + i =3D min_t(int, nbytes, LRNG_TESTING_RINGBUFFER_SIZE); + i =3D lrng_raw_entropy_reader(tmp_aligned, i); + if (i <=3D 0) { + if (i < 0) + ret =3D i; + break; + } + if (copy_to_user(buf, tmp_aligned, i)) { + ret =3D -EFAULT; + break; + } + + nbytes -=3D i; + buf +=3D i; + ret +=3D 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 =3D *ppos; + int ret; + + if (!count) + return 0; + + ret =3D lrng_raw_extract_user(to, count); + if (ret < 0) + return ret; + + count -=3D ret; + *ppos =3D pos + count; + + return ret; +} + +static struct file_operations lrng_raw_name_fops =3D { + .owner =3D THIS_MODULE, + .read =3D lrng_raw_read, +}; + +static int __init lrng_raw_init(void) +{ + struct dentry *lrng_raw_debugfs_root; + + lrng_raw_debugfs_root =3D 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); =2D-=20 2.23.0