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