From 609ed01f6cf7fe9bf681f5f3871b65a3b15e28ae Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Mon, 18 Apr 2022 14:18:33 +0000 Subject: [PATCH 1/4] x86/pmap: Feed entropy_extract output through nist_hash_drbg. The entropy pool algorithm is NOT designed to provide backtracking resistance on its own -- it MUST be combined with a PRNG/DRBG that provides that. The only reason we use entropy_extract here is that cprng(9) is not available yet (which in turn is because kmem and other basic kernel facilities aren't available yet), but nist_hash_drbg doesn't have any initialization order requirements, so we'll just use it directly. --- sys/arch/x86/x86/pmap.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/sys/arch/x86/x86/pmap.c b/sys/arch/x86/x86/pmap.c index 4a74f8f184f6..c95d9ac2b31c 100644 --- a/sys/arch/x86/x86/pmap.c +++ b/sys/arch/x86/x86/pmap.c @@ -178,6 +178,10 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.414 2022/05/07 14:59:25 bouyer Exp $"); #include #endif +#ifdef __HAVE_DIRECT_MAP +#include +#endif + /* * general info: * @@ -1602,6 +1606,33 @@ pmap_init_pcpu(void) #endif #ifdef __HAVE_DIRECT_MAP +static void +randomize_hole(size_t *randholep, vaddr_t *randvap) +{ + struct nist_hash_drbg drbg; + uint8_t seed[NIST_HASH_DRBG_SEEDLEN_BYTES]; + const char p[] = "x86/directmap"; + int ok; + + entropy_extract(seed, sizeof(seed), 0); + + ok = nist_hash_drbg_instantiate(&drbg, seed, sizeof(seed), + /*nonce*/NULL, 0, + /*personalization*/p, strlen(p)); + KASSERT(ok); + + ok = nist_hash_drbg_generate(&drbg, randholep, sizeof(*randholep), + /*additional*/NULL, 0); + KASSERT(ok); + + ok = nist_hash_drbg_generate(&drbg, randvap, sizeof(*randvap), + /*additional*/NULL, 0); + KASSERT(ok); + + explicit_memset(seed, 0, sizeof(seed)); + explicit_memset(&drbg, 0, sizeof(drbg)); +} + /* * Create the amd64 direct map. Called only once at boot time. We map all of * the physical memory contiguously using 2MB large pages, with RW permissions. @@ -1648,8 +1679,7 @@ pmap_init_directmap(struct pmap *kpm) panic("pmap_init_directmap: lastpa incorrect"); } - entropy_extract(&randhole, sizeof randhole, 0); - entropy_extract(&randva, sizeof randva, 0); + randomize_hole(&randhole, &randva); startva = slotspace_rand(SLAREA_DMAP, lastpa, NBPD_L2, randhole, randva); endva = startva + lastpa; From 71abea1ba8e8e83b08d5ae1951aec2f7a044f4bc Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Mon, 18 Apr 2022 14:21:01 +0000 Subject: [PATCH 2/4] entropy(9): Note rules about how to use entropy_extract output. --- sys/kern/kern_entropy.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sys/kern/kern_entropy.c b/sys/kern/kern_entropy.c index d867abefdadd..e09210bf91f1 100644 --- a/sys/kern/kern_entropy.c +++ b/sys/kern/kern_entropy.c @@ -1329,6 +1329,16 @@ sysctl_entropy_gather(SYSCTLFN_ARGS) * * Extract len bytes from the global entropy pool into buf. * + * Caller MUST NOT expose these bytes directly -- must use them + * ONLY to seed a cryptographic pseudorandom number generator + * (`CPRNG'), a.k.a. deterministic random bit generator (`DRBG'), + * and then erase them. entropy_extract does not, on its own, + * provide backtracking resistance -- it must be combined with a + * PRNG/DRBG that does. + * + * You generally shouldn't use this directly -- use cprng(9) + * instead. + * * Flags may have: * * ENTROPY_WAIT Wait for entropy if not available yet. From 42dc304df5c75e1a50df4fb0aeec8d8bf2f80901 Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Mon, 18 Apr 2022 14:21:35 +0000 Subject: [PATCH 3/4] entropy(9): Update comment about where entropy_extract is allowed. As of last month, it is forbidden in all hard interrupt context. --- sys/kern/kern_entropy.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sys/kern/kern_entropy.c b/sys/kern/kern_entropy.c index e09210bf91f1..f193bd34528a 100644 --- a/sys/kern/kern_entropy.c +++ b/sys/kern/kern_entropy.c @@ -1352,9 +1352,8 @@ sysctl_entropy_gather(SYSCTLFN_ARGS) * EINTR/ERESTART No entropy, ENTROPY_SIG set, and interrupted. * * If ENTROPY_WAIT is set, allowed only in thread context. If - * ENTROPY_WAIT is not set, allowed up to IPL_VM. (XXX That's - * awfully high... Do we really need it in hard interrupts? This - * arises from use of cprng_strong(9).) + * ENTROPY_WAIT is not set, allowed also in softint context. + * Forbidden in hard interrupt context. */ int entropy_extract(void *buf, size_t len, int flags) From 70659e3a67b986a45dd1262368855e7cac226754 Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Mon, 18 Apr 2022 14:22:02 +0000 Subject: [PATCH 4/4] cprng(9): Fix accidental 4x seed size. With SHA-256, NIST Hash_DRBG takes an preferred 440-bit/55-byte seed. It's a weird number, and I'm not sure where it comes from (a quick skim of SP800-90A doesn't turn anything up), but it's certainly sufficient (256-bit/32-byte seed is almost certainly enough) so it's not a problem to use something larger; Hash_DRBG can absorb seeds of arbitrary lengths and larger seeds can't really hurt security (with minor caveats like HMAC RO quirks that don't apply here). Except -- owing to a typo, we actually used a 1760-bit/220-byte seed, because I wrote `uint32_t seed[...]' instead of `uint8_t seed[...]'. Again: not a problem to use a seed larger than needed. But let's draw no more than we need out of the entropy pool! Verified with CTASSERT(sizeof(seed) == 55). (Assertion omitted from this commit because we might swap out Hash_DRBG for something else with a different seed size like 32 bytes.) --- sys/kern/subr_cprng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/kern/subr_cprng.c b/sys/kern/subr_cprng.c index 3588dcada4fa..691008f6e29a 100644 --- a/sys/kern/subr_cprng.c +++ b/sys/kern/subr_cprng.c @@ -268,7 +268,7 @@ cprng_fini_cpu(void *ptr, void *cookie, struct cpu_info *ci) size_t cprng_strong(struct cprng_strong *cprng, void *buf, size_t len, int flags) { - uint32_t seed[NIST_HASH_DRBG_SEEDLEN_BYTES]; + uint8_t seed[NIST_HASH_DRBG_SEEDLEN_BYTES]; struct cprng_cpu *cc; unsigned epoch; int s;