Botan  2.13.0
Crypto and TLS for C++11
Classes | Functions
Botan::OS Namespace Reference

Classes

class  Echo_Suppression
 
class  Socket
 
class  SocketUDP
 

Functions

std::vector< void * > allocate_locked_pages (size_t count)
 
void free_locked_pages (const std::vector< void * > &pages)
 
unsigned long get_auxval (unsigned long id)
 
size_t BOTAN_TEST_API get_cpu_available ()
 
uint64_t BOTAN_TEST_API get_cpu_cycle_counter ()
 
size_t BOTAN_TEST_API get_cpu_total ()
 
uint64_t BOTAN_TEST_API get_high_resolution_clock ()
 
size_t get_memory_locking_limit ()
 
uint32_t BOTAN_TEST_API get_process_id ()
 
uint64_t BOTAN_TEST_API get_system_timestamp_ns ()
 
std::unique_ptr< Socket > BOTAN_TEST_API open_socket (const std::string &hostname, const std::string &service, std::chrono::milliseconds timeout)
 
std::unique_ptr< SocketUDP > BOTAN_TEST_API open_socket_udp (const std::string &hostname, const std::string &service, std::chrono::microseconds timeout)
 
std::unique_ptr< SocketUDP > BOTAN_TEST_API open_socket_udp (const std::string &uri, std::chrono::microseconds timeout)
 
void page_allow_access (void *page)
 
void page_prohibit_access (void *page)
 
bool read_env_variable (std::string &value_out, const std::string &var_name)
 
size_t read_env_variable_sz (const std::string &var_name, size_t def_value=0)
 
int BOTAN_TEST_API run_cpu_instruction_probe (std::function< int()> probe_fn)
 
bool running_in_privileged_state ()
 
std::unique_ptr< Echo_Suppression > BOTAN_UNSTABLE_API suppress_echo_on_terminal ()
 
size_t system_page_size ()
 

Function Documentation

std::vector< void * > Botan::OS::allocate_locked_pages ( size_t  count)

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.

Parameters
countrequested number of locked pages

Definition at line 459 of file os_utils.cpp.

References page_prohibit_access(), and system_page_size().

