Bitcoin ABC  0.24.7
P2P Digital Currency
randomenv.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #if defined(HAVE_CONFIG_H)
7 #include <config/bitcoin-config.h>
8 #endif
9 
10 #include <randomenv.h>
11 
12 #include <clientversion.h>
13 #include <compat/cpuid.h>
14 #include <support/cleanse.h>
15 #include <util/time.h> // for GetTime()
16 #ifdef WIN32
17 #include <compat.h> // for Windows API
18 #endif
19 
20 #include <algorithm>
21 #include <atomic>
22 #include <chrono>
23 #include <climits>
24 #include <thread>
25 #include <vector>
26 
27 #include <cstdint>
28 #include <cstring>
29 #ifndef WIN32
30 #include <sys/types.h> // must go before a number of other headers
31 
32 #include <fcntl.h>
33 #include <netinet/in.h>
34 #include <sys/resource.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/utsname.h>
39 #include <unistd.h>
40 #endif
41 #if HAVE_DECL_GETIFADDRS
42 #include <ifaddrs.h>
43 #endif
44 #if HAVE_SYSCTL
45 #include <sys/sysctl.h>
46 #if HAVE_VM_VM_PARAM_H
47 #include <vm/vm_param.h>
48 #endif
49 #if HAVE_SYS_RESOURCES_H
50 #include <sys/resources.h>
51 #endif
52 #if HAVE_SYS_VMMETER_H
53 #include <sys/vmmeter.h>
54 #endif
55 #endif
56 #ifdef __linux__
57 #include <sys/auxv.h>
58 #endif
59 
61 extern char **environ;
62 
63 namespace {
64 void RandAddSeedPerfmon(CSHA512 &hasher) {
65 #ifdef WIN32
66  // Seed with the entire set of perfmon data
67 
68  // This can take up to 2 seconds, so only do it every 10 minutes.
69  // Initialize last_perfmon to 0 seconds, we don't skip the first call.
70  static std::atomic<std::chrono::seconds> last_perfmon{
71  std::chrono::seconds{0}};
72  auto last_time = last_perfmon.load();
73  auto current_time = GetTime<std::chrono::seconds>();
74  if (current_time < last_time + std::chrono::minutes{10}) {
75  return;
76  }
77  last_perfmon = current_time;
78 
79  std::vector<uint8_t> vData(250000, 0);
80  long ret = 0;
81  unsigned long nSize = 0;
82  // Bail out at more than 10MB of performance data
83  const size_t nMaxSize = 10000000;
84  while (true) {
85  nSize = vData.size();
86  ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", nullptr,
87  nullptr, vData.data(), &nSize);
88  if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize) {
89  break;
90  }
91  // Grow size of buffer exponentially
92  vData.resize(std::min((vData.size() * 3) / 2, nMaxSize));
93  }
94  RegCloseKey(HKEY_PERFORMANCE_DATA);
95  if (ret == ERROR_SUCCESS) {
96  hasher.Write(vData.data(), nSize);
97  memory_cleanse(vData.data(), nSize);
98  } else {
99  // Performance data is only a best-effort attempt at improving the
100  // situation when the OS randomness (and other sources) aren't
101  // adequate. As a result, failure to read it is isn't considered
102  // critical, so we don't call RandFailure().
103  // TODO: Add logging when the logger is made functional before global
104  // constructors have been invoked.
105  }
106 #endif
107 }
108 
114 template <typename T> CSHA512 &operator<<(CSHA512 &hasher, const T &data) {
115  static_assert(
116  !std::is_same<typename std::decay<T>::type, char *>::value,
117  "Calling operator<<(CSHA512, char*) is probably not what you want");
118  static_assert(
119  !std::is_same<typename std::decay<T>::type, uint8_t *>::value,
120  "Calling operator<<(CSHA512, uint8_t*) is probably not what you "
121  "want");
122  static_assert(
123  !std::is_same<typename std::decay<T>::type, const char *>::value,
124  "Calling operator<<(CSHA512, const char*) is probably not what you "
125  "want");
126  static_assert(
127  !std::is_same<typename std::decay<T>::type, const uint8_t *>::value,
128  "Calling operator<<(CSHA512, const uint8_t*) is "
129  "probably not what you want");
130  hasher.Write((const uint8_t *)&data, sizeof(data));
131  return hasher;
132 }
133 
134 #ifndef WIN32
135 void AddSockaddr(CSHA512 &hasher, const struct sockaddr *addr) {
136  if (addr == nullptr) {
137  return;
138  }
139  switch (addr->sa_family) {
140  case AF_INET:
141  hasher.Write((const uint8_t *)addr, sizeof(sockaddr_in));
142  break;
143  case AF_INET6:
144  hasher.Write((const uint8_t *)addr, sizeof(sockaddr_in6));
145  break;
146  default:
147  hasher.Write((const uint8_t *)&addr->sa_family,
148  sizeof(addr->sa_family));
149  }
150 }
151 
152 void AddFile(CSHA512 &hasher, const char *path) {
153  struct stat sb = {};
154  int f = open(path, O_RDONLY);
155  size_t total = 0;
156  if (f != -1) {
157  uint8_t fbuf[4096];
158  int n;
159  hasher.Write((const uint8_t *)&f, sizeof(f));
160  if (fstat(f, &sb) == 0) {
161  hasher << sb;
162  }
163  do {
164  n = read(f, fbuf, sizeof(fbuf));
165  if (n > 0) {
166  hasher.Write(fbuf, n);
167  }
168  total += n;
169  /* not bothering with EINTR handling. */
170  } while (n == sizeof(fbuf) &&
171  total < 1048576); // Read only the first 1 Mbyte
172  close(f);
173  }
174 }
175 
176 void AddPath(CSHA512 &hasher, const char *path) {
177  struct stat sb = {};
178  if (stat(path, &sb) == 0) {
179  hasher.Write((const uint8_t *)path, strlen(path) + 1);
180  hasher << sb;
181  }
182 }
183 #endif
184 
185 #if HAVE_SYSCTL
186 template <int... S> void AddSysctl(CSHA512 &hasher) {
187  int CTL[sizeof...(S)] = {S...};
188  uint8_t buffer[65536];
189  size_t siz = 65536;
190  int ret = sysctl(CTL, sizeof...(S), buffer, &siz, nullptr, 0);
191  if (ret == 0 || (ret == -1 && errno == ENOMEM)) {
192  hasher << sizeof(CTL);
193  hasher.Write((const uint8_t *)CTL, sizeof(CTL));
194  if (siz > sizeof(buffer)) {
195  siz = sizeof(buffer);
196  }
197  hasher << siz;
198  hasher.Write(buffer, siz);
199  }
200 }
201 #endif
202 
203 #ifdef HAVE_GETCPUID
204 void inline AddCPUID(CSHA512 &hasher, uint32_t leaf, uint32_t subleaf,
205  uint32_t &ax, uint32_t &bx, uint32_t &cx, uint32_t &dx) {
206  GetCPUID(leaf, subleaf, ax, bx, cx, dx);
207  hasher << leaf << subleaf << ax << bx << cx << dx;
208 }
209 
210 void AddAllCPUID(CSHA512 &hasher) {
211  uint32_t ax, bx, cx, dx;
212  // Iterate over all standard leaves
213  // Returns max leaf in ax
214  AddCPUID(hasher, 0, 0, ax, bx, cx, dx);
215  uint32_t max = ax;
216  for (uint32_t leaf = 1; leaf <= max && leaf <= 0xFF; ++leaf) {
217  uint32_t maxsub = 0;
218  for (uint32_t subleaf = 0; subleaf <= 0xFF; ++subleaf) {
219  AddCPUID(hasher, leaf, subleaf, ax, bx, cx, dx);
220  // Iterate subleafs for leaf values 4, 7, 11, 13
221  if (leaf == 4) {
222  if ((ax & 0x1f) == 0) {
223  break;
224  }
225  } else if (leaf == 7) {
226  if (subleaf == 0) {
227  maxsub = ax;
228  }
229  if (subleaf == maxsub) {
230  break;
231  }
232  } else if (leaf == 11) {
233  if ((cx & 0xff00) == 0) {
234  break;
235  }
236  } else if (leaf == 13) {
237  if (ax == 0 && bx == 0 && cx == 0 && dx == 0) {
238  break;
239  }
240  } else {
241  // For any other leaf, stop after subleaf 0.
242  break;
243  }
244  }
245  }
246  // Iterate over all extended leaves
247  // Returns max extended leaf in ax
248  AddCPUID(hasher, 0x80000000, 0, ax, bx, cx, dx);
249  uint32_t ext_max = ax;
250  for (uint32_t leaf = 0x80000001; leaf <= ext_max && leaf <= 0x800000FF;
251  ++leaf) {
252  AddCPUID(hasher, leaf, 0, ax, bx, cx, dx);
253  }
254 }
255 #endif
256 } // namespace
257 
258 void RandAddDynamicEnv(CSHA512 &hasher) {
259  RandAddSeedPerfmon(hasher);
260 
261  // Various clocks
262 #ifdef WIN32
263  FILETIME ftime;
264  GetSystemTimeAsFileTime(&ftime);
265  hasher << ftime;
266 #else
267  struct timespec ts = {};
268 #ifdef CLOCK_MONOTONIC
269  clock_gettime(CLOCK_MONOTONIC, &ts);
270  hasher << ts;
271 #endif
272 #ifdef CLOCK_REALTIME
273  clock_gettime(CLOCK_REALTIME, &ts);
274  hasher << ts;
275 #endif
276 #ifdef CLOCK_BOOTTIME
277  clock_gettime(CLOCK_BOOTTIME, &ts);
278  hasher << ts.tv_sec << ts.tv_nsec;
279 #endif
280  // gettimeofday is available on all UNIX systems, but only has microsecond
281  // precision.
282  struct timeval tv = {};
283  gettimeofday(&tv, nullptr);
284  hasher << tv;
285 #endif
286  // Probably redundant, but also use all the clocks C++11 provides:
287  hasher << std::chrono::system_clock::now().time_since_epoch().count();
288  hasher << std::chrono::steady_clock::now().time_since_epoch().count();
289  hasher
290  << std::chrono::high_resolution_clock::now().time_since_epoch().count();
291 
292 #ifndef WIN32
293  // Current resource usage.
294  struct rusage usage = {};
295  if (getrusage(RUSAGE_SELF, &usage) == 0) {
296  hasher << usage;
297  }
298 #endif
299 
300 #ifdef __linux__
301  AddFile(hasher, "/proc/diskstats");
302  AddFile(hasher, "/proc/vmstat");
303  AddFile(hasher, "/proc/schedstat");
304  AddFile(hasher, "/proc/zoneinfo");
305  AddFile(hasher, "/proc/meminfo");
306  AddFile(hasher, "/proc/softirqs");
307  AddFile(hasher, "/proc/stat");
308  AddFile(hasher, "/proc/self/schedstat");
309  AddFile(hasher, "/proc/self/status");
310 #endif
311 
312 #if HAVE_SYSCTL
313 #ifdef CTL_KERN
314 #if defined(KERN_PROC) && defined(KERN_PROC_ALL)
315  AddSysctl<CTL_KERN, KERN_PROC, KERN_PROC_ALL>(hasher);
316 #endif
317 #endif
318 #ifdef CTL_HW
319 #ifdef HW_DISKSTATS
320  AddSysctl<CTL_HW, HW_DISKSTATS>(hasher);
321 #endif
322 #endif
323 #ifdef CTL_VM
324 #ifdef VM_LOADAVG
325  AddSysctl<CTL_VM, VM_LOADAVG>(hasher);
326 #endif
327 #ifdef VM_TOTAL
328  AddSysctl<CTL_VM, VM_TOTAL>(hasher);
329 #endif
330 #ifdef VM_METER
331  AddSysctl<CTL_VM, VM_METER>(hasher);
332 #endif
333 #endif
334 #endif
335 
336  // Stack and heap location
337  void *addr = malloc(4097);
338  hasher << &addr << addr;
339  free(addr);
340 }
341 
342 void RandAddStaticEnv(CSHA512 &hasher) {
343  // Some compile-time static properties
344  hasher << (CHAR_MIN < 0) << sizeof(void *) << sizeof(long) << sizeof(int);
345 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
346  hasher << __GNUC__ << __GNUC_MINOR__ << __GNUC_PATCHLEVEL__;
347 #endif
348 #ifdef _MSC_VER
349  hasher << _MSC_VER;
350 #endif
351  hasher << __cplusplus;
352 #ifdef _XOPEN_VERSION
353  hasher << _XOPEN_VERSION;
354 #endif
355 #ifdef __VERSION__
356  const char *COMPILER_VERSION = __VERSION__;
357  hasher.Write((const uint8_t *)COMPILER_VERSION,
358  strlen(COMPILER_VERSION) + 1);
359 #endif
360 
361  // Bitcoin client version
362  hasher << CLIENT_VERSION;
363 
364 #ifdef __linux__
365  // Information available through getauxval()
366 #ifdef AT_HWCAP
367  hasher << getauxval(AT_HWCAP);
368 #endif
369 #ifdef AT_HWCAP2
370  hasher << getauxval(AT_HWCAP2);
371 #endif
372 #ifdef AT_RANDOM
373  const uint8_t *random_aux = (const uint8_t *)getauxval(AT_RANDOM);
374  if (random_aux) {
375  hasher.Write(random_aux, 16);
376  }
377 #endif
378 #ifdef AT_PLATFORM
379  const char *platform_str = (const char *)getauxval(AT_PLATFORM);
380  if (platform_str) {
381  hasher.Write((const uint8_t *)platform_str, strlen(platform_str) + 1);
382  }
383 #endif
384 #ifdef AT_EXECFN
385  const char *exec_str = (const char *)getauxval(AT_EXECFN);
386  if (exec_str) {
387  hasher.Write((const uint8_t *)exec_str, strlen(exec_str) + 1);
388  }
389 #endif
390 #endif // __linux__
391 
392 #ifdef HAVE_GETCPUID
393  AddAllCPUID(hasher);
394 #endif
395 
396  // Memory locations
397  hasher << &hasher << &RandAddStaticEnv << &malloc << &errno << &environ;
398 
399  // Hostname
400  char hname[256];
401  if (gethostname(hname, 256) == 0) {
402  hasher.Write((const uint8_t *)hname, strnlen(hname, 256));
403  }
404 
405 #if HAVE_DECL_GETIFADDRS
406  // Network interfaces
407  struct ifaddrs *ifad = NULL;
408  getifaddrs(&ifad);
409  struct ifaddrs *ifit = ifad;
410  while (ifit != NULL) {
411  hasher.Write((const uint8_t *)&ifit, sizeof(ifit));
412  hasher.Write((const uint8_t *)ifit->ifa_name,
413  strlen(ifit->ifa_name) + 1);
414  hasher.Write((const uint8_t *)&ifit->ifa_flags,
415  sizeof(ifit->ifa_flags));
416  AddSockaddr(hasher, ifit->ifa_addr);
417  AddSockaddr(hasher, ifit->ifa_netmask);
418  AddSockaddr(hasher, ifit->ifa_dstaddr);
419  ifit = ifit->ifa_next;
420  }
421  freeifaddrs(ifad);
422 #endif
423 
424 #ifndef WIN32
425  // UNIX kernel information
426  struct utsname name;
427  if (uname(&name) != -1) {
428  hasher.Write((const uint8_t *)&name.sysname, strlen(name.sysname) + 1);
429  hasher.Write((const uint8_t *)&name.nodename,
430  strlen(name.nodename) + 1);
431  hasher.Write((const uint8_t *)&name.release, strlen(name.release) + 1);
432  hasher.Write((const uint8_t *)&name.version, strlen(name.version) + 1);
433  hasher.Write((const uint8_t *)&name.machine, strlen(name.machine) + 1);
434  }
435 
436  /* Path and filesystem provided data */
437  AddPath(hasher, "/");
438  AddPath(hasher, ".");
439  AddPath(hasher, "/tmp");
440  AddPath(hasher, "/home");
441  AddPath(hasher, "/proc");
442 #ifdef __linux__
443  AddFile(hasher, "/proc/cmdline");
444  AddFile(hasher, "/proc/cpuinfo");
445  AddFile(hasher, "/proc/version");
446 #endif
447  AddFile(hasher, "/etc/passwd");
448  AddFile(hasher, "/etc/group");
449  AddFile(hasher, "/etc/hosts");
450  AddFile(hasher, "/etc/resolv.conf");
451  AddFile(hasher, "/etc/timezone");
452  AddFile(hasher, "/etc/localtime");
453 #endif
454 
455  // For MacOS/BSDs, gather data through sysctl instead of /proc. Not all of
456  // these will exist on every system.
457 #if HAVE_SYSCTL
458 #ifdef CTL_HW
459 #ifdef HW_MACHINE
460  AddSysctl<CTL_HW, HW_MACHINE>(hasher);
461 #endif
462 #ifdef HW_MODEL
463  AddSysctl<CTL_HW, HW_MODEL>(hasher);
464 #endif
465 #ifdef HW_NCPU
466  AddSysctl<CTL_HW, HW_NCPU>(hasher);
467 #endif
468 #ifdef HW_PHYSMEM
469  AddSysctl<CTL_HW, HW_PHYSMEM>(hasher);
470 #endif
471 #ifdef HW_USERMEM
472  AddSysctl<CTL_HW, HW_USERMEM>(hasher);
473 #endif
474 #ifdef HW_MACHINE_ARCH
475  AddSysctl<CTL_HW, HW_MACHINE_ARCH>(hasher);
476 #endif
477 #ifdef HW_REALMEM
478  AddSysctl<CTL_HW, HW_REALMEM>(hasher);
479 #endif
480 #ifdef HW_CPU_FREQ
481  AddSysctl<CTL_HW, HW_CPU_FREQ>(hasher);
482 #endif
483 #ifdef HW_BUS_FREQ
484  AddSysctl<CTL_HW, HW_BUS_FREQ>(hasher);
485 #endif
486 #ifdef HW_CACHELINE
487  AddSysctl<CTL_HW, HW_CACHELINE>(hasher);
488 #endif
489 #endif
490 #ifdef CTL_KERN
491 #ifdef KERN_BOOTFILE
492  AddSysctl<CTL_KERN, KERN_BOOTFILE>(hasher);
493 #endif
494 #ifdef KERN_BOOTTIME
495  AddSysctl<CTL_KERN, KERN_BOOTTIME>(hasher);
496 #endif
497 #ifdef KERN_CLOCKRATE
498  AddSysctl<CTL_KERN, KERN_CLOCKRATE>(hasher);
499 #endif
500 #ifdef KERN_HOSTID
501  AddSysctl<CTL_KERN, KERN_HOSTID>(hasher);
502 #endif
503 #ifdef KERN_HOSTUUID
504  AddSysctl<CTL_KERN, KERN_HOSTUUID>(hasher);
505 #endif
506 #ifdef KERN_HOSTNAME
507  AddSysctl<CTL_KERN, KERN_HOSTNAME>(hasher);
508 #endif
509 #ifdef KERN_OSRELDATE
510  AddSysctl<CTL_KERN, KERN_OSRELDATE>(hasher);
511 #endif
512 #ifdef KERN_OSRELEASE
513  AddSysctl<CTL_KERN, KERN_OSRELEASE>(hasher);
514 #endif
515 #ifdef KERN_OSREV
516  AddSysctl<CTL_KERN, KERN_OSREV>(hasher);
517 #endif
518 #ifdef KERN_OSTYPE
519  AddSysctl<CTL_KERN, KERN_OSTYPE>(hasher);
520 #endif
521 #ifdef KERN_POSIX1
522  AddSysctl<CTL_KERN, KERN_OSREV>(hasher);
523 #endif
524 #ifdef KERN_VERSION
525  AddSysctl<CTL_KERN, KERN_VERSION>(hasher);
526 #endif
527 #endif
528 #endif
529 
530  // Env variables
531  if (environ) {
532  for (size_t i = 0; environ[i]; ++i) {
533  hasher.Write((const uint8_t *)environ[i], strlen(environ[i]));
534  }
535  }
536 
537  // Process, thread, user, session, group, ... ids.
538 #ifdef WIN32
539  hasher << GetCurrentProcessId() << GetCurrentThreadId();
540 #else
541  hasher << getpid() << getppid() << getsid(0) << getpgid(0) << getuid()
542  << geteuid() << getgid() << getegid();
543 #endif
544  hasher << std::this_thread::get_id();
545 }
ankerl::nanobench::operator<<
std::ostream & operator<<(std::ostream &os, BigO const &bigO)
cpuid.h
randomenv.h
clientversion.h
memory_cleanse
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
Definition: cleanse.cpp:14
compat.h
cleanse.h
time.h
strnlen
size_t strnlen(const char *start, size_t max_len)
Definition: strnlen.cpp:12
environ
char ** environ
Necessary on some platforms.
name
const char * name
Definition: rest.cpp:43
RandAddStaticEnv
void RandAddStaticEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that does not change over time.
Definition: randomenv.cpp:342
CLIENT_VERSION
static constexpr int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:44
RandAddDynamicEnv
void RandAddDynamicEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that changes over time.
Definition: randomenv.cpp:258
CSHA512
A hasher class for SHA-512.
Definition: sha512.h:12
CSHA512::Write
CSHA512 & Write(const uint8_t *data, size_t len)
Definition: sha512.cpp:248