git: 9ca8e09abba8 - stable/15 - random: add RDSEED as a provably unique entropy source

From: David E. O'Brien <obrien_at_FreeBSD.org>
Date: Wed, 29 Oct 2025 07:00:51 UTC
The branch stable/15 has been updated by obrien:

URL: https://cgit.FreeBSD.org/src/commit/?id=9ca8e09abba87991ad5171ed8920f4d1571245d5

commit 9ca8e09abba87991ad5171ed8920f4d1571245d5
Author:     David E. O'Brien <obrien@FreeBSD.org>
AuthorDate: 2025-10-17 03:20:23 +0000
Commit:     David E. O'Brien <obrien@FreeBSD.org>
CommitDate: 2025-10-29 06:10:45 +0000

    random: add RDSEED as a provably unique entropy source
    
    NIST SP800-90B allows for only a single entropy source to be claimed
    in a FIPS-140-3 certificate.  In addition, only hardware sources that
    have a NIST Entropy Source Validation (ESV) certificate, backed by
    a SP800-90B Entropy Assessment Report, are usable.  Intel has obtained
    ESV certificates for several of their processors, so RDSEED is a
    FIPS-140-3 suitable entropy source.
    
    However, even though RDRAND is seeded by RDSEED internally, RDRAND
    would need a RBG certificate and CAVP testing run on the DRBG in order
    to use it for FIPS-140-3 (SP800-90B) purposes.  So we need to know
    down in the CSPRNG-subsystem which source the entropy came from.
    
    In light of the potential issues surrounding AMD Zen 5 CPU's RDSEED
    implementation[*], allow RDSEED to be disabled in loader.conf.
    [*] https://www.phoronix.com/news/AMD-EPYC-Turin-RDSEED-Bug
    
    Reviewed by:    cem
    MFC after:      3 days
    Sponsored by:   Juniper Networks
    Differential Revision:  https://reviews.freebsd.org/D53150
    Differential Revision:  https://reviews.freebsd.org/D53291
    (cherry picked from commit 3a12982962ce330c37c154bb2eb8ae0539fc6f48)
    (cherry picked from commit 38e9d282cd7dacbf64883b45544723408cfd4d09)
---
 sys/conf/files.x86                  |   1 +
 sys/dev/random/fenestrasX/fx_pool.c |   3 +
 sys/dev/random/ivy.c                |  69 ++++-----------
 sys/dev/random/random_harvestq.c    |   1 +
 sys/dev/random/rdseed.c             | 169 ++++++++++++++++++++++++++++++++++++
 sys/modules/Makefile                |   2 +
 sys/modules/rdrand_rng/Makefile     |   5 --
 sys/modules/rdseed_rng/Makefile     |   9 ++
 sys/sys/random.h                    |   1 +
 9 files changed, 205 insertions(+), 55 deletions(-)

diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
index 953da7dd1284..21a1b8046f12 100644
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -311,6 +311,7 @@ dev/ntb/test/ntb_tool.c		optional	ntb_tool
 dev/nvram/nvram.c		optional	nvram isa
 dev/random/ivy.c		optional	rdrand_rng !random_loadable
 dev/random/nehemiah.c		optional	padlock_rng !random_loadable
+dev/random/rdseed.c		optional	rdrand_rng !random_loadable
 dev/qat_c2xxx/qat.c		optional	qat_c2xxx
 dev/qat_c2xxx/qat_ae.c		optional	qat_c2xxx
 dev/qat_c2xxx/qat_c2xxx.c	optional	qat_c2xxx