460  {
461 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
462  static const int locked_fd = get_locked_fd();
463 #endif
464 
465  std::vector<void*> result;
466  result.reserve(count);
467 
468  const size_t page_size = OS::system_page_size();
469 
470  for(size_t i = 0; i != count; ++i)
471  {
472  void* ptr = nullptr;
473 
474 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
475 
476 #if !defined(MAP_ANONYMOUS)
477  #define MAP_ANONYMOUS MAP_ANON
478 #endif
479 
480 #if !defined(MAP_NOCORE)
481 #if defined(MAP_CONCEAL)
482  #define MAP_NOCORE MAP_CONCEAL
483 #else
484  #define MAP_NOCORE 0
485 #endif
486 #endif
487 
488 #if !defined(PROT_MAX)
489  #define PROT_MAX(p) 0
490 #endif
491  const int pflags = PROT_READ | PROT_WRITE;
492 
493  ptr = ::mmap(nullptr, 2*page_size,
494  pflags | PROT_MAX(pflags),
495  MAP_ANONYMOUS | MAP_PRIVATE | MAP_NOCORE,
496  /*fd=*/locked_fd, /*offset=*/0);
497 
498  if(ptr == MAP_FAILED)
499  {
500  continue;
501  }
502 
503  // failed to lock
504  if(::mlock(ptr, page_size) != 0)
505  {
506  ::munmap(ptr, 2*page_size);
507  continue;
508  }
509 
510 #if defined(MADV_DONTDUMP)
511  // we ignore errors here, as DONTDUMP is just a bonus
512  ::madvise(ptr, page_size, MADV_DONTDUMP);
513 #endif
514 
515 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
516  ptr = ::VirtualAlloc(nullptr, 2*page_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
517 
518  if(ptr == nullptr)
519  continue;
520 
521  if(::VirtualLock(ptr, page_size) == 0)
522  {
523  ::VirtualFree(ptr, 0, MEM_RELEASE);
524  continue;
525  }
526 #endif
527 
528  std::memset(ptr, 0, 2*page_size); // zero both data and guard pages
529 
530  // Make guard page following the data page
531  page_prohibit_access(static_cast<uint8_t*>(ptr) + page_size);
532 
533  result.push_back(ptr);
534  }
535 
536  return result;
537  }
void page_prohibit_access(void *page)
Definition: os_utils.cpp:551
size_t system_page_size()
Definition: os_utils.cpp:307
void Botan::OS::free_locked_pages ( const std::vector< void * > &  pages)

Free memory allocated by allocate_locked_pages

Parameters
pagesa list of pages returned by allocate_locked_pages

Definition at line 563 of file os_utils.cpp.

References page_allow_access(), Botan::secure_scrub_memory(), and system_page_size().

564  {
565  const size_t page_size = OS::system_page_size();
566 
567  for(size_t i = 0; i != pages.size(); ++i)
568  {
569  void* ptr = pages[i];
570 
571  secure_scrub_memory(ptr, page_size);
572 
573  // ptr points to the data page, guard page follows
574  page_allow_access(static_cast<uint8_t*>(ptr) + page_size);
575 
576 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
577  ::munlock(ptr, page_size);
578  ::munmap(ptr, 2*page_size);
579 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
580  ::VirtualUnlock(ptr, page_size);
581  ::VirtualFree(ptr, 0, MEM_RELEASE);
582 #endif
583  }
584  }
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:66
size_t system_page_size()
Definition: os_utils.cpp:307
void page_allow_access(void *page)
Definition: os_utils.cpp:539
unsigned long Botan::OS::get_auxval ( unsigned long  id)

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.

Definition at line 109 of file os_utils.cpp.

References BOTAN_UNUSED.

Referenced by running_in_privileged_state().

110  {
111 #if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
112  return ::getauxval(id);
113 #elif defined(BOTAN_TARGET_OS_IS_ANDROID) && defined(BOTAN_TARGET_ARCH_IS_ARM32)
114 
115  if(id == 0)
116  return 0;
117 
118  char **p = environ;
119 
120  while(*p++ != nullptr)
121  ;
122 
123  Elf32_auxv_t *e = reinterpret_cast<Elf32_auxv_t*>(p);
124 
125  while(e != nullptr)
126  {
127  if(e->a_type == id)
128  return e->a_un.a_val;
129  e++;
130  }
131 
132  return 0;
133 #elif defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
134  unsigned long auxinfo = 0;
135  ::elf_aux_info(id, &auxinfo, sizeof(auxinfo));
136  return auxinfo;
137 #else
138  BOTAN_UNUSED(id);
139  return 0;
140 #endif
141  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
size_t Botan::OS::get_cpu_available ( )

Definition at line 230 of file os_utils.cpp.

References get_cpu_total().

Referenced by Botan::Thread_Pool::Thread_Pool().

231  {
232 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_ONLN)
233  const long res = ::sysconf(_SC_NPROCESSORS_ONLN);
234  if(res > 0)
235  return static_cast<size_t>(res);
236 #endif
237 
238  return OS::get_cpu_total();
239  }
size_t BOTAN_TEST_API get_cpu_total()
Definition: os_utils.cpp:215
uint64_t Botan::OS::get_cpu_cycle_counter ( )
Returns
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.

Definition at line 154 of file os_utils.cpp.

Referenced by get_high_resolution_clock(), Botan::Timer::start(), and Botan::Timer::stop().

155  {
156  uint64_t rtc = 0;
157 
158 #if defined(BOTAN_TARGET_OS_HAS_WIN32)
159  LARGE_INTEGER tv;
160  ::QueryPerformanceCounter(&tv);
161  rtc = tv.QuadPart;
162 
163 #elif defined(BOTAN_USE_GCC_INLINE_ASM)
164 
165 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
166 
167  if(CPUID::has_rdtsc())
168  {
169  uint32_t rtc_low = 0, rtc_high = 0;
170  asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low));
171  rtc = (static_cast<uint64_t>(rtc_high) << 32) | rtc_low;
172  }
173 
174 #elif defined(BOTAN_TARGET_ARCH_IS_PPC64)
175 
176  for(;;)
177  {
178  uint32_t rtc_low = 0, rtc_high = 0, rtc_high2 = 0;
179  asm volatile("mftbu %0" : "=r" (rtc_high));
180  asm volatile("mftb %0" : "=r" (rtc_low));
181  asm volatile("mftbu %0" : "=r" (rtc_high2));
182 
183  if(rtc_high == rtc_high2)
184  {
185  rtc = (static_cast<uint64_t>(rtc_high) << 32) | rtc_low;
186  break;
187  }
188  }
189 
190 #elif defined(BOTAN_TARGET_ARCH_IS_ALPHA)
191  asm volatile("rpcc %0" : "=r" (rtc));
192 
193  // OpenBSD does not trap access to the %tick register
194 #elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD)
195  asm volatile("rd %%tick, %0" : "=r" (rtc));
196 
197 #elif defined(BOTAN_TARGET_ARCH_IS_IA64)
198  asm volatile("mov %0=ar.itc" : "=r" (rtc));
199 
200 #elif defined(BOTAN_TARGET_ARCH_IS_S390X)
201  asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc");
202 
203 #elif defined(BOTAN_TARGET_ARCH_IS_HPPA)
204  asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only?
205 
206 #else
207  //#warning "OS::get_cpu_cycle_counter not implemented"
208 #endif
209 
210 #endif
211 
212  return rtc;
213  }
size_t Botan::OS::get_cpu_total ( )

