1 /* $NetBSD: cpu_rng.c,v 1.23 2024/08/01 11:18:54 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Thor Lancelot Simon. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * For reference on VIA XSTORERNG, see the VIA PadLock Programming 34 * Guide (`VIA PPG'), August 4, 2005. 35 * https://web.archive.org/web/20210322141743/http://linux.via.com.tw/support/beginDownload.action?eleid=181&fid=261 36 * 37 * For reference on Intel RDRAND/RDSEED, see the Intel Digital Random 38 * Number Generator Software Implementation Guide (`Intel DRNG SIG'), 39 * Revision 2.1, October 17, 2018. 40 * https://web.archive.org/web/20200505093404/https://software.intel.com/sites/default/files/managed/98/4a/DRNG_Software_Implementation_Guide_2.1.pdf 41 * 42 * Intel's hardware implementation is analyzed by Mike Hamburg, Paul 43 * Kocher, and Mark E. Marson, `Analysis of Intel's Ivy Bridge Digital 44 * Random Number Generator', Cryptography Research, Inc., March 12, 45 * 2012. 46 * https://web.archive.org/web/20141230024150/http://www.cryptography.com/public/pdf/Intel_TRNG_Report_20120312.pdf 47 * 48 * For reference on AMD RDRAND/RDSEED, which are designed to be 49 * compatible with Intel RDRAND/RDSEED, see the somewhat less detailed 50 * AMD Random Number Generator documentation, 2017-06-27. 51 * https://web.archive.org/web/20220402133945/https://www.amd.com/system/files/TechDocs/amd-random-number-generator.pdf 52 */ 53 54 #include <sys/param.h> 55 #include <sys/systm.h> 56 #include <sys/cpu.h> 57 #include <sys/rndsource.h> 58 #include <sys/sha2.h> 59 60 #include <x86/specialreg.h> 61 62 #include <machine/cpufunc.h> 63 #include <machine/cpuvar.h> 64 #include <machine/cpu_rng.h> 65 #include <machine/limits.h> 66 67 static enum cpu_rng_mode { 68 CPU_RNG_NONE = 0, 69 CPU_RNG_RDRAND, 70 CPU_RNG_RDSEED, 71 CPU_RNG_RDSEED_RDRAND, 72 CPU_RNG_VIA 73 } cpu_rng_mode __read_mostly = CPU_RNG_NONE; 74 75 static const char *const cpu_rng_name[] = { 76 [CPU_RNG_RDRAND] = "rdrand", 77 [CPU_RNG_RDSEED] = "rdseed", 78 [CPU_RNG_RDSEED_RDRAND] = "rdrand/rdseed", 79 [CPU_RNG_VIA] = "via", 80 }; 81 82 static struct krndsource cpu_rng_source __read_mostly; 83 84 static enum cpu_rng_mode 85 cpu_rng_detect(void) 86 { 87 bool has_rdseed = (cpu_feature[5] & CPUID_SEF_RDSEED); 88 bool has_rdrand = (cpu_feature[1] & CPUID2_RDRAND); 89 bool has_viarng = (cpu_feature[4] & CPUID_VIA_HAS_RNG); 90 91 if (has_rdseed && has_rdrand) 92 return CPU_RNG_RDSEED_RDRAND; 93 else if (has_rdseed) 94 return CPU_RNG_RDSEED; 95 else if (has_rdrand) 96 return CPU_RNG_RDRAND; 97 else if (has_viarng) 98 return CPU_RNG_VIA; 99 else 100 return CPU_RNG_NONE; 101 } 102 103 static size_t 104 cpu_rng_rdrand(uint64_t *out) 105 { 106 uint8_t rndsts; 107 108 /* 109 * XXX The Intel DRNG SIG recommends (Sec. 5.2.1 `Retry 110 * recommendations', p. 22) that we retry up to ten times 111 * before giving up and panicking because something must be 112 * seriously awry with the CPU. 113 * 114 * XXX The Intel DRNG SIG also recommends (Sec. 5.2.6 115 * `Generating Seeds from RDRAND', p. 28) drawing 1024 64-bit 116 * samples (or, 512 128-bit samples) in order to guarantee that 117 * the CPU has drawn an independent sample from the physical 118 * entropy source, since the AES CTR_DRBG behind RDRAND will be 119 * used to generate at most 511 128-bit samples before it is 120 * reseeded from the physical entropy source. It is unclear 121 * whether the same considerations about RDSEED starvation 122 * apply to this advice. 123 */ 124 125 #ifdef __i386__ 126 uint32_t lo, hi; 127 128 __asm __volatile("rdrand %0; setc %1" : "=r"(lo), "=qm"(rndsts)); 129 if (rndsts != 1) 130 return 0; 131 __asm __volatile("rdrand %0; setc %1" : "=r"(hi), "=qm"(rndsts)); 132 133 *out = (uint64_t)lo | ((uint64_t)hi << 32); 134 explicit_memset(&lo, 0, sizeof(lo)); 135 explicit_memset(&hi, 0, sizeof(hi)); 136 if (rndsts != 1) 137 return sizeof(lo) * NBBY; 138 #else 139 __asm __volatile("rdrand %0; setc %1" : "=r"(*out), "=qm"(rndsts)); 140 if (rndsts != 1) 141 return 0; 142 #endif 143 return sizeof(*out) * NBBY; 144 } 145 146 static size_t 147 cpu_rng_rdseed(uint64_t *out) 148 { 149 uint8_t rndsts; 150 151 /* 152 * XXX The Intel DRNG SIG recommends (Sec. 5.3.1 `Retry 153 * recommendations', p. 22) that we consider retrying up to 100 154 * times, separated by PAUSE, but offers no guarantees about 155 * success after that many retries. In particular, userland 156 * threads could starve the kernel by issuing RDSEED. 157 */ 158 159 #ifdef __i386__ 160 uint32_t lo, hi; 161 162 __asm __volatile("rdseed %0; setc %1" : "=r"(lo), "=qm"(rndsts)); 163 if (rndsts != 1) 164 return 0; 165 __asm __volatile("rdseed %0; setc %1" : "=r"(hi), "=qm"(rndsts)); 166 if (rndsts != 1) 167 return 0; 168 169 *out = (uint64_t)lo | ((uint64_t)hi << 32); 170 explicit_memset(&lo, 0, sizeof(lo)); 171 explicit_memset(&hi, 0, sizeof(hi)); 172 #else 173 __asm __volatile("rdseed %0; setc %1" : "=r"(*out), "=qm"(rndsts)); 174 #endif 175 if (rndsts != 1) 176 return 0; 177 178 return sizeof(*out) * NBBY; 179 } 180 181 static size_t 182 cpu_rng_rdseed_rdrand(uint64_t *out) 183 { 184 size_t n = cpu_rng_rdseed(out); 185 186 if (n == 0) 187 n = cpu_rng_rdrand(out); 188 189 return n; 190 } 191 192 /* 193 * VIA PPG says EAX[4:0] is nbytes, but the only documented numbers of 194 * bytes are 0,1,2,4,8 -- and there's only 8 bytes of output buffer 195 * anyway, so let's ignore bit 4 and treat it like EAX[3:0] instead. 196 */ 197 #define VIA_RNG_STATUS_NBYTES __BITS(3,0) 198 #define VIA_RNG_STATUS_MSR110B __BITS(31,5) 199 200 static size_t 201 cpu_rng_via(uint64_t *out) 202 { 203 u_long psl; 204 uint32_t cr0, status, nbytes; 205 206 /* 207 * The XSTORE instruction is handled by the SSE unit, which 208 * requires the CR0 TS and CR0 EM bits to be clear. We disable 209 * all processor interrupts so there is no danger of any 210 * interrupt handler changing CR0 while we work -- although 211 * really, software splvm or fpu_kern_enter/leave should be 212 * enough (but we'll do that in a separate change for the 213 * benefit of bisection in case I'm wrong). 214 */ 215 psl = x86_read_psl(); 216 x86_disable_intr(); 217 cr0 = rcr0(); 218 lcr0(cr0 & ~(CR0_EM|CR0_TS)); 219 220 /* Read up to eight bytes out of the buffer. */ 221 asm volatile("xstorerng" 222 : "=a"(status) 223 : "D"(out), "d"(0) /* EDX[1:0]=00 -> wait for 8 bytes or fail */ 224 : "memory"); 225 226 /* Restore CR0 and interrupts. */ 227 lcr0(cr0); 228 x86_write_psl(psl); 229 230 /* Get the number of bytes stored. (Should always be 8 or 0.) */ 231 nbytes = __SHIFTOUT(status, VIA_RNG_STATUS_NBYTES); 232 233 /* 234 * The Cryptography Research paper on the VIA RNG estimates 235 * 0.75 bits of entropy per output bit and advises users to 236 * be "even more conservative". 237 * 238 * `Evaluation of VIA C3 Nehemiah Random Number 239 * Generator', Cryptography Research, Inc., February 27, 240 * 2003. 241 * https://www.rambus.com/wp-content/uploads/2015/08/VIA_rng.pdf 242 */ 243 return nbytes * NBBY/2; 244 } 245 246 static size_t 247 cpu_rng(enum cpu_rng_mode mode, uint64_t *out) 248 { 249 250 switch (mode) { 251 case CPU_RNG_NONE: 252 return 0; 253 case CPU_RNG_RDSEED: 254 return cpu_rng_rdseed(out); 255 case CPU_RNG_RDRAND: 256 return cpu_rng_rdrand(out); 257 case CPU_RNG_RDSEED_RDRAND: 258 return cpu_rng_rdseed_rdrand(out); 259 case CPU_RNG_VIA: 260 return cpu_rng_via(out); 261 default: 262 panic("cpu_rng: unknown mode %d", (int)mode); 263 } 264 } 265 266 static void 267 cpu_rng_get(size_t nbytes, void *cookie) 268 { 269 enum { 270 NBITS = 256, 271 NBYTES = howmany(NBITS, 8), 272 NWORDS = howmany(NBITS, 64), 273 }; 274 uint64_t buf[2*NWORDS]; 275 unsigned i, nbits = 0; 276 277 while (nbytes) { 278 /* 279 * The fraction of outputs this rejects in correct 280 * operation is 1/2^256, which is close enough to zero 281 * that we round it to having no effect on the number 282 * of bits of entropy. 283 */ 284 for (i = 0; i < __arraycount(buf); i++) 285 nbits += cpu_rng(cpu_rng_mode, &buf[i]); 286 if (consttime_memequal(buf, buf + NWORDS, NBYTES)) { 287 printf("cpu_rng %s: failed repetition test\n", 288 cpu_rng_name[cpu_rng_mode]); 289 nbits = 0; 290 } 291 rnd_add_data_sync(&cpu_rng_source, buf, sizeof buf, nbits); 292 nbytes -= MIN(MIN(nbytes, sizeof buf), MAX(1, 8*nbits)); 293 } 294 } 295 296 void 297 cpu_rng_init(void) 298 { 299 300 cpu_rng_mode = cpu_rng_detect(); 301 if (cpu_rng_mode == CPU_RNG_NONE) 302 return; 303 aprint_normal("cpu_rng: %s\n", cpu_rng_name[cpu_rng_mode]); 304 rndsource_setcb(&cpu_rng_source, cpu_rng_get, NULL); 305 rnd_attach_source(&cpu_rng_source, cpu_rng_name[cpu_rng_mode], 306 RND_TYPE_RNG, RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB); 307 } 308 309 /* -------------------------------------------------------------------------- */ 310 311 void 312 cpu_rng_early_sample(uint64_t *sample) 313 { 314 static bool has_rdseed = false; 315 static bool has_rdrand = false; 316 static bool inited = false; 317 u_int descs[4]; 318 size_t n; 319 320 if (!inited) { 321 if (cpuid_level >= 7) { 322 x86_cpuid(0x07, descs); 323 has_rdseed = (descs[1] & CPUID_SEF_RDSEED) != 0; 324 } 325 if (cpuid_level >= 1) { 326 x86_cpuid(0x01, descs); 327 has_rdrand = (descs[2] & CPUID2_RDRAND) != 0; 328 } 329 inited = true; 330 } 331 332 n = 0; 333 if (has_rdseed && has_rdrand) 334 n = cpu_rng_rdseed_rdrand(sample); 335 else if (has_rdseed) 336 n = cpu_rng_rdseed(sample); 337 else if (has_rdrand) 338 n = cpu_rng_rdrand(sample); 339 if (n == 0) 340 *sample = rdtsc(); 341 } 342