diff --git a/sys/dev/random/fenestrasX/fx_pool.c b/sys/dev/random/fenestrasX/fx_pool.c
index ec59b97a2070..95c2d223e0de 100644
--- a/sys/dev/random/fenestrasX/fx_pool.c
+++ b/sys/dev/random/fenestrasX/fx_pool.c
@@ -179,6 +179,9 @@ static const struct fxrng_ent_char {
 	[RANDOM_PURE_RDRAND] = {
 		.entc_cls = &fxrng_hi_pull,
 	},
+	[RANDOM_PURE_RDSEED] = {
+		.entc_cls = &fxrng_hi_pull,
+	},
 	[RANDOM_PURE_NEHEMIAH] = {
 		.entc_cls = &fxrng_hi_pull,
 	},
diff --git a/sys/dev/random/ivy.c b/sys/dev/random/ivy.c
index fa1e4831f1b9..3eb0f261e6dc 100644
--- a/sys/dev/random/ivy.c
+++ b/sys/dev/random/ivy.c
@@ -1,6 +1,6 @@
 /*-
+ * Copyright (c) 2013, 2025, David E. O'Brien <deo@NUXI.org>
  * Copyright (c) 2013 The FreeBSD Foundation
- * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
  * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
  * All rights reserved.
  *
@@ -48,7 +48,6 @@
 
 #define	RETRY_COUNT	10
 
-static bool has_rdrand, has_rdseed;
 static u_int random_ivy_read(void *, u_int);
 
 static const struct random_source random_ivy = {
@@ -57,13 +56,7 @@ static const struct random_source random_ivy = {
 	.rs_read = random_ivy_read
 };
 
-SYSCTL_NODE(_kern_random, OID_AUTO, rdrand, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
-    "rdrand (ivy) entropy source");
 static bool acquire_independent_seed_samples = false;
-SYSCTL_BOOL(_kern_random_rdrand, OID_AUTO, rdrand_independent_seed,
-    CTLFLAG_RWTUN, &acquire_independent_seed_samples, 0,
-    "If non-zero, use more expensive and slow, but safer, seeded samples "
-    "where RDSEED is not present.");
 
 static bool
 x86_rdrand_store(u_long *buf)
@@ -99,45 +92,6 @@ x86_rdrand_store(u_long *buf)
 	return (true);
 }
 
-static bool
-x86_rdseed_store(u_long *buf)
-{
-	u_long rndval;
-	int retry;
-
-	retry = RETRY_COUNT;
-	__asm __volatile(
-	    "1:\n\t"
-	    "rdseed	%1\n\t"	/* read randomness into rndval */
-	    "jc		2f\n\t" /* CF is set on success, exit retry loop */
-	    "dec	%0\n\t" /* otherwise, retry-- */
-	    "jne	1b\n\t" /* and loop if retries are not exhausted */
-	    "2:"
-	    : "+r" (retry), "=r" (rndval) : : "cc");
-	*buf = rndval;
-	return (retry != 0);
-}
-
-static bool
-x86_unimpl_store(u_long *buf __unused)
-{
-
-	panic("%s called", __func__);
-}
-
-DEFINE_IFUNC(static, bool, x86_rng_store, (u_long *buf))
-{
-	has_rdrand = (cpu_feature2 & CPUID2_RDRAND);
-	has_rdseed = (cpu_stdext_feature & CPUID_STDEXT_RDSEED);
-
-	if (has_rdseed)
-		return (x86_rdseed_store);
-	else if (has_rdrand)
-		return (x86_rdrand_store);
-	else
-		return (x86_unimpl_store);
-}
-
 /* It is required that buf length is a multiple of sizeof(u_long). */
 static u_int
 random_ivy_read(void *buf, u_int c)
@@ -148,7 +102,7 @@ random_ivy_read(void *buf, u_int c)
 	KASSERT(c % sizeof(*b) == 0, ("partial read %d", c));
 	b = buf;
 	for (count = c; count > 0; count -= sizeof(*b)) {
-		if (!x86_rng_store(&rndval))
+		if (!x86_rdrand_store(&rndval))
 			break;
 		*b++ = rndval;
 	}
