1 // random -*- C++ -*-
2 
3 // Copyright (C) 2012-2021 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 #define _GLIBCXX_USE_CXX11_ABI 1
26 #define _CRT_RAND_S // define this before including <stdlib.h> to get rand_s
27 
28 #include <random>
29 
30 #ifdef  _GLIBCXX_USE_C99_STDINT_TR1
31 
32 #if defined __i386__ || defined __x86_64__
33 # include <cpuid.h>
34 # ifdef _GLIBCXX_X86_RDRAND
35 #  define USE_RDRAND 1
36 # endif
37 # ifdef _GLIBCXX_X86_RDSEED
38 #  define USE_RDSEED 1
39 # endif
40 #endif
41 
42 #include <cerrno>
43 #include <cstdio>
44 #include <cctype> // For std::isdigit.
45 
46 #if defined _GLIBCXX_HAVE_UNISTD_H && defined _GLIBCXX_HAVE_FCNTL_H
47 # include <unistd.h>
48 # include <fcntl.h>
49 // Use POSIX open, close, read etc. instead of ISO fopen, fclose, fread
50 # define USE_POSIX_FILE_IO
51 #endif
52 
53 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
54 # include <sys/ioctl.h>
55 #endif
56 
57 #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H
58 # include <linux/types.h>
59 #endif
60 
61 #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H
62 # include <linux/random.h>
63 #endif
64 
65 #ifdef _GLIBCXX_USE_CRT_RAND_S
66 # include <stdlib.h>
67 #endif
68 
69 #if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM
70 // The OS provides a source of randomness we can use.
71 # pragma GCC poison _M_mt
72 #elif defined USE_RDRAND || defined USE_RDSEED
73 // Hardware instructions might be available, but use cpuid checks at runtime.
74 # pragma GCC poison _M_mt
75 // If the runtime cpuid checks fail we'll use a linear congruential engine.
76 # define USE_LCG 1
77 #else
78 // Use the mt19937 member of the union, as in previous GCC releases.
79 # define USE_MT19937 1
80 #endif
81 
82 #ifdef USE_LCG
83 # include <chrono>
84 #endif
85 
86 namespace std _GLIBCXX_VISIBILITY(default)
87 {
88   namespace
89   {
90 #if USE_RDRAND
91     unsigned int
92     __attribute__ ((target("rdrnd")))
__x86_rdrand(void *)93     __x86_rdrand(void*)
94     {
95       unsigned int retries = 100;
96       unsigned int val;
97 
98       while (__builtin_ia32_rdrand32_step(&val) == 0)
99 	if (--retries == 0)
100 	  std::__throw_runtime_error(__N("random_device: rdrand failed"));
101 
102       return val;
103     }
104 #endif
105 
106 #if USE_RDSEED
107     unsigned int
108     __attribute__ ((target("rdseed")))
__x86_rdseed(void * fallback)109     __x86_rdseed(void* fallback)
110     {
111       unsigned int retries = 100;
112       unsigned int val;
113 
114       while (__builtin_ia32_rdseed_si_step(&val) == 0)
115 	{
116 	  if (--retries == 0)
117 	    {
118 	      if (auto f = reinterpret_cast<unsigned int(*)(void*)>(fallback))
119 		return f(nullptr);
120 	      std::__throw_runtime_error(__N("random_device: rdseed failed"));
121 	    }
122 	  __builtin_ia32_pause();
123 	}
124 
125       return val;
126     }
127 
128 #if USE_RDRAND
129     unsigned int
130     __attribute__ ((target("rdseed,rdrnd")))
__x86_rdseed_rdrand(void *)131     __x86_rdseed_rdrand(void*)
132     {
133       return __x86_rdseed(reinterpret_cast<void*>(&__x86_rdrand));
134     }
135 #endif
136 #endif
137 
138 #ifdef _GLIBCXX_USE_CRT_RAND_S
139     unsigned int
__winxp_rand_s(void *)140     __winxp_rand_s(void*)
141     {
142       unsigned int val;
143       if (::rand_s(&val) != 0)
144 	std::__throw_runtime_error(__N("random_device: rand_s failed"));
145       return val;
146     }
147 #endif
148 
149 #ifdef USE_LCG
150     // TODO: use this to seed std::mt19937 engine too.
151     unsigned
bad_seed(void * p)152     bad_seed(void* p) noexcept
153     {
154       // Poor quality seed based on hash of the current time and the address
155       // of the object being seeded. Better than using the same default seed
156       // for every object though.
157       const uint64_t bits[] = {
158 	(uint64_t) chrono::system_clock::now().time_since_epoch().count(),
159 	(uint64_t) reinterpret_cast<uintptr_t>(p)
160       };
161       auto bytes = reinterpret_cast<const unsigned char*>(bits);
162       // 32-bit FNV-1a hash
163       uint32_t h = 2166136261u;
164       for (unsigned i = 0; i < sizeof(bits); ++i)
165 	{
166 	  h ^= *bytes++;
167 	  h *= 16777619u;
168 	}
169       return h;
170     }
171 
172     // Same as std::minstd_rand0 but using unsigned not uint_fast32_t.
173     using lcg_type
174       = linear_congruential_engine<unsigned, 16807UL, 0UL, 2147483647UL>;
175 
176     inline lcg_type*
construct_lcg_at(void * addr)177     construct_lcg_at(void* addr) noexcept
178     {
179       return ::new(addr) lcg_type(bad_seed(addr));
180     }
181 
182     inline void
destroy_lcg_at(void * addr)183     destroy_lcg_at(void* addr) noexcept
184     {
185       static_cast<lcg_type*>(addr)->~lcg_type();
186     }
187 
188     unsigned int
__lcg(void * ptr)189     __lcg(void* ptr) noexcept
190     {
191       auto& lcg = *static_cast<lcg_type*>(ptr);
192       return lcg();
193     }
194 #endif
195   }
196 
197   void
_M_init(const std::string & token)198   random_device::_M_init(const std::string& token)
199   {
200 #ifdef USE_MT19937
201     // If no real random device is supported then use the mt19937 engine.
202     _M_init_pretr1(token);
203     return;
204 #else
205 
206     _M_file = nullptr;
207     _M_func = nullptr;
208     _M_fd = -1;
209 
210     const char* fname [[gnu::unused]] = nullptr;
211 
212     enum {
213 	rand_s = 1, rdseed = 2, rdrand = 4, device_file = 8, prng = 16,
214 	any = 0xffff
215     } which;
216 
217     if (token == "default")
218       {
219 	which = any;
220 	fname = "/dev/urandom";
221       }
222 #ifdef USE_RDSEED
223     else if (token == "rdseed")
224       which = rdseed;
225 #endif // USE_RDSEED
226 #ifdef USE_RDRAND
227     else if (token == "rdrand" || token == "rdrnd")
228       which = rdrand;
229 #endif // USE_RDRAND
230 #ifdef _GLIBCXX_USE_CRT_RAND_S
231     else if (token == "rand_s")
232       which = rand_s;
233 #endif // _GLIBCXX_USE_CRT_RAND_S
234 #ifdef _GLIBCXX_USE_DEV_RANDOM
235     else if (token == "/dev/urandom" || token == "/dev/random")
236       {
237 	fname = token.c_str();
238 	which = device_file;
239       }
240 #endif // _GLIBCXX_USE_DEV_RANDOM
241 #ifdef USE_LCG
242     else if (token == "prng")
243       which = prng;
244 #endif
245     else
246       std::__throw_runtime_error(
247 	  __N("random_device::random_device(const std::string&):"
248 	      " unsupported token"));
249 
250 #ifdef _GLIBCXX_USE_CRT_RAND_S
251     if (which & rand_s)
252     {
253       _M_func = &__winxp_rand_s;
254       return;
255     }
256 #endif // _GLIBCXX_USE_CRT_RAND_S
257 
258 #ifdef USE_RDSEED
259     if (which & rdseed)
260     {
261       unsigned int eax, ebx, ecx, edx;
262       // Check availability of cpuid and, for now at least, also the
263       // CPU signature for Intel and AMD.
264       if (__get_cpuid_max(0, &ebx) > 0
265 	  && (ebx == signature_INTEL_ebx || ebx == signature_AMD_ebx))
266 	{
267 	  // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18]
268 	  __cpuid_count(7, 0, eax, ebx, ecx, edx);
269 	  if (ebx & bit_RDSEED)
270 	    {
271 #ifdef USE_RDRAND
272 	      // CPUID.01H:ECX.RDRAND[bit 30]
273 	      __cpuid(1, eax, ebx, ecx, edx);
274 	      if (ecx & bit_RDRND)
275 		{
276 		  _M_func = &__x86_rdseed_rdrand;
277 		  return;
278 		}
279 #endif
280 	      _M_func = &__x86_rdseed;
281 	      return;
282 	    }
283 	}
284     }
285 #endif // USE_RDSEED
286 
287 #ifdef USE_RDRAND
288     if (which & rdrand)
289     {
290       unsigned int eax, ebx, ecx, edx;
291       // Check availability of cpuid and, for now at least, also the
292       // CPU signature for Intel and AMD.
293       if (__get_cpuid_max(0, &ebx) > 0
294 	  && (ebx == signature_INTEL_ebx || ebx == signature_AMD_ebx))
295 	{
296 	  // CPUID.01H:ECX.RDRAND[bit 30]
297 	  __cpuid(1, eax, ebx, ecx, edx);
298 	  if (ecx & bit_RDRND)
299 	    {
300 	      _M_func = &__x86_rdrand;
301 	      return;
302 	    }
303 	}
304     }
305 #endif // USE_RDRAND
306 
307 #ifdef _GLIBCXX_USE_DEV_RANDOM
308     if (which & device_file)
309     {
310 #ifdef USE_POSIX_FILE_IO
311       _M_fd = ::open(fname, O_RDONLY);
312       if (_M_fd != -1)
313 	{
314 	  // Set _M_file to non-null so that _M_fini() will do clean up.
315 	  _M_file = &_M_fd;
316 	  return;
317 	}
318 #else // USE_POSIX_FILE_IO
319       _M_file = static_cast<void*>(std::fopen(fname, "rb"));
320       if (_M_file)
321 	return;
322 #endif // USE_POSIX_FILE_IO
323     }
324 #endif // _GLIBCXX_USE_DEV_RANDOM
325 
326 #ifdef USE_LCG
327     // Either "prng" was requested explicitly, or "default" was requested
328     // but nothing above worked, use a PRNG.
329     if (which & prng)
330     {
331       static_assert(sizeof(lcg_type) <= sizeof(_M_fd), "");
332       static_assert(alignof(lcg_type) <= alignof(_M_fd), "");
333       _M_file = construct_lcg_at(&_M_fd);
334       _M_func = &__lcg;
335       return;
336     }
337 #endif
338 
339     std::__throw_runtime_error(
340 	__N("random_device::random_device(const std::string&):"
341 	    " device not available"));
342 #endif // USE_MT19937
343   }
344 
345   // This function is called by _M_init for targets that use mt19937 for
346   // randomness, and by code compiled against old releases of libstdc++.
347   void
_M_init_pretr1(const std::string & token)348   random_device::_M_init_pretr1(const std::string& token)
349   {
350 #ifdef USE_MT19937
351     unsigned long seed = 5489UL;
352     if (token != "default" && token != "mt19937" && token != "prng")
353       {
354 	const char* nptr = token.c_str();
355 	char* endptr;
356 	seed = std::strtoul(nptr, &endptr, 0);
357 	if (*nptr == '\0' || *endptr != '\0')
358 	  std::__throw_runtime_error(__N("random_device::_M_init_pretr1"
359 					 "(const std::string&)"));
360       }
361     _M_mt.seed(seed);
362 #else
363     // Convert old default token "mt19937" or numeric seed tokens to "default".
364     if (token == "mt19937" || std::isdigit((unsigned char)token[0]))
365       _M_init("default");
366     else
367       _M_init(token);
368 #endif
369   }
370 
371   // Called by old ABI version of random_device::_M_init(const std::string&).
372   void
_M_init(const char * s,size_t len)373   random_device::_M_init(const char* s, size_t len)
374   {
375     const std::string token(s, len);
376 #ifdef USE_MT19937
377     _M_init_pretr1(token);
378 #else
379     _M_init(token);
380 #endif
381   }
382 
383   void
_M_fini()384   random_device::_M_fini()
385   {
386     // _M_file == nullptr means no resources to free.
387     if (!_M_file)
388       return;
389 
390 #if USE_LCG
391     if (_M_func == &__lcg)
392       {
393 	destroy_lcg_at(_M_file);
394 	return;
395       }
396 #endif
397 
398 #ifdef USE_POSIX_FILE_IO
399     ::close(_M_fd);
400     _M_fd = -1;
401 #else
402     std::fclose(static_cast<FILE*>(_M_file));
403 #endif
404     _M_file = nullptr;
405   }
406 
407   random_device::result_type
_M_getval()408   random_device::_M_getval()
409   {
410 #ifdef USE_MT19937
411     return _M_mt();
412 #else
413 
414     if (_M_func)
415       return _M_func(_M_file);
416 
417     result_type ret;
418     void* p = &ret;
419     size_t n = sizeof(result_type);
420 #ifdef USE_POSIX_FILE_IO
421     do
422       {
423 	const int e = ::read(_M_fd, p, n);
424 	if (e > 0)
425 	  {
426 	    n -= e;
427 	    p = static_cast<char*>(p) + e;
428 	  }
429 	else if (e != -1 || errno != EINTR)
430 	  __throw_runtime_error(__N("random_device could not be read"));
431       }
432     while (n > 0);
433 #else // USE_POSIX_FILE_IO
434     const size_t e = std::fread(p, n, 1, static_cast<FILE*>(_M_file));
435     if (e != 1)
436       __throw_runtime_error(__N("random_device could not be read"));
437 #endif // USE_POSIX_FILE_IO
438 
439     return ret;
440 #endif // USE_MT19937
441   }
442 
443   // Only called by code compiled against old releases of libstdc++.
444   // Forward the call to _M_getval() and let it decide what to do.
445   random_device::result_type
_M_getval_pretr1()446   random_device::_M_getval_pretr1()
447   { return _M_getval(); }
448 
449   double
_M_getentropy() const450   random_device::_M_getentropy() const noexcept
451   {
452 #if defined _GLIBCXX_USE_DEV_RANDOM \
453     && defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT
454     if (!_M_file)
455       return 0.0;
456 
457 #ifdef USE_POSIX_FILE_IO
458     const int fd = _M_fd;
459 #else
460     const int fd = ::fileno(static_cast<FILE*>(_M_file));
461 #endif
462     if (fd < 0)
463       return 0.0;
464 
465     int ent;
466     if (::ioctl(fd, RNDGETENTCNT, &ent) < 0)
467       return 0.0;
468 
469     if (ent < 0)
470       return 0.0;
471 
472     const int max = sizeof(result_type) * __CHAR_BIT__;
473     if (ent > max)
474       ent = max;
475 
476     return static_cast<double>(ent);
477 #else
478     return 0.0;
479 #endif // _GLIBCXX_USE_DEV_RANDOM && _GLIBCXX_HAVE_SYS_IOCTL_H && RNDGETENTCNT
480   }
481 
482 #ifdef USE_MT19937
483   template class mersenne_twister_engine<
484     uint_fast32_t,
485     32, 624, 397, 31,
486     0x9908b0dfUL, 11,
487     0xffffffffUL, 7,
488     0x9d2c5680UL, 15,
489     0xefc60000UL, 18, 1812433253UL>;
490 #endif // USE_MT19937
491 
492 #ifdef USE_LCG
493   template class
494     linear_congruential_engine<unsigned, 16807UL, 0UL, 2147483647UL>;
495   template struct __detail::_Mod<unsigned, 2147483647UL, 16807UL, 0UL>;
496 #endif
497 }
498 #endif // _GLIBCXX_USE_C99_STDINT_TR1
499