NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/54655: cpu_rng_rdseed() should check support of RDRAND instruction



>Number:         54655
>Category:       kern
>Synopsis:       cpu_rng_rdseed() should check support of RDRAND instruction
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Oct 29 14:30:00 +0000 2019
>Originator:     Takahiro Kambe
>Release:        NetBSD 9.0_BETA
>Organization:
Takahiro Kambe
>Environment:
	
	
System: NetBSD 9.0_BETA (SAKURA-VPS4) #26: Tue Oct 29 00:41:42 JST 2019  taca%edge.back-street.net@localhost:/data/netbsd-9/amd64/obj/sys/arch/amd64/compile/SAKURA-VPS4
Architecture: x86_64
Machine: amd64
>Description:
cpu_rng_rdseed() in sys/arch/x86/x86/cpu_rng.c dose not honor support
of RDRAND instruction.

(1) In cpu_earlyrng(), support of RDSEED and RDRAND is checked with
    cpu_feature.

	bool has_rdseed = (cpu_feature[5] & CPUID_SEF_RDSEED) != 0;
	bool has_rdrand = (cpu_feature[1] & CPUID2_RDRAND) != 0;

(2) Then cpu_rng_rdseed() and cpu_rng_rdrand() is called with these
    results:

	if (has_rdseed) {
		for (i = 0; i < 8; i++) {
			if (cpu_rng_rdseed(&buf[i]) == 0) {
...
	} else if (has_rdrand) {
		for (i = 0; i < 8; i++) {
			if (cpu_rng_rdrand(&buf[i]) == 0) {
...

(3) But cpu_rng_rdseed(() may call cpu_rng_rdrand() even if the case of
    has_rdrand is zero.

static size_t
cpu_rng_rdseed(cpu_rng_t *out)
{
	uint8_t rndsts;
	...
	/*
	 * Userspace could have exhausted RDSEED, but the
	 * CPU-internal generator feeding RDRAND is guaranteed
	 * to be seeded even in this case.
	 */
exhausted:
	return cpu_rng_rdrand(out);
}

I don't know is there real CPU supports RDSEED without RDRAND or not.
But there is such a case on VPS service at least.

$ /usr/sbin/cpuctl identify 0 | egrep RD
cpu0: features2 0x28100800<SYSCALL/SYSRET,XD,RDTSCP,EM64T>
cpu0: features5 0x1c07a9<FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,RDSEED,ADX>

I met this problem when updating a host running NetBSD 8.1_STABLE on a VPS
to 9.0_BETA.  After I reported it to NetBSD mailing list in Japanese
(http://www.re.soum.co.jp/~jun/welcome.html#netbsd), Azuma Okamoto told
where the problem (commeting out some lines make kernel work).

Thanks to Azuma Okamoto's examination what changed from NetBSD 8.  Without
his effort, I could not reach here.

>How-To-Repeat:
Boot NetBSD 9.0_BETA cdrom on a VPS (version 4) provided by
<https://vps.sakura.ad.jp>.

>Fix:
Check support of RDRAND in cpu_rng_rdseed():

diff --git a/sys/arch/x86/x86/cpu_rng.c b/sys/arch/x86/x86/cpu_rng.c
index 3b79d768ea..c716eeaa26 100644
--- a/sys/arch/x86/x86/cpu_rng.c
+++ b/sys/arch/x86/x86/cpu_rng.c
@@ -53,6 +53,8 @@ static enum {
 	CPU_RNG_VIA
 } cpu_rng_mode __read_mostly = CPU_RNG_NONE;
 
+static bool has_rdrand;
+
 bool
 cpu_rng_init(void)
 {
@@ -131,7 +133,10 @@ cpu_rng_rdseed(cpu_rng_t *out)
 	 * to be seeded even in this case.
 	 */
 exhausted:
-	return cpu_rng_rdrand(out);
+	if (has_rdrand)
+		return cpu_rng_rdrand(out);
+	else
+		return 0;
 }
 
 static size_t
@@ -213,7 +218,7 @@ cpu_earlyrng(void *out, size_t sz)
 	int i;
 
 	bool has_rdseed = (cpu_feature[5] & CPUID_SEF_RDSEED) != 0;
-	bool has_rdrand = (cpu_feature[1] & CPUID2_RDRAND) != 0;
+	has_rdrand = (cpu_feature[1] & CPUID2_RDRAND) != 0;
 
 	KASSERT(sz + sizeof(uint64_t) <= SHA512_DIGEST_LENGTH);
 

>Unformatted:
 	
 	


Home | Main Index | Thread Index | Old Index