@@ -158,18 +112,33 @@ random_ivy_read(void *buf, u_int c)
 static int
 rdrand_modevent(module_t mod, int type, void *unused)
 {
+	struct sysctl_ctx_list ctx;
+	struct sysctl_oid *o;
+	bool has_rdrand, has_rdseed;
 	int error = 0;
 
+	has_rdrand = (cpu_feature2 & CPUID2_RDRAND);
+	has_rdseed = (cpu_stdext_feature & CPUID_STDEXT_RDSEED);
+
 	switch (type) {
 	case MOD_LOAD:
-		if (has_rdrand || has_rdseed) {
+		if (has_rdrand && !has_rdseed) {
+			sysctl_ctx_init(&ctx);
+			o = SYSCTL_ADD_NODE(&ctx, SYSCTL_STATIC_CHILDREN(_kern_random),
+			    OID_AUTO, "rdrand", CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+			    "rdrand (ivy) entropy source");
+			SYSCTL_ADD_BOOL(&ctx, SYSCTL_CHILDREN(o), OID_AUTO,
+			    "rdrand_independent_seed", CTLFLAG_RDTUN,
+			    &acquire_independent_seed_samples, 0,
+	"If non-zero, use more expensive and slow, but safer, seeded samples "
+	"where RDSEED is not present.");
 			random_source_register(&random_ivy);
 			printf("random: fast provider: \"%s\"\n", random_ivy.rs_ident);
 		}
 		break;
 
 	case MOD_UNLOAD:
-		if (has_rdrand || has_rdseed)
+		if (has_rdrand && !has_rdseed)
 			random_source_deregister(&random_ivy);
 		break;
 
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index 3b68e41b053a..e38fd38c310b 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -665,6 +665,7 @@ static const char *random_source_descr[ENTROPYSOURCE] = {
 	[RANDOM_PURE_GLXSB] = "PURE_GLXSB",
 	[RANDOM_PURE_HIFN] = "PURE_HIFN",
 	[RANDOM_PURE_RDRAND] = "PURE_RDRAND",
+	[RANDOM_PURE_RDSEED] = "PURE_RDSEED",
 	[RANDOM_PURE_NEHEMIAH] = "PURE_NEHEMIAH",
 	[RANDOM_PURE_RNDTEST] = "PURE_RNDTEST",
 	[RANDOM_PURE_VIRTIO] = "PURE_VIRTIO",
diff --git a/sys/dev/random/rdseed.c b/sys/dev/random/rdseed.c
new file mode 100644
index 000000000000..af084aab4ed9
--- /dev/null
+++ b/sys/dev/random/rdseed.c
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 2013, 2025, David E. O'Brien <deo@NUXI.org>
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/random.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+#include <x86/ifunc.h>
+
+#include <dev/random/randomdev.h>
+
+#define	RETRY_COUNT	10
+
+static u_int random_rdseed_read(void *, u_int);
+
+static struct random_source random_rdseed = {
+	.rs_ident = "Intel Secure Key Seed",
+	.rs_source = RANDOM_PURE_RDSEED,
+	.rs_read = random_rdseed_read
+};
+
+SYSCTL_NODE(_kern_random, OID_AUTO, rdseed, CTLFLAG_RW, 0,
+    "rdseed (x86) entropy source");
+/* XXX: kern.random.rdseed.enabled=0 also disables RDRAND */
+static bool enabled = true;
+SYSCTL_BOOL(_kern_random_rdseed, OID_AUTO, enabled, CTLFLAG_RDTUN, &enabled, 0,
+    "If zero, disable the use of RDSEED.");
+
+static bool
+x86_rdseed_store(u_long *buf)
+{
+	u_long rndval;
+	int retry;
+
+	retry = RETRY_COUNT;
+	__asm __volatile(
+	    "1:\n\t"
+	    "rdseed	%1\n\t"	/* read randomness into rndval */
+	    "jc		2f\n\t" /* CF is set on success, exit retry loop */
+	    "dec	%0\n\t" /* otherwise, retry-- */
+	    "jne	1b\n\t" /* and loop if retries are not exhausted */
+	    "2:"
+	    : "+r" (retry), "=r" (rndval) : : "cc");
+	*buf = rndval;
+	return (retry != 0);
+}
+
+/* It is required that buf length is a multiple of sizeof(u_long). */
+static u_int
+random_rdseed_read(void *buf, u_int c)
+{
+	u_long *b, rndval;
+	u_int count;
+
+	KASSERT(c % sizeof(*b) == 0, ("partial read %d", c));
+	b = buf;
+	for (count = c; count > 0; count -= sizeof(*b)) {
+		if (!x86_rdseed_store(&rndval))
+			break;
+		*b++ = rndval;
+	}
+	return (c - count);
+}
+
+static int
+rdseed_modevent(module_t mod, int type, void *unused)
+{
+	bool has_rdseed;
+	int error = 0;
+
+	has_rdseed = (cpu_stdext_feature & CPUID_STDEXT_RDSEED);
+
+	switch (type) {
+	case MOD_LOAD:
+		if (has_rdseed && enabled) {
+			random_source_register(&random_rdseed);
+			printf("random: fast provider: \"%s\"\n", random_rdseed.rs_ident);
+		}
+		break;
+
+	case MOD_UNLOAD:
+		if (has_rdseed)
+			random_source_deregister(&random_rdseed);
+		break;
+
+	case MOD_SHUTDOWN:
+		break;
+
+	default:
+		error = EOPNOTSUPP;
+		break;
+
+	}
+
+	return (error);
+}
+
+static moduledata_t rdseed_mod = {
+	"rdseed",
+	rdseed_modevent,
+	0
+};
+
+DECLARE_MODULE(rdseed, rdseed_mod, SI_SUB_RANDOM, SI_ORDER_FOURTH);
+MODULE_VERSION(rdseed, 1);
+MODULE_DEPEND(rdseed, random_harvestq, 1, 1, 1);
+
+/*
+ * Intel's RDSEED Entropy Assessment Report min-entropy claim is 0.6 Shannons
+ * per bit of data output.  Rrefer to the following Entropy Source Validation
+ * (ESV) certificates:
+ *
+ *	E#87:	Junos OS Physical Entropy Source - Broadwell EP 10-Core Die
+ *		Broadwell-EP-10 FCLGA2011 Intel(R) Xeon(R) E5-2620 V4 Processor
+ *		https://csrc.nist.gov/projects/cryptographic-module-validation-program/entropy-validations/certificate/87
+ *		(URLs below omitted for brevity but follow same format.)
+ *
+ *	E#121:	Junos OS Physical Entropy Source - Intel Atom C3000 Series
+ *		(Denverton) 16 Core Die with FCBGA1310 Package
+ *
+ *	E#122:	Junos OS Physical Entropy Source - Intel Xeon D-1500 Family
+ *		(Broadwell) 8 Core Die with FCBGA1667 Package
+ *
+ *	E#123:	Junos OS Physical Entropy Source - Intel Xeon D-2100 Series
+ *		(Skylake) 18 Core Die with FCBGA2518 Package
+ *
+ *	E#141:	Junos OS Physical Entropy Source - Intel Xeon D-10 Series
+ *		(Ice Lake-D-10) Die with FCBGA2227 Package
+ *
+ *	E#169:	Junos OS Physical Entropy Source - Intel Xeon AWS-1000 v4 and
+ *		E5 v4 (Broadwell EP) 15 Core Die with FCLGA2011 Package
+ */
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index efe1e7ba3ab6..d877167a7eae 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -347,6 +347,7 @@ SUBDIR=	\
 	rc4 \
 	${_rdma} \
 	${_rdrand_rng} \
+	${_rdseed_rng} \
 	re \
 	rl \
 	${_rockchip} \
@@ -816,6 +817,7 @@ _nvram=		nvram
 _padlock=	padlock
 _padlock_rng=	padlock_rng
 _rdrand_rng=	rdrand_rng
+_rdseed_rng=	rdseed_rng
 .endif
 _pchtherm = pchtherm
 _s3=		s3
diff --git a/sys/modules/rdrand_rng/Makefile b/sys/modules/rdrand_rng/Makefile
index 7fa7a8bb8fb9..496fc863033f 100644
--- a/sys/modules/rdrand_rng/Makefile
+++ b/sys/modules/rdrand_rng/Makefile
@@ -6,9 +6,4 @@ SRCS+=	bus_if.h device_if.h
 
 CFLAGS+= -I${SRCTOP}/sys
 
-# ld.bfd doesn't support ifuncs invoked non-PIC
-.if ${MACHINE_CPUARCH} == "i386"
-CFLAGS.gcc= -fPIC
-.endif
-
 .include <bsd.kmod.mk>
diff --git a/sys/modules/rdseed_rng/Makefile b/sys/modules/rdseed_rng/Makefile
new file mode 100644
index 000000000000..6593505546dd
--- /dev/null
+++ b/sys/modules/rdseed_rng/Makefile
@@ -0,0 +1,9 @@
+.PATH: ${SRCTOP}/sys/dev/random
+
+KMOD=	rdseed_rng
+SRCS=	rdseed.c
+SRCS+=	bus_if.h device_if.h
+
+CFLAGS+= -I${SRCTOP}/sys
+
+.include <bsd.kmod.mk>
diff --git a/sys/sys/random.h b/sys/sys/random.h
index 4dc5b74abe4f..af6b1e117423 100644
--- a/sys/sys/random.h
+++ b/sys/sys/random.h
@@ -93,6 +93,7 @@ enum random_entropy_source {
 	RANDOM_PURE_GLXSB,
 	RANDOM_PURE_HIFN,
 	RANDOM_PURE_RDRAND,
+	RANDOM_PURE_RDSEED,
 	RANDOM_PURE_NEHEMIAH,
 	RANDOM_PURE_RNDTEST,
 	RANDOM_PURE_VIRTIO,