Botan  2.12.1
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 438 of file os_utils.cpp.

References page_prohibit_access(), and system_page_size().

439  {
440 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
441  static const int locked_fd = get_locked_fd();
442 #endif
443 
444  std::vector<void*> result;
445  result.reserve(count);
446 
447  const size_t page_size = OS::system_page_size();
448 
449  for(size_t i = 0; i != count; ++i)
450  {
451  void* ptr = nullptr;
452 
453 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
454 
455 #if !defined(MAP_ANONYMOUS)
456  #define MAP_ANONYMOUS MAP_ANON
457 #endif
458 
459 #if !defined(MAP_NOCORE)
460 #if defined(MAP_CONCEAL)
461  #define MAP_NOCORE MAP_CONCEAL
462 #else
463  #define MAP_NOCORE 0
464 #endif
465 #endif
466 
467 #if !defined(PROT_MAX)
468  #define PROT_MAX(p) 0
469 #endif
470  const int pflags = PROT_READ | PROT_WRITE;
471 
472  ptr = ::mmap(nullptr, 2*page_size,
473  pflags | PROT_MAX(pflags),
474  MAP_ANONYMOUS | MAP_PRIVATE | MAP_NOCORE,
475  /*fd=*/locked_fd, /*offset=*/0);
476 
477  if(ptr == MAP_FAILED)
478  {
479  continue;
480  }
481 
482  // failed to lock
483  if(::mlock(ptr, page_size) != 0)
484  {
485  ::munmap(ptr, 2*page_size);
486  continue;
487  }
488 
489 #if defined(MADV_DONTDUMP)
490  // we ignore errors here, as DONTDUMP is just a bonus
491  ::madvise(ptr, page_size, MADV_DONTDUMP);
492 #endif
493 
494 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
495  ptr = ::VirtualAlloc(nullptr, 2*page_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
496 
497  if(ptr == nullptr)
498  continue;
499 
500  if(::VirtualLock(ptr, page_size) == 0)
501  {
502  ::VirtualFree(ptr, 0, MEM_RELEASE);
503  continue;
504  }
505 #endif
506 
507  std::memset(ptr, 0, 2*page_size); // zero both data and guard pages
508 
509  // Make guard page following the data page
510  page_prohibit_access(static_cast<uint8_t*>(ptr) + page_size);
511 
512  result.push_back(ptr);
513  }
514 
515  return result;
516  }
void page_prohibit_access(void *page)
Definition: os_utils.cpp:530
size_t system_page_size()
Definition: os_utils.cpp:306

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

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

543  {
544  const size_t page_size = OS::system_page_size();
545 
546  for(size_t i = 0; i != pages.size(); ++i)
547  {
548  void* ptr = pages[i];
549 
550  secure_scrub_memory(ptr, page_size);
551 
552  // ptr points to the data page, guard page follows
553  page_allow_access(static_cast<uint8_t*>(ptr) + page_size);
554 
555 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
556  ::munlock(ptr, page_size);
557  ::munmap(ptr, 2*page_size);
558 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
559  ::VirtualUnlock(ptr, page_size);
560  ::VirtualFree(ptr, 0, MEM_RELEASE);
561 #endif
562  }
563  }
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:65
size_t system_page_size()
Definition: os_utils.cpp:306
void page_allow_access(void *page)
Definition: os_utils.cpp:518

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

References BOTAN_UNUSED.

Referenced by running_in_privileged_state().

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

◆ get_cpu_available()

size_t Botan::OS::get_cpu_available ( )

Definition at line 229 of file os_utils.cpp.

References get_cpu_total().

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

230  {
231 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_ONLN)
232  const long res = ::sysconf(_SC_NPROCESSORS_ONLN);
233  if(res > 0)
234  return static_cast<size_t>(res);
235 #endif
236 
237  return OS::get_cpu_total();
238  }
size_t BOTAN_TEST_API get_cpu_total()
Definition: os_utils.cpp:214

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

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

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

◆ get_cpu_total()

size_t Botan::OS::get_cpu_total ( )

Definition at line 214 of file os_utils.cpp.

Referenced by get_cpu_available().

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

◆ get_high_resolution_clock()

uint64_t Botan::OS::get_high_resolution_clock ( )

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

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

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

References read_env_variable_sz(), and system_page_size().

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

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

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

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

◆ 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 292 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().

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

◆ 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 518 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().

519  {
520  const size_t page_size = OS::system_page_size();
521 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
522  ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
523 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
524  DWORD old_perms = 0;
525  ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
526  BOTAN_UNUSED(old_perms);
527 #endif
528  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
size_t system_page_size()
Definition: os_utils.cpp:306

◆ page_prohibit_access()

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

Set the MMU to prohibit access to this page

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

531  {
532  const size_t page_size = OS::system_page_size();
533 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
534  ::mprotect(page, page_size, PROT_NONE);
535 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
536  DWORD old_perms = 0;
537  ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms);
538  BOTAN_UNUSED(old_perms);
539 #endif
540  }
#define BOTAN_UNUSED(...)
Definition: assert.h:142
size_t system_page_size()
Definition: os_utils.cpp:306

◆ 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 385 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().

386  {
388  return nullptr;
389 
390  return std::getenv(name.c_str());
391  }
bool running_in_privileged_state()
Definition: os_utils.cpp:142
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 393 of file os_utils.cpp.

References name, and read_env_variable().

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

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

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

References BOTAN_UNUSED.

581  {
582  volatile int probe_result = -3;
583 
584 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
585  struct sigaction old_sigaction;
586  struct sigaction sigaction;
587 
588  sigaction.sa_handler = botan_sigill_handler;
589  sigemptyset(&sigaction.sa_mask);
590  sigaction.sa_flags = 0;
591 
592  int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction);
593 
594  if(rc != 0)
595  throw System_Error("run_cpu_instruction_probe sigaction failed", errno);
596 
597  rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1);
598 
599  if(rc == 0)
600  {
601  // first call to sigsetjmp
602  probe_result = probe_fn();
603  }
604  else if(rc == 1)
605  {
606  // non-local return from siglongjmp in signal handler: return error
607  probe_result = -1;
608  }
609 
610  // Restore old SIGILL handler, if any
611  rc = ::sigaction(SIGILL, &old_sigaction, nullptr);
612  if(rc != 0)
613  throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno);
614 
615 #elif defined(BOTAN_TARGET_OS_IS_WINDOWS) && defined(BOTAN_TARGET_COMPILER_IS_MSVC)
616 
617  // Windows SEH
618  __try
619  {
620  probe_result = probe_fn();
621  }
622  __except(::GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ?
623  EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
624  {
625  probe_result = -1;
626  }
627 
628 #else
629  BOTAN_UNUSED(probe_fn);
630 #endif
631 
632  return probe_result;
633  }
#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 142 of file os_utils.cpp.

References get_auxval().

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

143  {
144 #if defined(AT_SECURE)
145  return OS::get_auxval(AT_SECURE) != 0;
146 #elif defined(BOTAN_TARGET_OS_HAS_POSIX1)
147  return (::getuid() != ::geteuid()) || (::getgid() != ::getegid());
148 #else
149  return false;
150 #endif
151  }
unsigned long get_auxval(unsigned long id)
Definition: os_utils.cpp:108

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

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

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

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

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