Botan  2.11.0
Crypto and TLS for C++11
os_utils.cpp
Go to the documentation of this file.
1 /*
2 * OS and machine specific utility functions
3 * (C) 2015,2016,2017,2018 Jack Lloyd
4 * (C) 2016 Daniel Neus
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8 
9 #include <botan/internal/os_utils.h>
10 #include <botan/cpuid.h>
11 #include <botan/exceptn.h>
12 #include <botan/mem_ops.h>
13 
14 #include <algorithm>
15 #include <chrono>
16 #include <cstdlib>
17 
18 #if defined(BOTAN_TARGET_OS_HAS_THREADS)
19  #include <thread>
20 #endif
21 
22 #if defined(BOTAN_TARGET_OS_HAS_EXPLICIT_BZERO)
23  #include <string.h>
24 #endif
25 
26 #if defined(BOTAN_TARGET_OS_HAS_POSIX1)
27  #include <sys/types.h>
28  #include <sys/resource.h>
29  #include <sys/mman.h>
30  #include <signal.h>
31  #include <stdlib.h>
32  #include <setjmp.h>
33  #include <unistd.h>
34  #include <errno.h>
35  #include <termios.h>
36  #undef B0
37 #endif
38 
39 #if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
40  #include <emscripten/emscripten.h>
41 #endif
42 
43 #if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_OS_IS_ANDROID) || \
44  defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
45  #include <sys/auxv.h>
46 #endif
47 
48 #if defined(BOTAN_TARGET_OS_HAS_WIN32)
49  #define NOMINMAX 1
50  #include <windows.h>
51 #endif
52 
53 #if defined(BOTAN_TARGET_OS_IS_ANDROID)
54  #include <elf.h>
55  extern "C" char **environ;
56 #endif
57 
58 namespace Botan {
59 
60 // Not defined in OS namespace for historical reasons
61 void secure_scrub_memory(void* ptr, size_t n)
62  {
63 #if defined(BOTAN_TARGET_OS_HAS_RTLSECUREZEROMEMORY)
64  ::RtlSecureZeroMemory(ptr, n);
65 
66 #elif defined(BOTAN_TARGET_OS_HAS_EXPLICIT_BZERO)
67  ::explicit_bzero(ptr, n);
68 
69 #elif defined(BOTAN_TARGET_OS_HAS_EXPLICIT_MEMSET)
70  (void)::explicit_memset(ptr, 0, n);
71 
72 #elif defined(BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO) && (BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO == 1)
73  /*
74  Call memset through a static volatile pointer, which the compiler
75  should not elide. This construct should be safe in conforming
76  compilers, but who knows. I did confirm that on x86-64 GCC 6.1 and
77  Clang 3.8 both create code that saves the memset address in the
78  data segment and unconditionally loads and jumps to that address.
79  */
80  static void* (*const volatile memset_ptr)(void*, int, size_t) = std::memset;
81  (memset_ptr)(ptr, 0, n);
82 #else
83 
84  volatile uint8_t* p = reinterpret_cast<volatile uint8_t*>(ptr);
85 
86  for(size_t i = 0; i != n; ++i)
87  p[i] = 0;
88 #endif
89  }
90 
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  }
103 
104 unsigned long OS::get_auxval(unsigned long id)
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  }
134 
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  }
145 
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  }
206 
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  }
222 
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  }
236 
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  }
288 
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  }
302 
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  }
321 
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  }
381 
382 const char* OS::read_env_variable(const std::string& name)
383  {
385  return nullptr;
386 
387  return std::getenv(name.c_str());
388  }
389 
390 size_t OS::read_env_variable_sz(const std::string& name, size_t def)
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  }
404 
405 std::vector<void*> OS::allocate_locked_pages(size_t count)
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  }
475 
476 void OS::page_allow_access(void* page)
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  }
487 
488 void OS::page_prohibit_access(void* page)
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  }
499 
500 void OS::free_locked_pages(const std::vector<void*>& pages)
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  }
522 
523 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
524 
525 namespace {
526 
527 static ::sigjmp_buf g_sigill_jmp_buf;
528 
529 void botan_sigill_handler(int)
530  {
531  siglongjmp(g_sigill_jmp_buf, /*non-zero return value*/1);
532  }
533 
534 }
535 
536 #endif
537 
538 int OS::run_cpu_instruction_probe(std::function<int ()> probe_fn)
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  }
592 
593 std::unique_ptr<OS::Echo_Suppression> OS::suppress_echo_on_terminal()
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  }
691 
692 }
size_t BOTAN_TEST_API get_cpu_total()
Definition: os_utils.cpp:207
int BOTAN_TEST_API run_cpu_instruction_probe(std::function< int()> probe_fn)
Definition: os_utils.cpp:538
uint64_t BOTAN_TEST_API get_cpu_cycle_counter()
Definition: os_utils.cpp:146
uint32_t BOTAN_TEST_API get_process_id()
Definition: os_utils.cpp:91
void free_locked_pages(const std::vector< void *> &pages)
Definition: os_utils.cpp:500
void page_prohibit_access(void *page)
Definition: os_utils.cpp:488
size_t get_memory_locking_limit()
Definition: os_utils.cpp:322
bool running_in_privileged_state()
Definition: os_utils.cpp:135
std::string name
std::vector< void * > allocate_locked_pages(size_t count)
Definition: os_utils.cpp:405
uint64_t BOTAN_TEST_API get_system_timestamp_ns()
Definition: os_utils.cpp:289
Definition: alg_id.cpp:13
#define BOTAN_UNUSED(...)
Definition: assert.h:142
size_t read_env_variable_sz(const std::string &var_name, size_t def_value=0)
Definition: os_utils.cpp:390
unsigned long get_auxval(unsigned long id)
Definition: os_utils.cpp:104
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:61
std::unique_ptr< Echo_Suppression > BOTAN_UNSTABLE_API suppress_echo_on_terminal()
Definition: os_utils.cpp:593
size_t system_page_size()
Definition: os_utils.cpp:303
void page_allow_access(void *page)
Definition: os_utils.cpp:476
size_t BOTAN_TEST_API get_cpu_available()
Definition: os_utils.cpp:223
const char * read_env_variable(const std::string &var_name)
Definition: os_utils.cpp:382
uint64_t BOTAN_TEST_API get_high_resolution_clock()
Definition: os_utils.cpp:237