diff options
author | lloyd <[email protected]> | 2014-01-01 21:20:55 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2014-01-01 21:20:55 +0000 |
commit | 197dc467dec28a04c3b2f30da7cef122dfbb13e9 (patch) | |
tree | cdbd3ddaec051c72f0a757db461973d90c37b97a /lib/entropy/unix_procs | |
parent | 62faac373c07cfe10bc8c309e89ebdd30d8e5eaa (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.txt | 25 | ||||
-rw-r--r-- | lib/entropy/unix_procs/unix_proc_sources.cpp | 65 | ||||
-rw-r--r-- | lib/entropy/unix_procs/unix_procs.cpp | 258 | ||||
-rw-r--r-- | lib/entropy/unix_procs/unix_procs.h | 89 |
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 |