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