From nobody Sun Feb 13 07:29:48 2022 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 2CC9919416C2; Sun, 13 Feb 2022 07:29:49 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4JxJs83mr5z3q2D; Sun, 13 Feb 2022 07:29:48 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1644737388; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=suOph1OwFcGVx+cZHeXp6eRlQGlHAlHUnYo0jpTJB+Y=; b=MpD3vODPAGlmkPp1UODFFTKQ6Z6gz2idYSTodSrbE5fu1+MociE10wN5eaGO/OsHmG5UMZ WdECg0sKS6S4TQRDCBdPynQwHMVBk5vOiAJjvqXg+bpV6wTFApZrV9bV7bEsr/9HGxKyEG mnDmviDQOFF4ovMfVpHuyZLq1g+OnLbHuV2yDQVsgqggMTNFKlo2sbF6UEl7rCaeuo2ZY1 jECmtHM6ekgBe53qLRvMevdjVnyNHKQMUotZReAlhuDRIlgoLgNH5ydfujonTk/O1xFe+s 9d8gZyiK1eXlvWoWYBKmvUOIGXviRvfk73bEm8aCsCW5vfP/Y8YQWgRcLDG7Yg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 396BB16E43; Sun, 13 Feb 2022 07:29:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 21D7TmpF018793; Sun, 13 Feb 2022 07:29:48 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 21D7TmGf018792; Sun, 13 Feb 2022 07:29:48 GMT (envelope-from git) Date: Sun, 13 Feb 2022 07:29:48 GMT Message-Id: <202202130729.21D7TmGf018792@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: "David E. O'Brien" Subject: git: f591279d9c93 - stable/12 - random(4): Restore availability tradeoff prior to r346250 List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: obrien X-Git-Repository: src X-Git-Refname: refs/heads/stable/12 X-Git-Reftype: branch X-Git-Commit: f591279d9c93bc2ea9cd1a447c2df11d437fbc7b Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1644737388; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=suOph1OwFcGVx+cZHeXp6eRlQGlHAlHUnYo0jpTJB+Y=; b=vvb7pIM3STAUIfEZgLPk0N4mzf+FCuvtKlOcom7bWwFF91+nYto2Udp26V3MiA0J57RHIF 6u7XfiZUeCS9m8W4FqHvhCSZzNf7/vZLuITTMTkwBKshYnP8weMy1e3d49PHh9/BScMAVo Sw126ILt8EorXvvAFLoGmDibUT5iPJxqStf+cEXkwU3JcnHJjpe3HE25jM59eiLn+PtuQT ez4bHpQW3+4s/or37CxDKc83ry3snQMl02JQ5xbuvgXaOnstEaA4ihCU2f+Eq9r/rU6bMM C2yOHBDRY2/9hDKYU+WXHkHwK3s9VHII+RSlx3U+LqkDGDjrEnDeE3yJiu8pGw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1644737388; a=rsa-sha256; cv=none; b=Exo33kyBZDc345OgKXm6F8NtCvg9qh0olOj3bk3mD+ehDnMyt6OU0R/rP+WxhxL7C09jiZ li69wCctOWDp0CoXIFcCPF7sqyjEshu1/3qB+BwLNF3tc/Xw5k6qBaBXYKe+AUx5xe5qkM 7PlNJ/HVHs04uBr0EXEBlU7S4I9awTPu//LAXGJttb8QKeOd1Ns82ynEfVXTyWmorvW/nT h0AiEl1PMWr9QVximLcFSLFnETw0YAqB+hCHDEb404m3egcrnli3H/4bDAsUop1xLleg1y 4YUA6UHHSbanejhSQqZ5mye/srYZzZViYU5dhWimt80AXxXvyzGtYESpe96C0Q== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch stable/12 has been updated by obrien: URL: https://cgit.FreeBSD.org/src/commit/?id=f591279d9c93bc2ea9cd1a447c2df11d437fbc7b commit f591279d9c93bc2ea9cd1a447c2df11d437fbc7b Author: Conrad Meyer AuthorDate: 2019-04-18 20:48:54 +0000 Commit: David E. O'Brien CommitDate: 2022-02-13 06:38:52 +0000 random(4): Restore availability tradeoff prior to r346250 As discussed in that commit message, it is a dangerous default. But the safe default causes enough pain on a variety of platforms that for now, restore the prior default. Some of this is self-induced pain we should/could do better about; for example, programmatic CI systems and VM managers should introduce entropy from the host for individual VM instances. This is considered a future work item. On modern x86 and Power9 systems, this may be wholly unnecessary after D19928 lands (even in the non-ideal case where early /boot/entropy is unavailable), because they have fast hardware random sources available early in boot. But D19928 is not yet landed and we have a host of architectures which do not provide fast random sources. This change adds several tunables and diagnostic sysctls, documented thoroughly in UPDATING and sys/dev/random/random_infra.c. (cherry picked from commit 3782136ff1fc1e076c939246f199e659d950bad5) NOTE: Enabling sys/mips/conf/PB92 'random' in 3782136ff is skipped. --- UPDATING | 23 ++++++++++++++++++ sys/dev/random/random_infra.c | 56 ++++++++++++++++++++++++++++++++++++++++++- sys/dev/random/randomdev.c | 39 +++++++++++++++++++++++------- sys/dev/random/randomdev.h | 6 +++++ sys/libkern/arc4random.c | 46 ++++++++++++++++++++++++++++++----- sys/sys/param.h | 2 +- 6 files changed, 156 insertions(+), 16 deletions(-) diff --git a/UPDATING b/UPDATING index 031d73d7e150..de06358e7420 100644 --- a/UPDATING +++ b/UPDATING @@ -18,6 +18,29 @@ the tip of head, and then rebuild without this option. The bootstrap process from older version of current across the gcc/clang cutover is a bit fragile. 20220214: + The following knobs have been added related to tradeoffs between + safe use of the random device and availability in the absence of + entropy: + + kern.random.initial_seeding.bypass_before_seeding: tunable; set + non-zero to bypass the random device prior to seeding, or zero to + block random requests until the random device is initially seeded. + For now, set to 1 (unsafe) by default to restore pre-r346250 boot + availability properties. + + kern.random.initial_seeding.read_random_bypassed_before_seeding: + read-only diagnostic sysctl that is set when bypass is enabled and + read_random(9) is bypassed, to enable programmatic handling of this + initial condition, if desired. + + kern.random.initial_seeding.arc4random_bypassed_before_seeding: + Similar to the above, but for for arc4random(9) initial seeding. + + kern.random.initial_seeding.disable_bypass_warnings: tunable; set + non-zero to disable warnings in dmesg when the same conditions are + met as for the diagnostic sysctls above. Defaults to zero, i.e., + produce warnings in dmesg when the conditions are met. + The loadable random module KPI has changed; the random_infra_init() routine now requires a 3rd function pointer for a bool (*)(void) method that returns true if the random device is seeded (and diff --git a/sys/dev/random/random_infra.c b/sys/dev/random/random_infra.c index 59cd44280b95..9a40c35f12b7 100644 --- a/sys/dev/random/random_infra.c +++ b/sys/dev/random/random_infra.c @@ -43,7 +43,61 @@ __FBSDID("$FreeBSD$"); #include /* Set up the sysctl root node for the entropy device */ -SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); +SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, + "Cryptographically Secure Random Number Generator"); +SYSCTL_NODE(_kern_random, OID_AUTO, initial_seeding, CTLFLAG_RW, 0, + "Initial seeding control and information"); + +/* + * N.B., this is a dangerous default, but it matches the behavior prior to + * r346250 (and, say, OpenBSD -- although they get some guaranteed saved + * entropy from the prior boot because of their KARL system, on RW media). + */ +bool random_bypass_before_seeding = true; +SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO, + bypass_before_seeding, CTLFLAG_RDTUN, &random_bypass_before_seeding, + 0, "If set non-zero, bypass the random device in requests for random " + "data when the random device is not yet seeded. This is considered " + "dangerous. Ordinarily, the random device will block requests until " + "it is seeded by sufficient entropy."); + +/* + * This is a read-only diagnostic that reports the combination of the former + * tunable and actual bypass. It is intended for programmatic inspection by + * userspace administrative utilities after boot. + */ +bool read_random_bypassed_before_seeding = false; +SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO, + read_random_bypassed_before_seeding, CTLFLAG_RD, + &read_random_bypassed_before_seeding, 0, "If non-zero, the random device " + "was bypassed because the 'bypass_before_seeding' knob was enabled and a " + "request was submitted prior to initial seeding."); + +/* + * This is a read-only diagnostic that reports the combination of the former + * tunable and actual bypass for arc4random initial seeding. It is intended + * for programmatic inspection by userspace administrative utilities after + * boot. + */ +bool arc4random_bypassed_before_seeding = false; +SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO, + arc4random_bypassed_before_seeding, CTLFLAG_RD, + &arc4random_bypassed_before_seeding, 0, "If non-zero, the random device " + "was bypassed when initially seeding the kernel arc4random(9), because " + "the 'bypass_before_seeding' knob was enabled and a request was submitted " + "prior to initial seeding."); + +/* + * This knob is for users who do not want additional warnings in their logs + * because they intend to handle bypass by inspecting the status of the + * diagnostic sysctls. + */ +bool random_bypass_disable_warnings = false; +SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO, + disable_bypass_warnings, CTLFLAG_RDTUN, + &random_bypass_disable_warnings, 0, "If non-zero, do not log a warning " + "if the 'bypass_before_seeding' knob is enabled and a request is " + "submitted prior to initial seeding."); MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index cbe01d1c5343..9e2ddb29ce0b 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -236,11 +236,15 @@ READ_RANDOM_UIO(struct uio *uio, bool nonblock) } /*- - * Kernel API version of read_random(). - * This is similar to random_alg_read(), - * except it doesn't interface with uio(9). - * It cannot assumed that random_buf is a multiple of - * RANDOM_BLOCKSIZE bytes. + * Kernel API version of read_random(). This is similar to read_random_uio(), + * except it doesn't interface with uio(9). It cannot assumed that random_buf + * is a multiple of RANDOM_BLOCKSIZE bytes. + * + * If the tunable 'kern.random.initial_seeding.bypass_before_seeding' is set + * non-zero, silently fail to emit random data (matching the pre-r346250 + * behavior). If read_random is called prior to seeding and bypassed because + * of this tunable, the condition is reported in the read-only sysctl + * 'kern.random.initial_seeding.read_random_bypassed_before_seeding'. */ void READ_RANDOM(void *random_buf, u_int len) @@ -249,12 +253,31 @@ READ_RANDOM(void *random_buf, u_int len) KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); p_random_alg_context->ra_pre_read(); + + if (len == 0) + return; + /* (Un)Blocking logic */ - if (!p_random_alg_context->ra_seeded()) + if (__predict_false(!p_random_alg_context->ra_seeded())) { + if (random_bypass_before_seeding) { + if (!read_random_bypassed_before_seeding) { + if (!random_bypass_disable_warnings) + printf("read_random: WARNING: bypassing" + " request for random data because " + "the random device is not yet " + "seeded and the knob " + "'bypass_before_seeding' was " + "enabled.\n"); + read_random_bypassed_before_seeding = true; + } + /* Avoid potentially leaking stack garbage */ + memset(random_buf, 0, len); + return; + } + (void)randomdev_wait_until_seeded(SEEDWAIT_UNINTERRUPTIBLE); + } read_rate_increment(roundup2(len, sizeof(uint32_t))); - if (len == 0) - return; /* * The underlying generator expects multiples of * RANDOM_BLOCKSIZE. diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index e5df7efefa5b..91c93aee0805 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -37,6 +37,7 @@ #ifdef SYSCTL_DECL /* from sysctl.h */ SYSCTL_DECL(_kern_random); +SYSCTL_DECL(_kern_random_initial_seeding); #define RANDOM_CHECK_UINT(name, min, max) \ static int \ @@ -55,6 +56,11 @@ random_check_uint_##name(SYSCTL_HANDLER_ARGS) \ MALLOC_DECLARE(M_ENTROPY); +extern bool random_bypass_before_seeding; +extern bool read_random_bypassed_before_seeding; +extern bool arc4random_bypassed_before_seeding; +extern bool random_bypass_disable_warnings; + #endif /* _KERNEL */ struct harvest_event; diff --git a/sys/libkern/arc4random.c b/sys/libkern/arc4random.c index cdc303e9d309..313ec986c80f 100644 --- a/sys/libkern/arc4random.c +++ b/sys/libkern/arc4random.c @@ -41,6 +41,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include +#include #define CHACHA20_RESEED_BYTES 65536 #define CHACHA20_RESEED_SECONDS 300 @@ -77,12 +80,43 @@ chacha20_randomstir(struct chacha20_s *chacha20) struct timeval tv_now; u_int8_t key[CHACHA20_KEYBYTES]; - /* - * If the loader(8) did not have an entropy stash from the previous - * shutdown to load, then we will block. The answer is to make sure - * there is an entropy stash at shutdown time. - */ - read_random(key, CHACHA20_KEYBYTES); + if (__predict_false(random_bypass_before_seeding && !is_random_seeded())) { + SHA256_CTX ctx; + uint64_t cc; + uint32_t fver; + + if (!arc4random_bypassed_before_seeding) { + arc4random_bypassed_before_seeding = true; + if (!random_bypass_disable_warnings) + printf("arc4random: WARNING: initial seeding " + "bypassed the cryptographic random device " + "because it was not yet seeded and the " + "knob 'bypass_before_seeding' was " + "enabled.\n"); + } + + /* Last ditch effort to inject something in a bad condition. */ + cc = get_cyclecount(); + SHA256_Init(&ctx); + SHA256_Update(&ctx, key, sizeof(key)); + SHA256_Update(&ctx, &cc, sizeof(cc)); + fver = __FreeBSD_version; + SHA256_Update(&ctx, &fver, sizeof(fver)); + _Static_assert(sizeof(key) == SHA256_DIGEST_LENGTH, + "make sure 256 bits is still 256 bits"); + SHA256_Final(key, &ctx); + } else { + /* + * If the loader(8) did not have an entropy stash from the + * previous shutdown to load, then we will block. The answer is + * to make sure there is an entropy stash at shutdown time. + * + * On the other hand, if the random_bypass_before_seeding knob + * was set and we landed in this branch, we know this won't + * block because we know the random device is seeded. + */ + read_random(key, CHACHA20_KEYBYTES); + } getmicrouptime(&tv_now); mtx_lock(&chacha20->mtx); chacha_keysetup(&chacha20->ctx, key, CHACHA20_KEYBYTES*8); diff --git a/sys/sys/param.h b/sys/sys/param.h index dd27b0d02a4f..5a6d46e9a05a 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1203505 /* Master, propagated to newvers */ +#define __FreeBSD_version 1203506 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,