Botan 2.19.5 Crypto and TLS for C&

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

## ◆ 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

  count | requested number of locked pages

Definition at line 459 of file os_utils.cpp.

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 }
BOTAN_UNUSED
#define BOTAN_UNUSED(...)
Definition: assert.h:142
Botan::OS::page_prohibit_access
void page_prohibit_access(void *page)
Definition: os_utils.cpp:562
Botan::OS::system_page_size
size_t system_page_size()
Definition: os_utils.cpp:307

References BOTAN_UNUSED, page_prohibit_access(), and system_page_size().

## ◆ free_locked_pages()

void Botan::OS::free_locked_pages | ( | const std::vector< void * > & | pages | ) |

Free memory allocated by allocate_locked_pages

Parameters

  pages | a list of pages returned by allocate_locked_pages

Definition at line 577 of file os_utils.cpp.

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 }
Botan::OS::page_allow_access
void page_allow_access(void *page)
Definition: os_utils.cpp:547
Botan::secure_scrub_memory
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:66

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

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

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 }

References BOTAN_UNUSED.

Referenced by running_in_privileged_state().

## ◆ get_cpu_available()

size_t Botan::OS::get_cpu_available | ( |  | ) |

Definition at line 230 of file os_utils.cpp.

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 }
Botan::OS::get_cpu_total
size_t BOTAN_TEST_API get_cpu_total()
Definition: os_utils.cpp:215

References get_cpu_total().

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

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

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 }

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

## ◆ get_cpu_total()

size_t Botan::OS::get_cpu_total | ( |  | ) |

Definition at line 215 of file os_utils.cpp.

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 }

Referenced by get_cpu_available().

## ◆ get_high_resolution_clock()

uint64_t Botan::OS::get_high_resolution_clock | ( |  | ) |

Definition at line 241 of file os_utils.cpp.

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 }
Botan::OS::get_cpu_cycle_counter
uint64_t BOTAN_TEST_API get_cpu_cycle_counter()
Definition: os_utils.cpp:154

References get_cpu_cycle_counter().

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

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

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 }
Botan::OS::read_env_variable_sz
size_t read_env_variable_sz(const std::string &var_name, size_t def_value=0)
Definition: os_utils.cpp:413

References read_env_variable_sz(), and system_page_size().

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

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 }

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

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

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 }

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

## ◆ 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 352 of file socket.cpp.

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 }

References BOTAN_UNUSED.

## ◆ open_socket_udp() [1/2]

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.

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 }

References BOTAN_UNUSED.

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

## ◆ open_socket_udp() [2/2]

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.

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 }
Botan::Invalid_Argument
Definition: exceptn.h:137
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Botan::OS::open_socket_udp
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

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

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

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 }

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

## ◆ page_prohibit_access()

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.

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 }

References BOTAN_UNUSED, and system_page_size().

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

## ◆ read_env_variable()

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.

388 {
389 value_out = "";
390
391 if(running_in_privileged_state())
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 }
name
std::string name
Definition: commoncrypto_hash.cpp:24
Botan::OS::running_in_privileged_state
bool running_in_privileged_state()
Definition: os_utils.cpp:143

References name, and running_in_privileged_state().

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

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

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 }
Botan::OS::read_env_variable
bool read_env_variable(std::string &value_out, const std::string &var_name)
Definition: os_utils.cpp:387

References name, and read_env_variable().

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

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

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 }
Botan::System_Error
Definition: exceptn.h:324

References BOTAN_UNUSED.

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

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 }
Botan::OS::get_auxval
unsigned long get_auxval(unsigned long id)
Definition: os_utils.cpp:109

References get_auxval().

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

## ◆ 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 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 }
Botan::OS::Echo_Suppression
Definition: os_utils.h:175
Botan::OS::Echo_Suppression::reenable_echo
virtual void reenable_echo()=0

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

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 }

References BOTAN_UNUSED.

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