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

Classes

class  Echo_Suppression
 
class  Socket
 

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)
 
void page_allow_access (void *page)
 
void page_prohibit_access (void *page)
 
const char * read_env_variable (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

◆ allocate_locked_pages()

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 405 of file os_utils.cpp.

References page_prohibit_access(), and system_page_size().

406  {
407  std::vector<void*> result;
408  result.reserve(count);
409 
410  const size_t page_size = OS::system_page_size();
411 
412  for(size_t i = 0; i != count; ++i)
413  {
414  void* ptr = nullptr;
415 
416 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
417 
418 #if !defined(MAP_NOCORE)
419 #if defined(MAP_CONCEAL)
420  #define MAP_NOCORE MAP_CONCEAL
421 #else
422  #define MAP_NOCORE 0
423 #endif
424 #endif
425 #if !defined(PROT_MAX)
426  #define PROT_MAX(p) 0
427 #endif
428  int pflags = PROT_READ | PROT_WRITE;
429 
430  ptr = ::mmap(nullptr, 2*page_size,
431  pflags | PROT_MAX(pflags),
432  MAP_ANONYMOUS | MAP_PRIVATE | MAP_NOCORE,
433  /*fd=*/-1, /*offset=*/0);
434 
435  if(ptr == MAP_FAILED)
436  {
437  continue;
438  }
439 
440  // failed to lock
441  if(::mlock(ptr, page_size) != 0)
442  {
443  ::munmap(ptr, 2*page_size);
444  continue;
445  }
446 
447 #if defined(MADV_DONTDUMP)
448  // we ignore errors here, as DONTDUMP is just a bonus
449  ::madvise(ptr, page_size, MADV_DONTDUMP);
450 #endif
451 
452 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
453  ptr = ::VirtualAlloc(nullptr, 2*page_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
454 
455  if(ptr == nullptr)
456  continue;
457 
458  if(::VirtualLock(ptr, page_size) == 0)
459  {
460  ::VirtualFree(ptr, 0, MEM_RELEASE);
461  continue;
462  }
463 #endif
464 
465  std::memset(ptr, 0, 2*page_size); // zero both data and guard pages
466 
467  // Make guard page following the data page
468  page_prohibit_access(static_cast<uint8_t*>(ptr) + page_size);
469 
470  result.push_back(ptr);
471  }
472 
473  return result;
474  }
void page_prohibit_access(void *page)
Definition: os_utils.cpp:488
size_t system_page_size()
Definition: os_utils.cpp:303

◆ free_locked_pages()

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 500 of file os_utils.cpp.

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

501  {
502  const size_t page_size = OS::system_page_size();
503 
504  for(size_t i = 0; i != pages.size(); ++i)
505  {
506  void* ptr = pages[i];
507 
508  secure_scrub_memory(ptr, page_size);
509 
510  // ptr points to the data page, guard page follows
511  page_allow_access(static_cast<uint8_t*>(ptr) + page_size);
512 
513 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
514  ::munlock(ptr, page_size);
515  ::munmap(ptr, 2*page_size);
516 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
517  ::VirtualUnlock(ptr, page_size);
518  ::VirtualFree(ptr, 0, MEM_RELEASE);
519 #endif
520  }
521  }
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:61
size_t system_page_size()
Definition: os_utils.cpp:303
void page_allow_access(void *page)
Definition: os_utils.cpp:476

◆ get_auxval()

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 104 of file os_utils.cpp.

References BOTAN_UNUSED.

Referenced by running_in_privileged_state().

105  {
106 #if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
107  return ::getauxval(id);
108 #elif defined(BOTAN_TARGET_OS_IS_ANDROID)
109  char **p = environ;
110 
111  while (*p++!=nullptr);
112 
113  Elf32_auxv_t *e = reinterpret_cast<Elf32_auxv_t *>(p);
114 
115  while (e!=nullptr)
116  {
117  if (e->a_type == 0)
118  continue;
119  if (e->a_type == id)
120  return e->a_un.a_val;
121  e++;
122  }
123 
124  return 0;
125 #elif defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
126  unsigned long auxinfo = 0;
127  ::elf_aux_info(id, &auxinfo, sizeof(auxinfo));
128  return auxinfo;
129 #else
130  BOTAN_UNUSED(id);
131  return 0;
132 #endif
133  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142

◆ get_cpu_available()

size_t Botan::OS::get_cpu_available ( )

Definition at line 223 of file os_utils.cpp.

References get_cpu_total().

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

224  {
225 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_ONLN)
226  long res;
227  if ((res = ::sysconf(_SC_NPROCESSORS_ONLN)) <= 0)
228  {
229  return 1;
230  }
231  return static_cast<size_t>(res);
232 #else
233  return get_cpu_total();
234 #endif
235  }
size_t BOTAN_TEST_API get_cpu_total()
Definition: os_utils.cpp:207

◆ get_cpu_cycle_counter()

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 146 of file os_utils.cpp.

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

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

◆ get_cpu_total()

size_t Botan::OS::get_cpu_total ( )

Definition at line 207 of file os_utils.cpp.

Referenced by get_cpu_available().

208  {
209  size_t tt = 1;
210 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_CONF)
211  long res;
212  if ((res = ::sysconf(_SC_NPROCESSORS_CONF)) <= 0)
213  {
214  return 1;
215  }
216  tt = static_cast<size_t>(res);
217 #elif defined(BOTAN_TARGET_OS_HAS_THREADS)
218  tt = static_cast<size_t>(std::thread::hardware_concurrency());
219 #endif
220  return tt;
221  }

◆ get_high_resolution_clock()

uint64_t Botan::OS::get_high_resolution_clock ( )

Definition at line 237 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().

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

◆ get_memory_locking_limit()

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 322 of file os_utils.cpp.

References read_env_variable_sz(), and system_page_size().

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

◆ get_process_id()

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 91 of file os_utils.cpp.

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

92  {
93 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
94  return ::getpid();
95 #elif defined(BOTAN_TARGET_OS_HAS_WIN32)
96  return ::GetCurrentProcessId();
97 #elif defined(BOTAN_TARGET_OS_IS_INCLUDEOS) || defined(BOTAN_TARGET_OS_IS_LLVM)
98  return 0; // truly no meaningful value
99 #else
100  #error "Missing get_process_id"
101 #endif
102  }

◆ get_system_timestamp_ns()

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 289 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().

290  {
291 #if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
292  struct timespec ts;
293  if(::clock_gettime(CLOCK_REALTIME, &ts) == 0)
294  {
295  return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
296  }
297 #endif
298 
299  auto now = std::chrono::system_clock::now().time_since_epoch();
300  return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
301  }

◆ open_socket()

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 356 of file socket.cpp.

359  {
360 #if defined(BOTAN_HAS_BOOST_ASIO)
361  return std::unique_ptr<OS::Socket>(new Asio_Socket(hostname, service, timeout));
362 
363 #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2)
364  return std::unique_ptr<OS::Socket>(new BSD_Socket(hostname, service, timeout));
365 
366 #else
367  // No sockets for you
368  return std::unique_ptr<Socket>();
369 #endif
370  }

◆ page_allow_access()

void Botan::OS::page_allow_access ( void *  page)

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

Definition at line 476 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().

477  {
478  const size_t page_size = OS::system_page_size();
479 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
480  ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
481 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
482  DWORD old_perms = 0;
483  ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
484  BOTAN_UNUSED(old_perms);
485 #endif
486  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
size_t system_page_size()
Definition: os_utils.cpp:303

◆ page_prohibit_access()

void Botan::OS::page_prohibit_access ( void *  page)

Set the MMU to prohibit access to this page

Definition at line 488 of file os_utils.cpp.

References BOTAN_UNUSED, and system_page_size().

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

489  {
490  const size_t page_size = OS::system_page_size();
491 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
492  ::mprotect(page, page_size, PROT_NONE);
493 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
494  DWORD old_perms = 0;
495  ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms);
496  BOTAN_UNUSED(old_perms);
497 #endif
498  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
size_t system_page_size()
Definition: os_utils.cpp:303

◆ read_env_variable()

const char * Botan::OS::read_env_variable ( const std::string &  var_name)

Read the value of an environment variable. Return nullptr if no such variable is set. 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 382 of file os_utils.cpp.

References name, and running_in_privileged_state().

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

383  {
385  return nullptr;
386 
387  return std::getenv(name.c_str());
388  }
bool running_in_privileged_state()
Definition: os_utils.cpp:135
std::string name

◆ read_env_variable_sz()

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 390 of file os_utils.cpp.

References name, and read_env_variable().

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

391  {
392  if(const char* env = read_env_variable(name))
393  {
394  try
395  {
396  const size_t val = std::stoul(env, nullptr);
397  return val;
398  }
399  catch(std::exception&) { /* ignore it */ }
400  }
401 
402  return def;
403  }
std::string name
const char * read_env_variable(const std::string &var_name)
Definition: os_utils.cpp:382

◆ run_cpu_instruction_probe()

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 538 of file os_utils.cpp.

References BOTAN_UNUSED.

539  {
540  volatile int probe_result = -3;
541 
542 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
543  struct sigaction old_sigaction;
544  struct sigaction sigaction;
545 
546  sigaction.sa_handler = botan_sigill_handler;
547  sigemptyset(&sigaction.sa_mask);
548  sigaction.sa_flags = 0;
549 
550  int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction);
551 
552  if(rc != 0)
553  throw System_Error("run_cpu_instruction_probe sigaction failed", errno);
554 
555  rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1);
556 
557  if(rc == 0)
558  {
559  // first call to sigsetjmp
560  probe_result = probe_fn();
561  }
562  else if(rc == 1)
563  {
564  // non-local return from siglongjmp in signal handler: return error
565  probe_result = -1;
566  }
567 
568  // Restore old SIGILL handler, if any
569  rc = ::sigaction(SIGILL, &old_sigaction, nullptr);
570  if(rc != 0)
571  throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno);
572 
573 #elif defined(BOTAN_TARGET_OS_IS_WINDOWS) && defined(BOTAN_TARGET_COMPILER_IS_MSVC)
574 
575  // Windows SEH
576  __try
577  {
578  probe_result = probe_fn();
579  }
580  __except(::GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ?
581  EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
582  {
583  probe_result = -1;
584  }
585 
586 #else
587  BOTAN_UNUSED(probe_fn);
588 #endif
589 
590  return probe_result;
591  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142

◆ running_in_privileged_state()

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 135 of file os_utils.cpp.

References get_auxval().

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

136  {
137 #if defined(AT_SECURE)
138  return OS::get_auxval(AT_SECURE) != 0;
139 #elif defined(BOTAN_TARGET_OS_HAS_POSIX1)
140  return (::getuid() != ::geteuid()) || (::getgid() != ::getegid());
141 #else
142  return false;
143 #endif
144  }
unsigned long get_auxval(unsigned long id)
Definition: os_utils.cpp:104

◆ suppress_echo_on_terminal()

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 593 of file os_utils.cpp.

594  {
595 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
596  class POSIX_Echo_Suppression : public Echo_Suppression
597  {
598  public:
599  POSIX_Echo_Suppression()
600  {
601  m_stdin_fd = fileno(stdin);
602  if(::tcgetattr(m_stdin_fd, &m_old_termios) != 0)
603  throw System_Error("Getting terminal status failed", errno);
604 
605  struct termios noecho_flags = m_old_termios;
606  noecho_flags.c_lflag &= ~ECHO;
607  noecho_flags.c_lflag |= ECHONL;
608 
609  if(::tcsetattr(m_stdin_fd, TCSANOW, &noecho_flags) != 0)
610  throw System_Error("Clearing terminal echo bit failed", errno);
611  }
612 
613  void reenable_echo() override
614  {
615  if(m_stdin_fd > 0)
616  {
617  if(::tcsetattr(m_stdin_fd, TCSANOW, &m_old_termios) != 0)
618  throw System_Error("Restoring terminal echo bit failed", errno);
619  m_stdin_fd = -1;
620  }
621  }
622 
623  ~POSIX_Echo_Suppression()
624  {
625  try
626  {
627  reenable_echo();
628  }
629  catch(...)
630  {
631  }
632  }
633 
634  private:
635  int m_stdin_fd;
636  struct termios m_old_termios;
637  };
638 
639  return std::unique_ptr<Echo_Suppression>(new POSIX_Echo_Suppression);
640 
641 #elif defined(BOTAN_TARGET_OS_HAS_WIN32)
642 
643  class Win32_Echo_Suppression : public Echo_Suppression
644  {
645  public:
646  Win32_Echo_Suppression()
647  {
648  m_input_handle = ::GetStdHandle(STD_INPUT_HANDLE);
649  if(::GetConsoleMode(m_input_handle, &m_console_state) == 0)
650  throw System_Error("Getting console mode failed", ::GetLastError());
651 
652  DWORD new_mode = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
653  if(::SetConsoleMode(m_input_handle, new_mode) == 0)
654  throw System_Error("Setting console mode failed", ::GetLastError());
655  }
656 
657  void reenable_echo() override
658  {
659  if(m_input_handle != INVALID_HANDLE_VALUE)
660  {
661  if(::SetConsoleMode(m_input_handle, m_console_state) == 0)
662  throw System_Error("Setting console mode failed", ::GetLastError());
663  m_input_handle = INVALID_HANDLE_VALUE;
664  }
665  }
666 
667  ~Win32_Echo_Suppression()
668  {
669  try
670  {
671  reenable_echo();
672  }
673  catch(...)
674  {
675  }
676  }
677 
678  private:
679  HANDLE m_input_handle;
680  DWORD m_console_state;
681  };
682 
683  return std::unique_ptr<Echo_Suppression>(new Win32_Echo_Suppression);
684 
685 #else
686 
687  // Not supported on this platform, return null
688  return std::unique_ptr<Echo_Suppression>();
689 #endif
690  }

◆ system_page_size()

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 303 of file os_utils.cpp.

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

304  {
305  const size_t default_page_size = 4096;
306 
307 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
308  long p = ::sysconf(_SC_PAGESIZE);
309  if(p > 1)
310  return static_cast<size_t>(p);
311  else
312  return default_page_size;
313 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
314  SYSTEM_INFO sys_info;
315  ::GetSystemInfo(&sys_info);
316  return sys_info.dwPageSize;
317 #else
318  return default_page_size;
319 #endif
320  }