Botan  2.19.1
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 BOTAN_UNUSED, page_prohibit_access(), and system_page_size().

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

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

578  {
579  const size_t page_size = OS::system_page_size();
580 
581  for(size_t i = 0; i != pages.size(); ++i)
582  {
583  void* ptr = pages[i];
584 
585  secure_scrub_memory(ptr, page_size);
586 
587  // ptr points to the data page, guard pages are before and after
588  page_allow_access(static_cast<uint8_t*>(ptr) - page_size);
589  page_allow_access(static_cast<uint8_t*>(ptr) + page_size);
590 
591 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
592  ::munlock(ptr, page_size);
593  ::munmap(static_cast<uint8_t*>(ptr) - page_size, 3*page_size);
594 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
595  ::VirtualUnlock(ptr, page_size);
596  ::VirtualFree(static_cast<uint8_t*>(ptr) - page_size, 0, MEM_RELEASE);
597 #endif
598  }
599  }
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:547
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::randomize_with_ts_input(), and 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) || defined(BOTAN_TARGET_OS_IS_NONE)
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 318 of file socket_udp.cpp.

References BOTAN_UNUSED.

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

321  {
322 #if defined(BOTAN_HAS_BOOST_ASIO)
323  return std::unique_ptr<OS::SocketUDP>(new Asio_SocketUDP(hostname, service, timeout));
324 #elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2)
325  return std::unique_ptr<OS::SocketUDP>(new BSD_SocketUDP(hostname, service, timeout));
326 #else
327  BOTAN_UNUSED(hostname);
328  BOTAN_UNUSED(service);
329  BOTAN_UNUSED(timeout);
330  return std::unique_ptr<OS::SocketUDP>();
331 #endif
332  }
#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 335 of file socket_udp.cpp.

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

337  {
338  const auto uri = URI::fromAny(uri_string);
339  if(uri.port == 0)
340  { throw Invalid_Argument("UDP port not specified"); }
341  return open_socket_udp(uri.host, std::to_string(uri.port), timeout);
342  }
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:318
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 547 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().

548  {
549 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
550  const size_t page_size = OS::system_page_size();
551  ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
552 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
553  const size_t page_size = OS::system_page_size();
554  DWORD old_perms = 0;
555  ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
556  BOTAN_UNUSED(old_perms);
557 #else
558  BOTAN_UNUSED(page);
559 #endif
560  }
#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 562 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().

563  {
564 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
565  const size_t page_size = OS::system_page_size();
566  ::mprotect(page, page_size, PROT_NONE);
567 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
568  const size_t page_size = OS::system_page_size();
569  DWORD old_perms = 0;
570  ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms);
571  BOTAN_UNUSED(old_perms);
572 #else
573  BOTAN_UNUSED(page);
574 #endif
575  }
#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 616 of file os_utils.cpp.

References BOTAN_UNUSED.

617  {
618  volatile int probe_result = -3;
619 
620 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
621  struct sigaction old_sigaction;
622  struct sigaction sigaction;
623 
624  sigaction.sa_handler = botan_sigill_handler;
625  sigemptyset(&sigaction.sa_mask);
626  sigaction.sa_flags = 0;
627 
628  int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction);
629 
630  if(rc != 0)
631  throw System_Error("run_cpu_instruction_probe sigaction failed", errno);
632 
633  rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1);
634 
635  if(rc == 0)
636  {
637  // first call to sigsetjmp
638  probe_result = probe_fn();
639  }
640  else if(rc == 1)
641  {
642  // non-local return from siglongjmp in signal handler: return error
643  probe_result = -1;
644  }
645 
646  // Restore old SIGILL handler, if any
647  rc = ::sigaction(SIGILL, &old_sigaction, nullptr);
648  if(rc != 0)
649  throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno);
650 
651 #else
652  BOTAN_UNUSED(probe_fn);
653 #endif
654 
655  return probe_result;
656  }
#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 658 of file os_utils.cpp.

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