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