Definition at line 215 of file os_utils.cpp.

Referenced by get_cpu_available().

216  {
217 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_CONF)
218  const long res = ::sysconf(_SC_NPROCESSORS_CONF);
219  if(res > 0)
220  return static_cast<size_t>(res);
221 #endif
222 
223 #if defined(BOTAN_TARGET_OS_HAS_THREADS)
224  return static_cast<size_t>(std::thread::hardware_concurrency());
225 #else
226  return 1;
227 #endif
228  }
uint64_t Botan::OS::get_high_resolution_clock ( )

Definition at line 241 of file os_utils.cpp.

References get_cpu_cycle_counter().

Referenced by Botan::Stateful_RNG::randomize_with_ts_input(), and Botan::RandomNumberGenerator::randomize_with_ts_input().

242  {
243  if(uint64_t cpu_clock = OS::get_cpu_cycle_counter())
244  return cpu_clock;
245 
246 #if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
247  return emscripten_get_now();
248 #endif
249 
250  /*
251  If we got here either we either don't have an asm instruction
252  above, or (for x86) RDTSC is not available at runtime. Try some
253  clock_gettimes and return the first one that works, or otherwise
254  fall back to std::chrono.
255  */
256 
257 #if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
258 
259  // The ordering here is somewhat arbitrary...
260  const clockid_t clock_types[] = {
261 #if defined(CLOCK_MONOTONIC_HR)
262  CLOCK_MONOTONIC_HR,
263 #endif
264 #if defined(CLOCK_MONOTONIC_RAW)
265  CLOCK_MONOTONIC_RAW,
266 #endif
267 #if defined(CLOCK_MONOTONIC)
268  CLOCK_MONOTONIC,
269 #endif
270 #if defined(CLOCK_PROCESS_CPUTIME_ID)
271  CLOCK_PROCESS_CPUTIME_ID,
272 #endif
273 #if defined(CLOCK_THREAD_CPUTIME_ID)
274  CLOCK_THREAD_CPUTIME_ID,
275 #endif
276  };
277 
278  for(clockid_t clock : clock_types)
279  {
280  struct timespec ts;
281  if(::clock_gettime(clock, &ts) == 0)
282  {
283  return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
284  }
285  }
286 #endif
287 
288  // Plain C++11 fallback
289  auto now = std::chrono::high_resolution_clock::now().time_since_epoch();
290  return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
291  }
uint64_t BOTAN_TEST_API get_cpu_cycle_counter()
Definition: os_utils.cpp:154
size_t Botan::OS::get_memory_locking_limit ( )
Returns
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.

