Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
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
61extern char **environ;
62
63namespace {
64void 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{0s};
71 auto last_time = last_perfmon.load();
73 if (current_time < last_time + std::chrono::minutes{10}) {
74 return;
75 }
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::min((vData.size() * 3) / 2, nMaxSize));
92 }
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
113template <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
134void 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
151void 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
175void 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
185template <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
203void inline AddCPUID(CSHA512 &hasher, uint32_t leaf, uint32_t subleaf,
205 GetCPUID(leaf, subleaf, ax, bx, cx, dx);
206 hasher << leaf << subleaf << ax << bx << cx << dx;
207}
208
209void 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);
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
258 RandAddSeedPerfmon(hasher);
259
260 // Various clocks
261#ifdef WIN32
264 hasher << ftime;
265#else
266 struct timespec ts = {};
267#ifdef CLOCK_MONOTONIC
269 hasher << ts;
270#endif
271#ifdef CLOCK_REALTIME
273 hasher << ts;
274#endif
275#ifdef CLOCK_BOOTTIME
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)
315#endif
316#endif
317#ifdef CTL_HW
318#ifdef HW_DISKSTATS
320#endif
321#endif
322#ifdef CTL_VM
323#ifdef VM_LOADAVG
325#endif
326#ifdef VM_TOTAL
328#endif
329#ifdef VM_METER
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
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__)
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,
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;
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 }
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
460#endif
461#ifdef HW_MODEL
463#endif
464#ifdef HW_NCPU
466#endif
467#ifdef HW_PHYSMEM
469#endif
470#ifdef HW_USERMEM
472#endif
473#ifdef HW_MACHINE_ARCH
475#endif
476#ifdef HW_REALMEM
478#endif
479#ifdef HW_CPU_FREQ
481#endif
482#ifdef HW_BUS_FREQ
484#endif
485#ifdef HW_CACHELINE
487#endif
488#endif
489#ifdef CTL_KERN
490#ifdef KERN_BOOTFILE
492#endif
493#ifdef KERN_BOOTTIME
495#endif
496#ifdef KERN_CLOCKRATE
498#endif
499#ifdef KERN_HOSTID
501#endif
502#ifdef KERN_HOSTUUID
504#endif
505#ifdef KERN_HOSTNAME
507#endif
508#ifdef KERN_OSRELDATE
510#endif
511#ifdef KERN_OSRELEASE
513#endif
514#ifdef KERN_OSREV
516#endif
517#ifdef KERN_OSTYPE
519#endif
520#ifdef KERN_POSIX1
522#endif
523#ifdef KERN_VERSION
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
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}
A hasher class for SHA-512.
Definition sha512.h:12
CSHA512 & Write(const uint8_t *data, size_t len)
Definition sha512.cpp:248
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.
size_t strnlen(const char *start, size_t max_len)
Definition strnlen.cpp:12
std::ostream & operator<<(std::ostream &os, const PeerMessagingState &state)
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
void RandAddStaticEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that does not change over time.
char ** environ
Necessary on some platforms.
void RandAddDynamicEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that changes over time.
const char * name
Definition rest.cpp:47