/* * OS specific utility functions * (C) 2015,2016,2017,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #ifndef BOTAN_OS_UTILS_H_ #define BOTAN_OS_UTILS_H_ #include #include #include #include namespace Botan { namespace OS { /* * This header is internal (not installed) and these functions are not * intended to be called by applications. However they are given public * visibility (using BOTAN_TEST_API macro) for the tests. This also probably * allows them to be overridden by the application on ELF systems, but * this hasn't been tested. */ /** * @return process ID assigned by the operating system. * On Unix and Windows systems, this always returns a result * On IncludeOS it returns 0 since there is no process ID to speak of * in a unikernel. */ uint32_t BOTAN_TEST_API get_process_id(); /** * Test if we are currently running with elevated permissions * eg setuid, setgid, or with POSIX caps set. */ bool running_in_privileged_state(); /** * @return CPU processor clock, if available * * On Windows, calls QueryPerformanceCounter. * * Under GCC or Clang on supported platforms the hardware cycle counter is queried. * Currently supported processors are x86, PPC, Alpha, SPARC, IA-64, S/390x, and HP-PA. * If no CPU cycle counter is available on this system, returns zero. */ uint64_t BOTAN_TEST_API get_cpu_cycle_counter(); size_t BOTAN_TEST_API get_cpu_total(); size_t BOTAN_TEST_API get_cpu_available(); /** * Return the ELF auxiliary vector cooresponding to the given ID. * This only makes sense on Unix-like systems and is currently * only supported on Linux, Android, and FreeBSD. * * Returns zero if not supported on the current system or if * the id provided is not known. */ unsigned long get_auxval(unsigned long id); /* * @return best resolution timestamp available * * The epoch and update rate of this clock is arbitrary and depending * on the hardware it may not tick at a constant rate. * * Uses hardware cycle counter, if available. * On POSIX platforms clock_gettime is used with a monotonic timer * As a final fallback std::chrono::high_resolution_clock is used. */ uint64_t BOTAN_TEST_API get_high_resolution_clock(); /** * @return system clock (reflecting wall clock) with best resolution * available, normalized to nanoseconds resolution. */ uint64_t BOTAN_TEST_API get_system_timestamp_ns(); /** * @return maximum amount of memory (in bytes) Botan could/should * hyptothetically allocate for the memory poool. Reads environment * variable "BOTAN_MLOCK_POOL_SIZE", set to "0" to disable pool. */ size_t get_memory_locking_limit(); /** * Return the size of a memory page, if that can be derived on the * current system. Otherwise returns some default value (eg 4096) */ size_t system_page_size(); /** * Read the value of an environment variable, setting it to value_out if it * exists. Returns false and sets value_out to empty string if no such variable * is set. If the process seems to be running in a privileged state (such as * setuid) then always returns false and does not examine the environment. */ bool read_env_variable(std::string& value_out, const std::string& var_name); /** * Read the value of an environment variable and convert it to an * integer. If not set or conversion fails, returns the default value. * * If the process seems to be running in a privileged state (such as setuid) * then always returns nullptr, similiar to glibc's secure_getenv. */ size_t read_env_variable_sz(const std::string& var_name, size_t def_value = 0); /** * Request count pages of RAM which are locked into memory using mlock, * VirtualLock, or some similar OS specific API. Free it with free_locked_pages. * * Returns an empty list on failure. This function is allowed to return fewer * than count pages. * * The contents of the allocated pages are undefined. * * Each page is preceded by and followed by a page which is marked * as noaccess, such that accessing it will cause a crash. This turns * out of bound reads/writes into crash events. * * @param count requested number of locked pages */ std::vector allocate_locked_pages(size_t count); /** * Free memory allocated by allocate_locked_pages * @param pages a list of pages returned by allocate_locked_pages */ void free_locked_pages(const std::vector& pages); /** * Set the MMU to prohibit access to this page */ void page_prohibit_access(void* page); /** * Set the MMU to allow R/W access to this page */ void page_allow_access(void* page); /** * Run a probe instruction to test for support for a CPU instruction. * Runs in system-specific env that catches illegal instructions; this * function always fails if the OS doesn't provide this. * Returns value of probe_fn, if it could run. * If error occurs, returns negative number. * This allows probe_fn to indicate errors of its own, if it wants. * For example the instruction might not only be only available on some * CPUs, but also buggy on some subset of these - the probe function * can test to make sure the instruction works properly before * indicating that the instruction is available. * * @warning on Unix systems uses signal handling in a way that is not * thread safe. It should only be called in a single-threaded context * (ie, at static init time). * * If probe_fn throws an exception the result is undefined. * * Return codes: * -1 illegal instruction detected */ int BOTAN_TEST_API run_cpu_instruction_probe(std::function probe_fn); /** * Represents a terminal state */ class BOTAN_UNSTABLE_API Echo_Suppression { public: /** * Reenable echo on this terminal. Can be safely called * multiple times. May throw if an error occurs. */ virtual void reenable_echo() = 0; /** * Implicitly calls reenable_echo, but swallows/ignored all * errors which would leave the terminal in an invalid state. */ virtual ~Echo_Suppression() = default; }; /** * Suppress echo on the terminal * Returns null if this operation is not supported on the current system. */ std::unique_ptr BOTAN_UNSTABLE_API suppress_echo_on_terminal(); } } #endif