Definition at line 327 of file os_utils.cpp.

References read_env_variable_sz(), and system_page_size().

328  {
329 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) && defined(RLIMIT_MEMLOCK)
330  /*
331  * If RLIMIT_MEMLOCK is not defined, likely the OS does not support
332  * unprivileged mlock calls.
333  *
334  * Linux defaults to only 64 KiB of mlockable memory per process
335  * (too small) but BSDs offer a small fraction of total RAM (more
336  * than we need). Bound the total mlock size to 512 KiB which is
337  * enough to run the entire test suite without spilling to non-mlock
338  * memory (and thus presumably also enough for many useful
339  * programs), but small enough that we should not cause problems
340  * even if many processes are mlocking on the same machine.
341  */
342  const size_t user_req = read_env_variable_sz("BOTAN_MLOCK_POOL_SIZE", BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB);
343 
344  const size_t mlock_requested = std::min<size_t>(user_req, BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB);
345 
346  if(mlock_requested > 0)
347  {
348  struct ::rlimit limits;
349 
350  ::getrlimit(RLIMIT_MEMLOCK, &limits);
351 
352  if(limits.rlim_cur < limits.rlim_max)
353  {
354  limits.rlim_cur = limits.rlim_max;
355  ::setrlimit(RLIMIT_MEMLOCK, &limits);
356  ::getrlimit(RLIMIT_MEMLOCK, &limits);
357  }
358 
359  return std::min<size_t>(limits.rlim_cur, mlock_requested * 1024);
360  }
361 
362 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
363  SIZE_T working_min = 0, working_max = 0;
364  if(!::GetProcessWorkingSetSize(::GetCurrentProcess(), &working_min, &working_max))
365  {
366  return 0;
367  }
368 
369  // According to Microsoft MSDN:
370  // The maximum number of pages that a process can lock is equal to the number of pages in its minimum working set minus a small overhead
371  // In the book "Windows Internals Part 2": the maximum lockable pages are minimum working set size - 8 pages
372  // But the information in the book seems to be inaccurate/outdated
373  // I've tested this on Windows 8.1 x64, Windows 10 x64 and Windows 7 x86
374  // On all three OS the value is 11 instead of 8
375  const size_t overhead = OS::system_page_size() * 11;
376  if(working_min > overhead)
377  {
378  const size_t lockable_bytes = working_min - overhead;
379  return std::min<size_t>(lockable_bytes, BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB * 1024);
380  }
381 #endif
382 
383  // Not supported on this platform
384  return 0;
385  }
size_t read_env_variable_sz(const std::string &var_name, size_t def_value=0)
Definition: os_utils.cpp:413
size_t system_page_size()
Definition: os_utils.cpp:307
uint32_t Botan::OS::get_process_id ( )
Returns
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.

Definition at line 96 of file os_utils.cpp.

Referenced by Botan::Stateful_RNG::reseed_check().

97  {
98 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
99  return ::getpid();
100 #elif defined(BOTAN_TARGET_OS_HAS_WIN32)
101  return ::GetCurrentProcessId();
102 #elif defined(BOTAN_TARGET_OS_IS_INCLUDEOS) || defined(BOTAN_TARGET_OS_IS_LLVM)
103  return 0; // truly no meaningful value
104 #else
105  #error "Missing get_process_id"
106 #endif
107  }
uint64_t Botan::OS::get_system_timestamp_ns ( )
Returns
system clock (reflecting wall clock) with best resolution available, normalized to nanoseconds resolution.

Definition at line 293 of file os_utils.cpp.

Referenced by Botan::Stateful_RNG::randomize_with_ts_input(), Botan::RandomNumberGenerator::randomize_with_ts_input(), Botan::Timer::start(), and Botan::Timer::stop().

