Received: by 2002:a25:7ec1:0:0:0:0:0 with SMTP id z184csp800886ybc; Sat, 16 Nov 2019 08:57:04 -0800 (PST) X-Google-Smtp-Source: APXvYqwSu6t7F4OtWP4aNiOpfn3mSAX0orOHYWAk/ZDSEg3O3Cf9z6Oa9OtDQWdOf/bFN8eGNVUG X-Received: by 2002:a17:906:4e94:: with SMTP id v20mr11513051eju.34.1573923424291; Sat, 16 Nov 2019 08:57:04 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1573923424; cv=none; d=google.com; s=arc-20160816; b=OclPYGNI6DnasJ/tqtNHZ3n+qGt/bMZtBtdFfwD8ZDBjBTPZ9qCJidk7oRLbShR3q9 q2YkVMzg5ddGuHD2IDXvnCOZnhnduR/XX3LD3l3XdfeEN9a914/1eIcPfFmMWGY4WY7g lJ0Do/TBeYFoeTGvMkqGCVqcJ5oPG7+1tHOC5MXMU9lquduv+0rbsKSca6mtOzP/tsf1 HXrsQ/zwW8krj1aG7+yi5l5UckMJ7V8Ski//wg6vjG+iz92CtUiNJhLackWYiKuS5LvP 39rAKsWJqU0oAg96Lq7FMIYHvym3LtxlvaY8nq8AvnC5/lv1i6sTj3aC4qm88Q+L1ljS sdGQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:to:in-reply-to:cc:references:message-id :date:subject:mime-version:from:content-transfer-encoding :dkim-signature; bh=K9dzo1Lpl/E8eQcOkXHQEfmmSekoCsu3mvK4T8VA6ms=; b=lQLLmW1gazs8oN0OmdJ2AH0lRpd1uatUMWhRgeK1a2FWmUrAs000KI5QxmkGVuvMnU 7u5wp14H6gGyv0pClqr2l4Nwc0TYn6yXydrwsAVV8qkBkcahmdza3fXUrFNcWyQjP8BM kDflyWYMvPM/yQXTcqdeqgkIhHnEdUn7Q9zrCvJL9iPPv6CfETL94bL/F/pb2fjUwlVU qeg5z6LnfSHpbmA5G1ahKB2LfvOxDAqGZBhmKhFeGViPeteEzavhmbDtfdCUqvfPdX1z 3iSMrlWtEXYCOHA48CnictSNMEZOkeoptcU4mrkrE1tdIKUP+hjOrDVYcCCI/9v62SaX J3rQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@amacapital-net.20150623.gappssmtp.com header.s=20150623 header.b=xDDrhd9i; 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 p13si8169242eju.398.2019.11.16.08.56.35; Sat, 16 Nov 2019 08:57:04 -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=pass header.i=@amacapital-net.20150623.gappssmtp.com header.s=20150623 header.b=xDDrhd9i; 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 S1727854AbfKPQv1 (ORCPT + 99 others); Sat, 16 Nov 2019 11:51:27 -0500 Received: from mail-pg1-f195.google.com ([209.85.215.195]:40757 "EHLO mail-pg1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727606AbfKPQv1 (ORCPT ); Sat, 16 Nov 2019 11:51:27 -0500 Received: by mail-pg1-f195.google.com with SMTP id e17so67507pgd.7 for ; Sat, 16 Nov 2019 08:51:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amacapital-net.20150623.gappssmtp.com; s=20150623; h=content-transfer-encoding:from:mime-version:subject:date:message-id :references:cc:in-reply-to:to; bh=K9dzo1Lpl/E8eQcOkXHQEfmmSekoCsu3mvK4T8VA6ms=; b=xDDrhd9i3eXCIiOH+UeBc69E1x6O7SGIiFaTPPLESKjLU0oHdgKQ94YJ+kT8wGoMXN Utdc9qKlJAAgohJFN5oLJ2u199xvO3OLZwC+EMK0WTdDpBuIuPi63NM5wn/tra14vpB9 yrMyb/pk/JYyDv4QMdqXsH+MSYIrrRP8AsUA+T8uthmlZPf3spg6kVxJXQZ4JR2zUSvF qZjIWAPilJ3R9C+7/FDMB0iW6ktBs5K6mCMEJHKtPRGuFP+RcoY1QfouxPfJmWIKxDSA XqiP42hO7w14RTPtCwY9JIsLaDBhlb/FH1Arov8LKYqGjZYNn9lzy2wlBW0gtDAXwldV AtGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:content-transfer-encoding:from:mime-version :subject:date:message-id:references:cc:in-reply-to:to; bh=K9dzo1Lpl/E8eQcOkXHQEfmmSekoCsu3mvK4T8VA6ms=; b=jYM51X5BnG3ZyEaESRPczrcjDBr7Isu/hYv9nBAiyzNKAQQmqfPh+Bg6zYufgb9G2v XUeSiIbE+CQPsWYp3YHS3NVCD6ob/l2ctbzPBd+SFNQmZyv9Z2fpUWq/0RCnaTMZxxuI vf1Qad6ZrCsfSG6JHYp/oye5+SQ13XcIy5uMZvCzyB9ZNIb1RImEcNz2rq2wgLLSIlbR 5vbpKiGvSwo92fIhqP+FlWFcJ87SG9uLVqUGsJseRVRl28aBLCu8higKiwkptda1AUvQ /IfJN+Xk34BBTaTlG2JiPuZngOn6V0n1Z6WELvOC56wiXSym9pk2eMHXU9ASCwf4W2It vyhw== X-Gm-Message-State: APjAAAX5DIfw7l+e2p4gQNuy0OeEYMOCaS2ZhZIrIRu52+xSb0ivPukD F9XFt3gNOTu7Dw7W4ymYVSZcrg== X-Received: by 2002:a63:77c3:: with SMTP id s186mr23095280pgc.370.1573923086271; Sat, 16 Nov 2019 08:51:26 -0800 (PST) Received: from ?IPv6:2600:1010:b01b:e50d:6d7c:21:d243:910c? ([2600:1010:b01b:e50d:6d7c:21:d243:910c]) by smtp.gmail.com with ESMTPSA id d139sm18147514pfd.162.2019.11.16.08.51.25 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 16 Nov 2019 08:51:25 -0800 (PST) Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable From: Andy Lutomirski Mime-Version: 1.0 (1.0) Subject: Re: [PATCH v25 12/12] LRNG - add interface for gathering of raw entropy Date: Sat, 16 Nov 2019 08:51:24 -0800 Message-Id: <6950B235-6231-4DFF-A375-54A70C548B2E@amacapital.net> References: <3610406.x8mDjznOIz@positron.chronox.de> Cc: Arnd Bergmann , 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 In-Reply-To: <3610406.x8mDjznOIz@positron.chronox.de> To: =?utf-8?Q?Stephan_M=C3=BCller?= X-Mailer: iPhone Mail (17A878) Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org > On Nov 16, 2019, at 1:40 AM, Stephan M=C3=BCller wro= te: >=20 > =EF=BB=BFThe 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. This > is a test interface and not appropriate for production systems. > Yet, the interface is considered to be sufficiently secured for > production systems. >=20 > 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. >=20 > 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. >=20 > 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=C3=BCller > 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 | 324 +++++++++++++++++++++++++++++++ > 3 files changed, 341 insertions(+) > create mode 100644 drivers/char/lrng/lrng_testing.c >=20 > diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig > index e6ca3acc1e48..4ccc710832ef 100644 > --- 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" > + select CONFIG_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 > --- 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_tes= ting.c > new file mode 100644 > index 000000000000..5c33d3bd2172 > --- /dev/null > +++ b/drivers/char/lrng/lrng_testing.c > @@ -0,0 +1,324 @@ > +// 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 atomic_t lrng_rb_reader =3D ATOMIC_INIT(0); > +static atomic_t lrng_rb_writer =3D ATOMIC_INIT(0); > +static atomic_t lrng_rb_first_in =3D ATOMIC_INIT(0); > +static atomic_t lrng_testing_enabled =3D ATOMIC_INIT(0); > + > +static DECLARE_WAIT_QUEUE_HEAD(lrng_raw_read_wait); > + > +static u32 boot_test =3D 0; > +module_param(boot_test, uint, 0644); > +MODULE_PARM_DESC(boot_test, "Enable gathering boot time entropy of the fi= rst" > + " entropy events"); > + > +static inline void lrng_raw_entropy_reset(void) > +{ > + atomic_set(&lrng_rb_reader, 0); > + atomic_set(&lrng_rb_writer, 0); > + atomic_set(&lrng_rb_first_in, 0); > +} > + > +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; > + > + lrng_raw_entropy_reset(); > + atomic_set(&lrng_testing_enabled, 0); > + pr_warn("Disabling raw entropy collection\n"); > +} > + > +bool lrng_raw_entropy_store(u32 value) > +{ > + unsigned int write_ptr; > + unsigned int read_ptr; > + > + if (!atomic_read(&lrng_testing_enabled) && !boot_test) > + return false; > + > + write_ptr =3D (unsigned int)atomic_add_return_relaxed(1, &lrng_rb_wri= ter); > + read_ptr =3D (unsigned int)atomic_read(&lrng_rb_reader); Am I correct in assuming that this function can be called concurrently in di= fferent threads or CPUs? > + > + /* > + * Disable entropy testing for boot time testing after ring buffer > + * is filled. > + */ > + if (boot_test && write_ptr > LRNG_TESTING_RINGBUFFER_SIZE) { > + pr_warn_once("Boot time entropy collection test disabled\n"); > + return false; > + } > + > + if (boot_test && !atomic_read(&lrng_rb_first_in)) > + pr_warn("Boot time entropy collection test enabled\n"); > + > + lrng_testing_rb[write_ptr & LRNG_TESTING_RINGBUFFER_MASK] =3D value; You=E2=80=99re writing *somewhere*, but not necessarily to the first open sl= ot. > + > + /* We got at least one event, enable the reader now. */ > + atomic_set(&lrng_rb_first_in, 1); But not necessarily in position 0. > + > + if (wq_has_sleeper(&lrng_raw_read_wait)) > + wake_up_interruptible(&lrng_raw_read_wait); > + > + /* > + * Our writer is taking over the reader - this means the reader > + * one full ring buffer available. Thus we "push" the reader ahead > + * to guarantee that he will be able to consume the full ring. > + */ > + if (!boot_test && > + ((write_ptr & LRNG_TESTING_RINGBUFFER_MASK) =3D=3D > + (read_ptr & LRNG_TESTING_RINGBUFFER_MASK))) > + atomic_inc_return_relaxed(&lrng_rb_reader); Because you did a relaxed increment above, you don=E2=80=99t actually know t= his. Maybe it=E2=80=99s okay, but this is way too subtle. I think you should have a mutex for the read side and put all the complicate= d accounting inside the mutex. If the reader can=E2=80=99t figure out that t= he read pointer is too far behind the write pointer, then fix the reader. I also don=E2=80=99t see how the reader is supposed to know how much data ha= s actually been written. You don=E2=80=99t have any variable that says =E2=80= =9Call words up to X have been written=E2=80=9D. I think you should stop trying to make the write side wait free. Instead, co= nsider either using a lock or making it unreliable. For the former, just sk= ip taking the lock if testing is off. For the latter, read write_ptr, write (= using WRITE_ONCE) your data, then cmpxchg the write ptr from the value you r= ead to that value plus one. And make sure that the reader never tries to re= ad the first unwritten slot, i.e. never let the reader catch all the way up.= I=E2=80=99m also curious why you need entirely different infrastructure for t= esting as for normal operation. > + > + return true; > +} > + > +static inline bool lrng_raw_have_data(void) > +{ > + unsigned int read_ptr =3D (unsigned int)atomic_read(&lrng_rb_reader);= > + unsigned int write_ptr =3D (unsigned int)atomic_read(&lrng_rb_writer)= ; > + > + return (atomic_read(&lrng_rb_first_in) && > + (write_ptr & LRNG_TESTING_RINGBUFFER_MASK) !=3D > + (read_ptr & LRNG_TESTING_RINGBUFFER_MASK)); > +} > + > +static int lrng_raw_entropy_reader(u8 *outbuf, u32 outbuflen) > +{ > + int collected_data =3D 0; > + > + if (!atomic_read(&lrng_testing_enabled) && !boot_test) > + return -EAGAIN; > + > + if (!atomic_read(&lrng_rb_first_in)) { > + wait_event_interruptible(lrng_raw_read_wait, > + lrng_raw_have_data()); > + if (signal_pending(current)) > + return -ERESTARTSYS; > + } > + > + while (outbuflen) { > + unsigned int read_ptr =3D > + (unsigned int)atomic_add_return_relaxed( > + 1, &lrng_rb_reader); > + unsigned int write_ptr =3D > + (unsigned int)atomic_read(&lrng_rb_writer); > + > + /* > + * For boot time testing, only output one round of ring buffer. > + */ > + if (boot_test && read_ptr > LRNG_TESTING_RINGBUFFER_SIZE) { > + collected_data =3D -ENOMSG; > + goto out; > + } > + > + /* We reached the writer */ > + if (!boot_test && ((write_ptr & LRNG_TESTING_RINGBUFFER_MASK) =3D= =3D > + (read_ptr & LRNG_TESTING_RINGBUFFER_MASK))) { > + =20 This is wrong. The fact that you haven=E2=80=99t reached the writer does not= imply that you=E2=80=99re about to read valid data.