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