Bitcoin Core 30.99.0
P2P Digital Currency
randomenv.cpp
Go to the documentation of this file.
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#include <bitcoin-build-config.h> // IWYU pragma: keep
7
8#include <randomenv.h>
9
10#include <clientversion.h>
11#include <compat/compat.h>
12#include <compat/cpuid.h>
13#include <crypto/sha512.h>
14#include <span.h>
15#include <support/cleanse.h>
16#include <util/time.h>
17
18#include <algorithm>
19#include <atomic>
20#include <cstdint>
21#include <cstring>
22#include <chrono>
23#include <climits>
24#include <thread>
25#include <vector>
26
27#include <sys/types.h> // must go before a number of other headers
28
29#ifdef WIN32
30#include <windows.h>
31#else
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#ifdef HAVE_IFADDRS
42#include <ifaddrs.h>
43#endif
44#ifdef HAVE_SYSCTL
45#include <sys/sysctl.h>
46#if __has_include(<vm/vm_param.h>)
47#include <vm/vm_param.h>
48#endif
49#if __has_include(<sys/resources.h>)
50#include <sys/resources.h>
51#endif
52#if __has_include(<sys/vmmeter.h>)
53#include <sys/vmmeter.h>
54#endif
55#endif
56#if defined(HAVE_STRONG_GETAUXVAL)
57#include <sys/auxv.h>
58#endif
59
60#if defined(__APPLE__) || \
61 defined(__FreeBSD__) || \
62 defined(__NetBSD__) || \
63 defined(__OpenBSD__) || \
64 defined(__illumos__)
65extern char** environ; // Necessary on the above platforms
66#endif
67
68namespace {
69
75template<typename T>
76CSHA512& operator<<(CSHA512& hasher, const T& data) {
77 static_assert(!std::is_same_v<std::decay_t<T>, char*>, "Calling operator<<(CSHA512, char*) is probably not what you want");
78 static_assert(!std::is_same_v<std::decay_t<T>, unsigned char*>, "Calling operator<<(CSHA512, unsigned char*) is probably not what you want");
79 static_assert(!std::is_same_v<std::decay_t<T>, const char*>, "Calling operator<<(CSHA512, const char*) is probably not what you want");
80 static_assert(!std::is_same_v<std::decay_t<T>, const unsigned char*>, "Calling operator<<(CSHA512, const unsigned char*) is probably not what you want");
81 hasher.Write((const unsigned char*)&data, sizeof(data));
82 return hasher;
83}
84
85#ifndef WIN32
86void AddSockaddr(CSHA512& hasher, const struct sockaddr *addr)
87{
88 if (addr == nullptr) return;
89 switch (addr->sa_family) {
90 case AF_INET:
91 hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in));
92 break;
93 case AF_INET6:
94 hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in6));
95 break;
96 default:
97 hasher.Write((const unsigned char*)&addr->sa_family, sizeof(addr->sa_family));
98 }
99}
100
101void AddFile(CSHA512& hasher, const char *path)
102{
103 struct stat sb = {};
104 int f = open(path, O_RDONLY);
105 size_t total = 0;
106 if (f != -1) {
107 unsigned char fbuf[4096];
108 int n;
109 hasher.Write((const unsigned char*)&f, sizeof(f));
110 if (fstat(f, &sb) == 0) hasher << sb;
111 do {
112 n = read(f, fbuf, sizeof(fbuf));
113 if (n > 0) hasher.Write(fbuf, n);
114 total += n;
115 /* not bothering with EINTR handling. */
116 } while (n == sizeof(fbuf) && total < 1048576); // Read only the first 1 Mbyte
117 close(f);
118 }
119}
120
121void AddPath(CSHA512& hasher, const char *path)
122{
123 struct stat sb = {};
124 if (stat(path, &sb) == 0) {
125 hasher.Write((const unsigned char*)path, strlen(path) + 1);
126 hasher << sb;
127 }
128}
129#endif
130
131#ifdef HAVE_SYSCTL
132template<int... S>
133void AddSysctl(CSHA512& hasher)
134{
135 int CTL[sizeof...(S)] = {S...};
136 unsigned char buffer[65536];
137 size_t siz = 65536;
138 int ret = sysctl(CTL, sizeof...(S), buffer, &siz, nullptr, 0);
139 if (ret == 0 || (ret == -1 && errno == ENOMEM)) {
140 hasher << sizeof(CTL);
141 hasher.Write((const unsigned char*)CTL, sizeof(CTL));
142 if (siz > sizeof(buffer)) siz = sizeof(buffer);
143 hasher << siz;
144 hasher.Write(buffer, siz);
145 }
146}
147#endif
148
149#ifdef HAVE_GETCPUID
150void inline AddCPUID(CSHA512& hasher, uint32_t leaf, uint32_t subleaf, uint32_t& ax, uint32_t& bx, uint32_t& cx, uint32_t& dx)
151{
152 GetCPUID(leaf, subleaf, ax, bx, cx, dx);
153 hasher << leaf << subleaf << ax << bx << cx << dx;
154}
155
156void AddAllCPUID(CSHA512& hasher)
157{
158 uint32_t ax, bx, cx, dx;
159 // Iterate over all standard leaves
160 AddCPUID(hasher, 0, 0, ax, bx, cx, dx); // Returns max leaf in ax
161 uint32_t max = ax;
162 for (uint32_t leaf = 1; leaf <= max && leaf <= 0xFF; ++leaf) {
163 uint32_t maxsub = 0;
164 for (uint32_t subleaf = 0; subleaf <= 0xFF; ++subleaf) {
165 AddCPUID(hasher, leaf, subleaf, ax, bx, cx, dx);
166 // Iterate subleafs for leaf values 4, 7, 11, 13
167 if (leaf == 4) {
168 if ((ax & 0x1f) == 0) break;
169 } else if (leaf == 7) {
170 if (subleaf == 0) maxsub = ax;
171 if (subleaf == maxsub) break;
172 } else if (leaf == 11) {
173 if ((cx & 0xff00) == 0) break;
174 } else if (leaf == 13) {
175 if (ax == 0 && bx == 0 && cx == 0 && dx == 0) break;
176 } else {
177 // For any other leaf, stop after subleaf 0.
178 break;
179 }
180 }
181 }
182 // Iterate over all extended leaves
183 AddCPUID(hasher, 0x80000000, 0, ax, bx, cx, dx); // Returns max extended leaf in ax
184 uint32_t ext_max = ax;
185 for (uint32_t leaf = 0x80000001; leaf <= ext_max && leaf <= 0x800000FF; ++leaf) {
186 AddCPUID(hasher, leaf, 0, ax, bx, cx, dx);
187 }
188}
189#endif
190} // namespace
191
193{
194 // Various clocks
195#ifdef WIN32
196 FILETIME ftime;
197 GetSystemTimeAsFileTime(&ftime);
198 hasher << ftime;
199#else
200 struct timespec ts = {};
201# ifdef CLOCK_MONOTONIC
202 clock_gettime(CLOCK_MONOTONIC, &ts);
203 hasher << ts;
204# endif
205# ifdef CLOCK_REALTIME
206 clock_gettime(CLOCK_REALTIME, &ts);
207 hasher << ts;
208# endif
209# ifdef CLOCK_BOOTTIME
210 clock_gettime(CLOCK_BOOTTIME, &ts);
211 hasher << ts;
212# endif
213 // gettimeofday is available on all UNIX systems, but only has microsecond precision.
214 struct timeval tv = {};
215 gettimeofday(&tv, nullptr);
216 hasher << tv;
217#endif
218 // Probably redundant, but also use all the standard library clocks:
219 hasher << std::chrono::system_clock::now().time_since_epoch().count();
220 hasher << std::chrono::steady_clock::now().time_since_epoch().count();
221 hasher << std::chrono::high_resolution_clock::now().time_since_epoch().count();
222
223#ifndef WIN32
224 // Current resource usage.
225 struct rusage usage = {};
226 if (getrusage(RUSAGE_SELF, &usage) == 0) hasher << usage;
227#endif
228
229#ifdef __linux__
230 AddFile(hasher, "/proc/diskstats");
231 AddFile(hasher, "/proc/vmstat");
232 AddFile(hasher, "/proc/schedstat");
233 AddFile(hasher, "/proc/zoneinfo");
234 AddFile(hasher, "/proc/meminfo");
235 AddFile(hasher, "/proc/softirqs");
236 AddFile(hasher, "/proc/stat");
237 AddFile(hasher, "/proc/self/schedstat");
238 AddFile(hasher, "/proc/self/status");
239#endif
240
241#ifdef HAVE_SYSCTL
242# ifdef CTL_KERN
243# if defined(KERN_PROC) && defined(KERN_PROC_ALL)
244 AddSysctl<CTL_KERN, KERN_PROC, KERN_PROC_ALL>(hasher);
245# endif
246# endif
247# ifdef CTL_HW
248# ifdef HW_DISKSTATS
249 AddSysctl<CTL_HW, HW_DISKSTATS>(hasher);
250# endif
251# endif
252# ifdef CTL_VM
253# ifdef VM_LOADAVG
254 AddSysctl<CTL_VM, VM_LOADAVG>(hasher);
255# endif
256# ifdef VM_TOTAL
257 AddSysctl<CTL_VM, VM_TOTAL>(hasher);
258# endif
259# ifdef VM_METER
260 AddSysctl<CTL_VM, VM_METER>(hasher);
261# endif
262# endif
263#endif
264
265 // Stack and heap location
266 void* addr = malloc(4097);
267 hasher << &addr << addr;
268 free(addr);
269}
270
272{
273 // Some compile-time static properties
274 hasher << (CHAR_MIN < 0) << sizeof(void*) << sizeof(long) << sizeof(int);
275#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
276 hasher << __GNUC__ << __GNUC_MINOR__ << __GNUC_PATCHLEVEL__;
277#endif
278#ifdef _MSC_VER
279 hasher << _MSC_VER;
280#endif
281 hasher << __cplusplus;
282#ifdef _XOPEN_VERSION
283 hasher << _XOPEN_VERSION;
284#endif
285#ifdef __VERSION__
286 const char* COMPILER_VERSION = __VERSION__;
287 hasher.Write((const unsigned char*)COMPILER_VERSION, strlen(COMPILER_VERSION) + 1);
288#endif
289
290 // Bitcoin client version
291 hasher << CLIENT_VERSION;
292
293#if defined(HAVE_STRONG_GETAUXVAL)
294 // Information available through getauxval()
295# ifdef AT_HWCAP
296 hasher << getauxval(AT_HWCAP);
297# endif
298# ifdef AT_HWCAP2
299 hasher << getauxval(AT_HWCAP2);
300# endif
301# ifdef AT_RANDOM
302 const unsigned char* random_aux = (const unsigned char*)getauxval(AT_RANDOM);
303 if (random_aux) hasher.Write(random_aux, 16);
304# endif
305# ifdef AT_PLATFORM
306 const char* platform_str = (const char*)getauxval(AT_PLATFORM);
307 if (platform_str) hasher.Write((const unsigned char*)platform_str, strlen(platform_str) + 1);
308# endif
309# ifdef AT_EXECFN
310 const char* exec_str = (const char*)getauxval(AT_EXECFN);
311 if (exec_str) hasher.Write((const unsigned char*)exec_str, strlen(exec_str) + 1);
312# endif
313#endif // HAVE_STRONG_GETAUXVAL
314
315#ifdef HAVE_GETCPUID
316 AddAllCPUID(hasher);
317#endif
318
319 // Memory locations
320 hasher << &hasher << &RandAddStaticEnv << &malloc << &errno << &environ;
321
322 // Hostname
323#ifdef WIN32
324 constexpr DWORD max_size = MAX_COMPUTERNAME_LENGTH + 1;
325 char hname[max_size];
326 DWORD size = max_size;
327 if (GetComputerNameA(hname, &size) != 0) {
328 hasher.Write(UCharCast(hname), size);
329 }
330#else
331 char hname[256];
332 if (gethostname(hname, 256) == 0) {
333 hasher.Write((const unsigned char*)hname, strnlen(hname, 256));
334 }
335#endif
336
337#ifdef HAVE_IFADDRS
338 // Network interfaces
339 struct ifaddrs *ifad = nullptr;
340 getifaddrs(&ifad);
341 struct ifaddrs *ifit = ifad;
342 while (ifit != nullptr) {
343 hasher.Write((const unsigned char*)&ifit, sizeof(ifit));
344 hasher.Write((const unsigned char*)ifit->ifa_name, strlen(ifit->ifa_name) + 1);
345 hasher.Write((const unsigned char*)&ifit->ifa_flags, sizeof(ifit->ifa_flags));
346 AddSockaddr(hasher, ifit->ifa_addr);
347 AddSockaddr(hasher, ifit->ifa_netmask);
348 AddSockaddr(hasher, ifit->ifa_dstaddr);
349 ifit = ifit->ifa_next;
350 }
351 freeifaddrs(ifad);
352#endif
353
354#ifndef WIN32
355 // UNIX kernel information
356 struct utsname name;
357 if (uname(&name) != -1) {
358 hasher.Write((const unsigned char*)&name.sysname, strlen(name.sysname) + 1);
359 hasher.Write((const unsigned char*)&name.nodename, strlen(name.nodename) + 1);
360 hasher.Write((const unsigned char*)&name.release, strlen(name.release) + 1);
361 hasher.Write((const unsigned char*)&name.version, strlen(name.version) + 1);
362 hasher.Write((const unsigned char*)&name.machine, strlen(name.machine) + 1);
363 }
364
365 /* Path and filesystem provided data */
366 AddPath(hasher, "/");
367 AddPath(hasher, ".");
368 AddPath(hasher, "/tmp");
369 AddPath(hasher, "/home");
370 AddPath(hasher, "/proc");
371#ifdef __linux__
372 AddFile(hasher, "/proc/cmdline");
373 AddFile(hasher, "/proc/cpuinfo");
374 AddFile(hasher, "/proc/version");
375#endif
376 AddFile(hasher, "/etc/passwd");
377 AddFile(hasher, "/etc/group");
378 AddFile(hasher, "/etc/hosts");
379 AddFile(hasher, "/etc/resolv.conf");
380 AddFile(hasher, "/etc/timezone");
381 AddFile(hasher, "/etc/localtime");
382#endif
383
384 // For MacOS/BSDs, gather data through sysctl instead of /proc. Not all of these
385 // will exist on every system.
386#ifdef HAVE_SYSCTL
387# ifdef CTL_HW
388# ifdef HW_MACHINE
389 AddSysctl<CTL_HW, HW_MACHINE>(hasher);
390# endif
391# ifdef HW_MODEL
392 AddSysctl<CTL_HW, HW_MODEL>(hasher);
393# endif
394# ifdef HW_NCPU
395 AddSysctl<CTL_HW, HW_NCPU>(hasher);
396# endif
397# ifdef HW_PHYSMEM
398 AddSysctl<CTL_HW, HW_PHYSMEM>(hasher);
399# endif
400# ifdef HW_USERMEM
401 AddSysctl<CTL_HW, HW_USERMEM>(hasher);
402# endif
403# ifdef HW_MACHINE_ARCH
404 AddSysctl<CTL_HW, HW_MACHINE_ARCH>(hasher);
405# endif
406# ifdef HW_REALMEM
407 AddSysctl<CTL_HW, HW_REALMEM>(hasher);
408# endif
409# ifdef HW_CPU_FREQ
410 AddSysctl<CTL_HW, HW_CPU_FREQ>(hasher);
411# endif
412# ifdef HW_BUS_FREQ
413 AddSysctl<CTL_HW, HW_BUS_FREQ>(hasher);
414# endif
415# ifdef HW_CACHELINE
416 AddSysctl<CTL_HW, HW_CACHELINE>(hasher);
417# endif
418# endif
419# ifdef CTL_KERN
420# ifdef KERN_BOOTFILE
421 AddSysctl<CTL_KERN, KERN_BOOTFILE>(hasher);
422# endif
423# ifdef KERN_BOOTTIME
424 AddSysctl<CTL_KERN, KERN_BOOTTIME>(hasher);
425# endif
426# ifdef KERN_CLOCKRATE
427 AddSysctl<CTL_KERN, KERN_CLOCKRATE>(hasher);
428# endif
429# ifdef KERN_HOSTID
430 AddSysctl<CTL_KERN, KERN_HOSTID>(hasher);
431# endif
432# ifdef KERN_HOSTUUID
433 AddSysctl<CTL_KERN, KERN_HOSTUUID>(hasher);
434# endif
435# ifdef KERN_HOSTNAME
436 AddSysctl<CTL_KERN, KERN_HOSTNAME>(hasher);
437# endif
438# ifdef KERN_OSRELDATE
439 AddSysctl<CTL_KERN, KERN_OSRELDATE>(hasher);
440# endif
441# ifdef KERN_OSRELEASE
442 AddSysctl<CTL_KERN, KERN_OSRELEASE>(hasher);
443# endif
444# ifdef KERN_OSREV
445 AddSysctl<CTL_KERN, KERN_OSREV>(hasher);
446# endif
447# ifdef KERN_OSTYPE
448 AddSysctl<CTL_KERN, KERN_OSTYPE>(hasher);
449# endif
450# ifdef KERN_POSIX1
451 AddSysctl<CTL_KERN, KERN_OSREV>(hasher);
452# endif
453# ifdef KERN_VERSION
454 AddSysctl<CTL_KERN, KERN_VERSION>(hasher);
455# endif
456# endif
457#endif
458
459 // Env variables
460 if (environ) {
461 for (size_t i = 0; environ[i]; ++i) {
462 hasher.Write((const unsigned char*)environ[i], strlen(environ[i]));
463 }
464 }
465
466 // Process, thread, user, session, group, ... ids.
467#ifdef WIN32
468 hasher << GetCurrentProcessId() << GetCurrentThreadId();
469#else
470 hasher << getpid() << getppid() << getsid(0) << getpgid(0) << getuid() << geteuid() << getgid() << getegid();
471#endif
472 hasher << std::this_thread::get_id();
473}
int ret
A hasher class for SHA-512.
Definition: sha512.h:13
CSHA512 & Write(const unsigned char *data, size_t len)
Definition: sha512.cpp:159
static const int CLIENT_VERSION
Definition: clientversion.h:26
std::ostream & operator<<(std::ostream &os, BigO const &bigO)
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
void RandAddStaticEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that does not change over time.
Definition: randomenv.cpp:271
void RandAddDynamicEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that changes over time.
Definition: randomenv.cpp:192
const char * name
Definition: rest.cpp:50
unsigned char * UCharCast(char *c)
Definition: span.h:95