aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/entropy/unix_procs/unix_procs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/entropy/unix_procs/unix_procs.cpp')
-rw-r--r--src/lib/entropy/unix_procs/unix_procs.cpp292
1 files changed, 0 insertions, 292 deletions
diff --git a/src/lib/entropy/unix_procs/unix_procs.cpp b/src/lib/entropy/unix_procs/unix_procs.cpp
deleted file mode 100644
index eae1b5255..000000000
--- a/src/lib/entropy/unix_procs/unix_procs.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
- /*
-* Gather entropy by running various system commands in the hopes that
-* some of the output cannot be guessed by a remote attacker.
-*
-* (C) 1999-2009,2013 Jack Lloyd
-* 2012 Markus Wanner
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/internal/unix_procs.h>
-#include <botan/exceptn.h>
-#include <botan/parsing.h>
-#include <algorithm>
-#include <atomic>
-
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/resource.h>
-#include <unistd.h>
-#include <signal.h>
-#include <stdlib.h>
-
-namespace Botan {
-
-namespace {
-
-std::string find_full_path_if_exists(const std::vector<std::string>& trusted_path,
- const std::string& proc)
- {
- for(auto dir : trusted_path)
- {
- const std::string full_path = dir + "/" + proc;
- if(::access(full_path.c_str(), X_OK) == 0)
- return full_path;
- }
-
- return "";
- }
-
-size_t concurrent_processes(size_t user_request)
- {
- const size_t DEFAULT_CONCURRENT = 2;
- const size_t MAX_CONCURRENT = 8;
-
- if(user_request > 0)
- return std::min(user_request, MAX_CONCURRENT);
-
- const long online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
-
- if(online_cpus > 0)
- return static_cast<size_t>(online_cpus); // maybe fewer?
-
- return DEFAULT_CONCURRENT;
- }
-
-}
-
-/**
-* Unix_EntropySource Constructor
-*/
-Unix_EntropySource::Unix_EntropySource(const std::vector<std::string>& trusted_paths,
- size_t proc_count) :
- m_trusted_paths(trusted_paths),
- m_concurrent(concurrent_processes(proc_count))
- {
- }
-
-size_t UnixProcessInfo_EntropySource::poll(RandomNumberGenerator& rng)
- {
- rng.add_entropy_T(::getpid());
- rng.add_entropy_T(::getppid());
- rng.add_entropy_T(::getuid());
- rng.add_entropy_T(::getgid());
- rng.add_entropy_T(::getpgrp());
-
- struct ::rusage usage;
- ::getrusage(RUSAGE_SELF, &usage);
- rng.add_entropy_T(usage);
-
-#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
-
-#define CLOCK_GETTIME_POLL(src) \
- do { \
- struct timespec ts; \
- ::clock_gettime(src, &ts); \
- rng.add_entropy_T(ts); \
- } while(0)
-
-#if defined(CLOCK_REALTIME)
- CLOCK_GETTIME_POLL(CLOCK_REALTIME);
-#endif
-
-#if defined(CLOCK_MONOTONIC)
- CLOCK_GETTIME_POLL(CLOCK_MONOTONIC);
-#endif
-
-#if defined(CLOCK_MONOTONIC_RAW)
- CLOCK_GETTIME_POLL(CLOCK_MONOTONIC_RAW);
-#endif
-
-#if defined(CLOCK_PROCESS_CPUTIME_ID)
- CLOCK_GETTIME_POLL(CLOCK_PROCESS_CPUTIME_ID);
-#endif
-
-#if defined(CLOCK_THREAD_CPUTIME_ID)
- CLOCK_GETTIME_POLL(CLOCK_THREAD_CPUTIME_ID);
-#endif
-
-#undef CLOCK_GETTIME_POLL
-
-#endif
-
- return 0;
- }
-
-void Unix_EntropySource::Unix_Process::spawn(const std::vector<std::string>& args)
- {
- if(args.empty())
- throw Invalid_Argument("Cannot spawn process without path");
-
- shutdown();
-
- int pipe[2];
- if(::pipe(pipe) != 0)
- return;
-
- pid_t pid = ::fork();
-
- if(pid == -1)
- {
- ::close(pipe[0]);
- ::close(pipe[1]);
- }
- else if(pid > 0) // in parent
- {
- m_pid = pid;
- m_fd = pipe[0];
- ::close(pipe[1]);
- }
- else // in child
- {
- if(::dup2(pipe[1], STDOUT_FILENO) == -1)
- ::exit(127);
- if(::close(pipe[0]) != 0 || ::close(pipe[1]) != 0)
- ::exit(127);
- if(close(STDERR_FILENO) != 0)
- ::exit(127);
-
- const char* arg0 = args[0].c_str();
- const char* arg1 = (args.size() > 1) ? args[1].c_str() : nullptr;
- const char* arg2 = (args.size() > 2) ? args[2].c_str() : nullptr;
- const char* arg3 = (args.size() > 3) ? args[3].c_str() : nullptr;
- const char* arg4 = (args.size() > 4) ? args[4].c_str() : nullptr;
-
- ::execl(arg0, arg0, arg1, arg2, arg3, arg4, NULL);
- ::exit(127);
- }
- }
-
-void Unix_EntropySource::Unix_Process::shutdown()
- {
- if(m_pid == -1)
- return;
-
- ::close(m_fd);
- m_fd = -1;
-
- pid_t reaped = waitpid(m_pid, nullptr, WNOHANG);
-
- if(reaped == 0)
- {
- /*
- * Child is still alive - send it SIGTERM, sleep for a bit and
- * try to reap again, if still alive send SIGKILL
- */
- kill(m_pid, SIGTERM);
-
- struct ::timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 1000;
- select(0, nullptr, nullptr, nullptr, &tv);
-
- reaped = ::waitpid(m_pid, nullptr, WNOHANG);
-
- if(reaped == 0)
- {
- ::kill(m_pid, SIGKILL);
- do
- reaped = ::waitpid(m_pid, nullptr, 0);
- while(reaped == -1);
- }
- }
-
- m_pid = -1;
- }
-
-const std::vector<std::string>& Unix_EntropySource::next_source()
- {
- const auto& src = m_sources.at(m_sources_idx);
- m_sources_idx = (m_sources_idx + 1) % m_sources.size();
- return src;
- }
-
-size_t Unix_EntropySource::poll(RandomNumberGenerator& rng)
- {
- // refuse to run setuid or setgid, or as root
- if((getuid() != geteuid()) || (getgid() != getegid()) || (geteuid() == 0))
- return 0;
-
- lock_guard_type<mutex_type> lock(m_mutex);
-
- if(m_sources.empty())
- {
- auto sources = get_default_sources();
-
- for(auto src : sources)
- {
- const std::string path = find_full_path_if_exists(m_trusted_paths, src[0]);
- if(path != "")
- {
- src[0] = path;
- m_sources.push_back(src);
- }
- }
- }
-
- if(m_sources.empty())
- return 0; // still empty, really nothing to try
-
- const size_t MS_WAIT_TIME = 32;
-
- m_buf.resize(4096);
-
- size_t bytes = 0;
-
- while(bytes < 128 * 1024) // arbitrary limit...
- {
- while(m_procs.size() < m_concurrent)
- m_procs.emplace_back(Unix_Process(next_source()));
-
- fd_set read_set;
- FD_ZERO(&read_set);
-
- std::vector<int> fds;
-
- for(auto& proc : m_procs)
- {
- int fd = proc.fd();
- if(fd > 0)
- {
- fds.push_back(fd);
- FD_SET(fd, &read_set);
- }
- }
-
- if(fds.empty())
- break;
-
- const int max_fd = *std::max_element(fds.begin(), fds.end());
-
- struct ::timeval timeout;
- timeout.tv_sec = (MS_WAIT_TIME / 1000);
- timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000;
-
- if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0)
- break; // or continue?
-
- for(auto& proc : m_procs)
- {
- int fd = proc.fd();
-
- if(FD_ISSET(fd, &read_set))
- {
- const ssize_t got = ::read(fd, m_buf.data(), m_buf.size());
-
- if(got > 0)
- {
- rng.add_entropy(m_buf.data(), got);
- bytes += got;
- }
- else
- proc.spawn(next_source());
- }
- }
- }
-
- return bytes / 1024;
- }
-
-}