aboutsummaryrefslogtreecommitdiff
path: root/src/randomenv.cpp
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2019-10-26 18:05:10 -0700
committerPieter Wuille <pieter.wuille@gmail.com>2019-11-12 15:24:02 -0800
commit2554c1b81bb8c40e1989025c6f18e7935720b156 (patch)
tree86dc2f698d86ed556c2fa0ac0f141dfde2f40b23 /src/randomenv.cpp
parentc2a262a78c3bcc4d5e13612ab0214874abe15de0 (diff)
Gather additional entropy from the environment
This based on code by Gregory Maxwell.
Diffstat (limited to 'src/randomenv.cpp')
-rw-r--r--src/randomenv.cpp194
1 files changed, 184 insertions, 10 deletions
diff --git a/src/randomenv.cpp b/src/randomenv.cpp
index 3f970ec330..1faf2f4613 100644
--- a/src/randomenv.cpp
+++ b/src/randomenv.cpp
@@ -3,8 +3,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
#include <randomenv.h>
+#include <clientversion.h>
#include <crypto/sha512.h>
#include <support/cleanse.h>
#include <util/time.h> // for GetTime()
@@ -14,14 +19,21 @@
#include <algorithm>
#include <chrono>
+#include <climits>
#include <thread>
#include <vector>
#include <stdint.h>
#include <string.h>
#ifndef WIN32
+#include <sys/types.h> // must go before a number of other headers
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/types.h>
+#include <sys/utsname.h>
#include <unistd.h>
#endif
#ifdef __MACH__
@@ -29,6 +41,12 @@
#include <mach/mach.h>
#include <mach/mach_time.h>
#endif
+#if HAVE_DECL_GETIFADDRS
+#include <ifaddrs.h>
+#endif
+
+//! Necessary on some platforms
+extern char** environ;
namespace {
@@ -85,6 +103,53 @@ CSHA512& operator<<(CSHA512& hasher, const T& data) {
return hasher;
}
+#ifndef WIN32
+void AddSockaddr(CSHA512& hasher, const struct sockaddr *addr)
+{
+ if (addr == nullptr) return;
+ switch (addr->sa_family) {
+ case AF_INET:
+ hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in));
+ break;
+ case AF_INET6:
+ hasher.Write((const unsigned char*)addr, sizeof(sockaddr_in6));
+ break;
+ default:
+ hasher.Write((const unsigned char*)&addr->sa_family, sizeof(addr->sa_family));
+ }
+}
+
+void AddFile(CSHA512& hasher, const char *path)
+{
+ struct stat sb = {};
+ int f = open(path, O_RDONLY);
+ size_t total = 0;
+ if (f != -1) {
+ unsigned char fbuf[4096];
+ int n;
+ hasher.Write((const unsigned char*)&f, sizeof(f));
+ if (fstat(f, &sb) == 0) hasher << sb;
+ do {
+ n = read(f, fbuf, sizeof(fbuf));
+ if (n > 0) hasher.Write(fbuf, n);
+ total += n;
+ /* not bothering with EINTR handling. */
+ } while (n == sizeof(fbuf) && total < 1048576); // Read only the first 1 Mbyte
+ close(f);
+ }
+}
+
+void AddPath(CSHA512& hasher, const char *path)
+{
+ struct stat sb = {};
+ if (stat(path, &sb) == 0) {
+ hasher.Write((const unsigned char*)path, strlen(path) + 1);
+ hasher << sb;
+ }
+}
+#endif
+
+
} // namespace
void RandAddDynamicEnv(CSHA512& hasher)
@@ -99,18 +164,18 @@ void RandAddDynamicEnv(CSHA512& hasher)
#else
# ifndef __MACH__
// On non-MacOS systems, use various clock_gettime() calls.
- struct timespec ts;
+ struct timespec ts = {};
# ifdef CLOCK_MONOTONIC
clock_gettime(CLOCK_MONOTONIC, &ts);
- hasher << ts.tv_sec << ts.tv_nsec;
+ hasher << ts;
# endif
# ifdef CLOCK_REALTIME
clock_gettime(CLOCK_REALTIME, &ts);
- hasher << ts.tv_sec << ts.tv_nsec;
+ hasher << ts;
# endif
# ifdef CLOCK_BOOTTIME
clock_gettime(CLOCK_BOOTTIME, &ts);
- hasher << ts.tv_sec << ts.tv_nsec;
+ hasher << ts;
# endif
# else
// On MacOS use mach_absolute_time (number of CPU ticks since boot) as a replacement for CLOCK_MONOTONIC,
@@ -118,29 +183,138 @@ void RandAddDynamicEnv(CSHA512& hasher)
hasher << mach_absolute_time();
// From https://gist.github.com/jbenet/1087739
clock_serv_t cclock;
- mach_timespec_t mts;
+ mach_timespec_t mts = {};
if (host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock) == KERN_SUCCESS && clock_get_time(cclock, &mts) == KERN_SUCCESS) {
- hasher << mts.tv_sec << mts.tv_nsec;
+ hasher << mts;
mach_port_deallocate(mach_task_self(), cclock);
}
# endif
// gettimeofday is available on all UNIX systems, but only has microsecond precision.
- struct timeval tv;
+ struct timeval tv = {};
gettimeofday(&tv, nullptr);
- hasher << tv.tv_sec << tv.tv_usec;
+ hasher << tv;
#endif
// Probably redundant, but also use all the clocks C++11 provides:
hasher << std::chrono::system_clock::now().time_since_epoch().count();
hasher << std::chrono::steady_clock::now().time_since_epoch().count();
hasher << std::chrono::high_resolution_clock::now().time_since_epoch().count();
+
+#ifndef WIN32
+ // Current resource usage.
+ struct rusage usage = {};
+ if (getrusage(RUSAGE_SELF, &usage) == 0) hasher << usage;
+#endif
+
+#ifdef __linux__
+ AddFile(hasher, "/proc/diskstats");
+ AddFile(hasher, "/proc/vmstat");
+ AddFile(hasher, "/proc/schedstat");
+ AddFile(hasher, "/proc/zoneinfo");
+ AddFile(hasher, "/proc/meminfo");
+ AddFile(hasher, "/proc/softirqs");
+ AddFile(hasher, "/proc/stat");
+ AddFile(hasher, "/proc/self/schedstat");
+ AddFile(hasher, "/proc/self/status");
+#endif
+
+ // Stack and heap location
+ void* addr = malloc(4097);
+ hasher << &addr << addr;
+ free(addr);
}
void RandAddStaticEnv(CSHA512& hasher)
{
+ // Some compile-time static properties
+ hasher << (CHAR_MIN < 0) << sizeof(void*) << sizeof(long) << sizeof(int);
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+ hasher << __GNUC__ << __GNUC_MINOR__ << __GNUC_PATCHLEVEL__;
+#endif
+#ifdef _MSC_VER
+ hasher << _MSC_VER;
+#endif
+ hasher << __cplusplus;
+#ifdef _XOPEN_VERSION
+ hasher << _XOPEN_VERSION;
+#endif
+#ifdef __VERSION__
+ const char* COMPILER_VERSION = __VERSION__;
+ hasher.Write((const unsigned char*)COMPILER_VERSION, strlen(COMPILER_VERSION) + 1);
+#endif
+
+ // Bitcoin client version
+ hasher << CLIENT_VERSION;
+
+ // Memory locations
+ hasher << &hasher << &RandAddStaticEnv << &malloc << &errno << &environ;
+
+ // Hostname
+ char hname[256];
+ if (gethostname(hname, 256) == 0) {
+ hasher.Write((const unsigned char*)hname, strnlen(hname, 256));
+ }
+
+#if HAVE_DECL_GETIFADDRS
+ // Network interfaces
+ struct ifaddrs *ifad = NULL;
+ getifaddrs(&ifad);
+ struct ifaddrs *ifit = ifad;
+ while (ifit != NULL) {
+ hasher.Write((const unsigned char*)&ifit, sizeof(ifit));
+ hasher.Write((const unsigned char*)ifit->ifa_name, strlen(ifit->ifa_name) + 1);
+ hasher.Write((const unsigned char*)&ifit->ifa_flags, sizeof(ifit->ifa_flags));
+ AddSockaddr(hasher, ifit->ifa_addr);
+ AddSockaddr(hasher, ifit->ifa_netmask);
+ AddSockaddr(hasher, ifit->ifa_dstaddr);
+ ifit = ifit->ifa_next;
+ }
+ freeifaddrs(ifad);
+#endif
+
+#ifndef WIN32
+ // UNIX kernel information
+ struct utsname name;
+ if (uname(&name) != -1) {
+ hasher.Write((const unsigned char*)&name.sysname, strlen(name.sysname) + 1);
+ hasher.Write((const unsigned char*)&name.nodename, strlen(name.nodename) + 1);
+ hasher.Write((const unsigned char*)&name.release, strlen(name.release) + 1);
+ hasher.Write((const unsigned char*)&name.version, strlen(name.version) + 1);
+ hasher.Write((const unsigned char*)&name.machine, strlen(name.machine) + 1);
+ }
+
+ /* Path and filesystem provided data */
+ AddPath(hasher, "/");
+ AddPath(hasher, ".");
+ AddPath(hasher, "/tmp");
+ AddPath(hasher, "/home");
+ AddPath(hasher, "/proc");
+#ifdef __linux__
+ AddFile(hasher, "/proc/cmdline");
+ AddFile(hasher, "/proc/cpuinfo");
+ AddFile(hasher, "/proc/version");
+#endif
+ AddFile(hasher, "/etc/passwd");
+ AddFile(hasher, "/etc/group");
+ AddFile(hasher, "/etc/hosts");
+ AddFile(hasher, "/etc/resolv.conf");
+ AddFile(hasher, "/etc/timezone");
+ AddFile(hasher, "/etc/localtime");
+
+ /* TODO: sysctl's for OSX to fetch information not available from /proc */
+#endif
+
+ // Env variables
+ if (environ) {
+ for (size_t i = 0; environ[i]; ++i) {
+ hasher.Write((const unsigned char*)environ[i], strlen(environ[i]));
+ }
+ }
+
+ // Process, thread, user, session, group, ... ids.
#ifdef WIN32
hasher << GetCurrentProcessId() << GetCurrentThreadId();
#else
- hasher << getpid();
+ hasher << getpid() << getppid() << getsid(0) << getpgid(0) << getuid() << geteuid() << getgid() << getegid();
#endif
hasher << std::this_thread::get_id();
}