aboutsummaryrefslogtreecommitdiffstats
path: root/lib/entropy/unix_procs
diff options
context:
space:
mode:
authorlloyd <[email protected]>2014-01-01 21:20:55 +0000
committerlloyd <[email protected]>2014-01-01 21:20:55 +0000
commit197dc467dec28a04c3b2f30da7cef122dfbb13e9 (patch)
treecdbd3ddaec051c72f0a757db461973d90c37b97a /lib/entropy/unix_procs
parent62faac373c07cfe10bc8c309e89ebdd30d8e5eaa (diff)
Shuffle things around. Add NIST X.509 test to build.
Diffstat (limited to 'lib/entropy/unix_procs')
-rw-r--r--lib/entropy/unix_procs/info.txt25
-rw-r--r--lib/entropy/unix_procs/unix_proc_sources.cpp65
-rw-r--r--lib/entropy/unix_procs/unix_procs.cpp258
-rw-r--r--lib/entropy/unix_procs/unix_procs.h89
4 files changed, 437 insertions, 0 deletions
diff --git a/lib/entropy/unix_procs/info.txt b/lib/entropy/unix_procs/info.txt
new file mode 100644
index 000000000..755d2565d
--- /dev/null
+++ b/lib/entropy/unix_procs/info.txt
@@ -0,0 +1,25 @@
+define ENTROPY_SRC_UNIX_PROCESS_RUNNER 20131128
+
+<source>
+unix_procs.cpp
+unix_proc_sources.cpp
+</source>
+
+<header:internal>
+unix_procs.h
+</header:internal>
+
+<os>
+aix
+cygwin
+darwin
+freebsd
+haiku
+hpux
+irix
+linux
+netbsd
+qnx
+solaris
+tru64
+</os>
diff --git a/lib/entropy/unix_procs/unix_proc_sources.cpp b/lib/entropy/unix_procs/unix_proc_sources.cpp
new file mode 100644
index 000000000..6cf185064
--- /dev/null
+++ b/lib/entropy/unix_procs/unix_proc_sources.cpp
@@ -0,0 +1,65 @@
+/*
+* Program List for Unix_EntropySource
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/unix_procs.h>
+
+namespace Botan {
+
+/**
+* Default Commands for Entropy Gathering
+*/
+std::vector<std::vector<std::string>> Unix_EntropySource::get_default_sources()
+ {
+ std::vector<std::vector<std::string>> srcs;
+
+ srcs.push_back({ "netstat", "-in" });
+ srcs.push_back({ "pfstat" });
+ srcs.push_back({ "vmstat", "-s" });
+ srcs.push_back({ "vmstat" });
+
+ srcs.push_back({ "arp", "-a", "-n" });
+ srcs.push_back({ "ifconfig", "-a" });
+ srcs.push_back({ "iostat" });
+ srcs.push_back({ "ipcs", "-a" });
+ srcs.push_back({ "mpstat" });
+ srcs.push_back({ "netstat", "-an" });
+ srcs.push_back({ "netstat", "-s" });
+ srcs.push_back({ "nfsstat" });
+ srcs.push_back({ "portstat" });
+ srcs.push_back({ "procinfo", "-a" });
+ srcs.push_back({ "pstat", "-T" });
+ srcs.push_back({ "pstat", "-s" });
+ srcs.push_back({ "uname", "-a" });
+ srcs.push_back({ "uptime" });
+
+ srcs.push_back({ "listarea" });
+ srcs.push_back({ "listdev" });
+ srcs.push_back({ "ps", "-A" });
+ srcs.push_back({ "sysinfo" });
+
+ srcs.push_back({ "finger" });
+ srcs.push_back({ "mailstats" });
+ srcs.push_back({ "rpcinfo", "-p", "localhost" });
+ srcs.push_back({ "who" });
+
+ srcs.push_back({ "df", "-l" });
+ srcs.push_back({ "dmesg" });
+ srcs.push_back({ "last", "-5" });
+ srcs.push_back({ "ls", "-alni", "/proc" });
+ srcs.push_back({ "ls", "-alni", "/tmp" });
+ srcs.push_back({ "pstat", "-f" });
+
+ srcs.push_back({ "ps", "-elf" });
+ srcs.push_back({ "ps", "aux" });
+
+ srcs.push_back({ "lsof", "-n" });
+ srcs.push_back({ "sar", "-A" });
+
+ return srcs;
+ }
+
+}
diff --git a/lib/entropy/unix_procs/unix_procs.cpp b/lib/entropy/unix_procs/unix_procs.cpp
new file mode 100644
index 000000000..c36941f43
--- /dev/null
+++ b/lib/entropy/unix_procs/unix_procs.cpp
@@ -0,0 +1,258 @@
+ /*
+* 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
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/unix_procs.h>
+#include <botan/parsing.h>
+#include <algorithm>
+
+#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 && user_request < MAX_CONCURRENT)
+ return user_request;
+
+ 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_path,
+ size_t proc_cnt) :
+ m_trusted_paths(trusted_path),
+ m_concurrent(concurrent_processes(proc_cnt))
+ {
+ }
+
+void UnixProcessInfo_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ accum.add(::getpid(), 0.0);
+ accum.add(::getppid(), 0.0);
+ accum.add(::getuid(), 0.0);
+ accum.add(::getgid(), 0.0);
+ accum.add(::getsid(0), 0.0);
+ accum.add(::getpgrp(), 0.0);
+
+ struct ::rusage usage;
+ ::getrusage(RUSAGE_SELF, &usage);
+ accum.add(usage, 0.0);
+
+ ::getrusage(RUSAGE_CHILDREN, &usage);
+ accum.add(usage, 0.0);
+ }
+
+namespace {
+
+void do_exec(const std::vector<std::string>& args)
+ {
+ // cleaner way to do this?
+ const char* arg0 = (args.size() > 0) ? args[0].c_str() : nullptr;
+ 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);
+ }
+
+}
+
+void Unix_EntropySource::Unix_Process::spawn(const std::vector<std::string>& args)
+ {
+ 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);
+
+ do_exec(args);
+ ::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;
+ }
+
+void Unix_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ // refuse to run as root (maybe instead setuid to nobody before exec?)
+ // fixme: this should also check for setgid
+ if(::getuid() == 0 || ::geteuid() == 0)
+ return;
+
+ 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; // still empty, really nothing to try
+
+ const size_t MS_WAIT_TIME = 32;
+ const double ENTROPY_ESTIMATE = 1.0 / 1024;
+
+ secure_vector<byte>& io_buffer = accum.get_io_buffer(4*1024); // page
+
+ while(!accum.polling_goal_achieved())
+ {
+ 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)
+ return; // or continue?
+
+ for(auto& proc : m_procs)
+ {
+ int fd = proc.fd();
+
+ if(FD_ISSET(fd, &read_set))
+ {
+ const ssize_t got = ::read(fd, &io_buffer[0], io_buffer.size());
+ if(got > 0)
+ accum.add(&io_buffer[0], got, ENTROPY_ESTIMATE);
+ else
+ proc.spawn(next_source());
+ }
+ }
+ }
+ }
+
+}
diff --git a/lib/entropy/unix_procs/unix_procs.h b/lib/entropy/unix_procs/unix_procs.h
new file mode 100644
index 000000000..7c1ae8c65
--- /dev/null
+++ b/lib/entropy/unix_procs/unix_procs.h
@@ -0,0 +1,89 @@
+/*
+* Unix EntropySource
+* (C) 1999-2009,2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_UNIX_H__
+#define BOTAN_ENTROPY_SRC_UNIX_H__
+
+#include <botan/entropy_src.h>
+#include <vector>
+#include <sys/types.h>
+
+namespace Botan {
+
+/**
+* Entropy source for generic Unix. Runs various programs trying to
+* gather data hard for a remote attacker to guess. Probably not too
+* effective against local attackers as they can sample from the same
+* distribution.
+*/
+class Unix_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "Unix Process Runner"; }
+
+ void poll(Entropy_Accumulator& accum) override;
+
+ /**
+ * @param trusted_paths is a list of directories that are assumed
+ * to contain only 'safe' binaries. If an attacker can write
+ * an executable to one of these directories then we will
+ * run arbitrary code.
+ */
+ Unix_EntropySource(const std::vector<std::string>& trusted_paths,
+ size_t concurrent_processes = 0);
+ private:
+ static std::vector<std::vector<std::string>> get_default_sources();
+
+ class Unix_Process
+ {
+ public:
+ int fd() const { return m_fd; }
+
+ void spawn(const std::vector<std::string>& args);
+ void shutdown();
+
+ Unix_Process() {}
+
+ Unix_Process(const std::vector<std::string>& args) { spawn(args); }
+
+ ~Unix_Process() { shutdown(); }
+
+ Unix_Process(Unix_Process&& other)
+ {
+ std::swap(m_fd, other.m_fd);
+ std::swap(m_pid, other.m_pid);
+ }
+
+ Unix_Process(const Unix_Process&) = delete;
+ Unix_Process& operator=(const Unix_Process&) = delete;
+ private:
+ int m_fd = -1;
+ pid_t m_pid = -1;
+ };
+
+ const std::vector<std::string>& next_source();
+
+ const std::vector<std::string> m_trusted_paths;
+ const size_t m_concurrent;
+
+ std::vector<std::vector<std::string>> m_sources;
+ size_t m_sources_idx = 0;
+
+ std::vector<Unix_Process> m_procs;
+ };
+
+class UnixProcessInfo_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "Unix Process Info"; }
+
+ void poll(Entropy_Accumulator& accum);
+ };
+
+}
+
+#endif