294  {
295 #if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
296  struct timespec ts;
297  if(::clock_gettime(CLOCK_REALTIME, &ts) == 0)
298  {
299  return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
300  }
301 #endif
302 
303  auto now = std::chrono::system_clock::now().time_since_epoch();
304  return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
305  }
std::unique_ptr< OS::Socket > Botan::OS::open_socket ( const std::string &  hostname,
const std::string &  service,
std::chrono::milliseconds  timeout 
)

Open up a socket. Will throw on error. Returns null if sockets are not available on this platform.

Definition at line 352 of file socket.cpp.

References BOTAN_UNUSED.

355  {
356 #if defined(BOTAN_HAS_BOOST_ASIO)
357  return std::unique_ptr<OS::Socket>(new Asio_Socket(hostname, service, timeout));
358 
359 #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2)
360  return std::unique_ptr<OS::Socket>(new BSD_Socket(hostname, service, timeout));
361 
362 #else
363  BOTAN_UNUSED(hostname);
364  BOTAN_UNUSED(service);
365  BOTAN_UNUSED(timeout);
366  // No sockets for you
367  return std::unique_ptr<Socket>();
368 #endif
369  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
std::unique_ptr< OS::SocketUDP > Botan::OS::open_socket_udp ( const std::string &  hostname,
const std::string &  service,
std::chrono::microseconds  timeout 
)

Open up a socket. Will throw on error. Returns null if sockets are not available on this platform.

Definition at line 316 of file socket_udp.cpp.

References BOTAN_UNUSED.

Referenced by Botan::Roughtime::online_request(), and open_socket_udp().

319  {
320 #if defined(BOTAN_HAS_BOOST_ASIO)
321  return std::unique_ptr<OS::SocketUDP>(new Asio_SocketUDP(hostname, service, timeout));
322 #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2)
323  return std::unique_ptr<OS::SocketUDP>(new BSD_SocketUDP(hostname, service, timeout));
324 #else
325  BOTAN_UNUSED(hostname);
326  BOTAN_UNUSED(service);
327  BOTAN_UNUSED(timeout);
328  return std::unique_ptr<OS::SocketUDP>();
329 #endif
330  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
std::unique_ptr< OS::SocketUDP > Botan::OS::open_socket_udp ( const std::string &  uri,
std::chrono::microseconds  timeout 
)

Open up a socket. Will throw on error. Returns null if sockets are not available on this platform.

Definition at line 333 of file socket_udp.cpp.

References Botan::URI::fromAny(), open_socket_udp(), and Botan::ASN1::to_string().

335  {
336  const auto uri = URI::fromAny(uri_string);
337  if(uri.port == 0)
338  { throw Invalid_Argument("UDP port not specified"); }
339  return open_socket_udp(uri.host, std::to_string(uri.port), timeout);
340  }
std::unique_ptr< SocketUDP > BOTAN_TEST_API open_socket_udp(const std::string &hostname, const std::string &service, std::chrono::microseconds timeout)
Definition: socket_udp.cpp:316
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
void Botan::OS::page_allow_access ( void *  page)

Set the MMU to allow R/W access to this page

Definition at line 539 of file os_utils.cpp.

References BOTAN_UNUSED, and system_page_size().

Referenced by Botan::Memory_Pool::allocate(), free_locked_pages(), Botan::Sodium::sodium_mprotect_readwrite(), and Botan::Memory_Pool::~Memory_Pool().

540  {
541  const size_t page_size = OS::system_page_size();
542 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
543  ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
544 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
545  DWORD old_perms = 0;
546  ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
547  BOTAN_UNUSED(old_perms);
548 #endif
549  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
size_t system_page_size()
Definition: os_utils.cpp:307
void Botan::OS::page_prohibit_access ( void *  page)

Set the MMU to prohibit access to this page

Definition at line 551 of file os_utils.cpp.

References BOTAN_UNUSED, and system_page_size().

Referenced by allocate_locked_pages(), Botan::Memory_Pool::deallocate(), Botan::Memory_Pool::Memory_Pool(), and Botan::Sodium::sodium_mprotect_noaccess().

552  {
553  const size_t page_size = OS::system_page_size();
554 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
555  ::mprotect(page, page_size, PROT_NONE);
556 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
557  DWORD old_perms = 0;
558  ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms);
559  BOTAN_UNUSED(old_perms);
560 #endif
561  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
size_t system_page_size()
Definition: os_utils.cpp:307
bool Botan::OS::read_env_variable ( std::string &  value_out,
const std::string &  var_name 
)

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.

Definition at line 387 of file os_utils.cpp.

References running_in_privileged_state().

Referenced by Botan_FFI::ffi_error_exception_thrown(), and read_env_variable_sz().

388  {
389  value_out = "";
390 
392  return false;
393 
394 #if defined(BOTAN_TARGET_OS_HAS_WIN32) && defined(BOTAN_BUILD_COMPILER_IS_MSVC)
395  char val[128] = { 0 };
396  size_t req_size = 0;
397  if(getenv_s(&req_size, val, sizeof(val), name.c_str()) == 0)
398  {
399  value_out = std::string(val, req_size);
400  return true;
401  }
402 #else
403  if(const char* val = std::getenv(name.c_str()))
404  {
405  value_out = val;
406  return true;
407  }
408 #endif
409 
410  return false;
411  }
bool running_in_privileged_state()
Definition: os_utils.cpp:143
std::string name
size_t Botan::OS::read_env_variable_sz ( const std::string &  var_name,
size_t  def_value = 0 
)

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.

Definition at line 413 of file os_utils.cpp.

References read_env_variable().

Referenced by get_memory_locking_limit(), and Botan::Thread_Pool::global_instance().

414  {
415  std::string value;
416  if(read_env_variable(value, name))
417  {
418  try
419  {
420  const size_t val = std::stoul(value, nullptr);
421  return val;
422  }
423  catch(std::exception&) { /* ignore it */ }
424  }
425 
426  return def;
427  }
bool read_env_variable(std::string &value_out, const std::string &var_name)
Definition: os_utils.cpp:387
std::string name
int Botan::OS::run_cpu_instruction_probe ( std::function< int()>  probe_fn)

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

Definition at line 601 of file os_utils.cpp.

References BOTAN_UNUSED.

602  {
603  volatile int probe_result = -3;
604 
605 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
606  struct sigaction old_sigaction;
607  struct sigaction sigaction;
608 
609  sigaction.sa_handler = botan_sigill_handler;
610  sigemptyset(&sigaction.sa_mask);
611  sigaction.sa_flags = 0;
612 
613  int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction);
614 
615  if(rc != 0)
616  throw System_Error("run_cpu_instruction_probe sigaction failed", errno);
617 
618  rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1);
619 
620  if(rc == 0)
621  {
622  // first call to sigsetjmp
623  probe_result = probe_fn();
624  }
625  else if(rc == 1)
626  {
627  // non-local return from siglongjmp in signal handler: return error
628  probe_result = -1;
629  }
630 
631  // Restore old SIGILL handler, if any
632  rc = ::sigaction(SIGILL, &old_sigaction, nullptr);
633  if(rc != 0)
634  throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno);
635 
636 #else
637  BOTAN_UNUSED(probe_fn);
638 #endif
639 
640  return probe_result;
641  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
bool Botan::OS::running_in_privileged_state ( )

Test if we are currently running with elevated permissions eg setuid, setgid, or with POSIX caps set.

Definition at line 143 of file os_utils.cpp.

References get_auxval().

Referenced by Botan::Entropy_Source::create(), and read_env_variable().

144  {
145 #if defined(AT_SECURE)
146  return OS::get_auxval(AT_SECURE) != 0;
147 #elif defined(BOTAN_TARGET_OS_HAS_POSIX1)
148  return (::getuid() != ::geteuid()) || (::getgid() != ::getegid());
149 #else
150  return false;
151 #endif
152  }
unsigned long get_auxval(unsigned long id)
Definition: os_utils.cpp:109
std::unique_ptr< OS::Echo_Suppression > Botan::OS::suppress_echo_on_terminal ( )

Suppress echo on the terminal Returns null if this operation is not supported on the current system.

Definition at line 643 of file os_utils.cpp.

644  {
645 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
646  class POSIX_Echo_Suppression : public Echo_Suppression
647  {
648  public:
649  POSIX_Echo_Suppression()
650  {
651  m_stdin_fd = fileno(stdin);
652  if(::tcgetattr(m_stdin_fd, &m_old_termios) != 0)
653  throw System_Error("Getting terminal status failed", errno);
654 
655  struct termios noecho_flags = m_old_termios;
656  noecho_flags.c_lflag &= ~ECHO;
657  noecho_flags.c_lflag |= ECHONL;
658 
659  if(::tcsetattr(m_stdin_fd, TCSANOW, &noecho_flags) != 0)
660  throw System_Error("Clearing terminal echo bit failed", errno);
661  }
662 
663  void reenable_echo() override
664  {
665  if(m_stdin_fd > 0)
666  {
667  if(::tcsetattr(m_stdin_fd, TCSANOW, &m_old_termios) != 0)
668  throw System_Error("Restoring terminal echo bit failed", errno);
669  m_stdin_fd = -1;
670  }
671  }
672 
673  ~POSIX_Echo_Suppression()
674  {
675  try
676  {
677  reenable_echo();
678  }
679  catch(...)
680  {
681  }
682  }
683 
684  private:
685  int m_stdin_fd;
686  struct termios m_old_termios;
687  };
688 
689  return std::unique_ptr<Echo_Suppression>(new POSIX_Echo_Suppression);
690 
691 #elif defined(BOTAN_TARGET_OS_HAS_WIN32)
692 
693  class Win32_Echo_Suppression : public Echo_Suppression
694  {
695  public:
696  Win32_Echo_Suppression()
697  {
698  m_input_handle = ::GetStdHandle(STD_INPUT_HANDLE);
699  if(::GetConsoleMode(m_input_handle, &m_console_state) == 0)
700  throw System_Error("Getting console mode failed", ::GetLastError());
701 
702  DWORD new_mode = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
703  if(::SetConsoleMode(m_input_handle, new_mode) == 0)
704  throw System_Error("Setting console mode failed", ::GetLastError());
705  }
706 
707  void reenable_echo() override
708  {
709  if(m_input_handle != INVALID_HANDLE_VALUE)
710  {
711  if(::SetConsoleMode(m_input_handle, m_console_state) == 0)
712  throw System_Error("Setting console mode failed", ::GetLastError());
713  m_input_handle = INVALID_HANDLE_VALUE;
714  }
715  }
716 
717  ~Win32_Echo_Suppression()
718  {
719  try
720  {
721  reenable_echo();
722  }
723  catch(...)
724  {
725  }
726  }
727 
728  private:
729  HANDLE m_input_handle;
730  DWORD m_console_state;
731  };
732 
733  return std::unique_ptr<Echo_Suppression>(new Win32_Echo_Suppression);
734 
735 #else
736 
737  // Not supported on this platform, return null
738  return std::unique_ptr<Echo_Suppression>();
739 #endif
740  }
size_t Botan::OS::system_page_size ( )

Return the size of a memory page, if that can be derived on the current system. Otherwise returns some default value (eg 4096)

Definition at line 307 of file os_utils.cpp.

References BOTAN_UNUSED.

Referenced by allocate_locked_pages(), free_locked_pages(), get_memory_locking_limit(), page_allow_access(), and page_prohibit_access().

308  {
309  const size_t default_page_size = 4096;
310 
311 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
312  long p = ::sysconf(_SC_PAGESIZE);
313  if(p > 1)
314  return static_cast<size_t>(p);
315  else
316  return default_page_size;
317 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
318  BOTAN_UNUSED(default_page_size);
319  SYSTEM_INFO sys_info;
320  ::GetSystemInfo(&sys_info);
321  return sys_info.dwPageSize;
322 #else
323  return default_page_size;
324 #endif
325  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142