Botan 3.7.1
Crypto and TLS for C&
Botan::OS Namespace Reference

Classes

class  Echo_Suppression
 
class  Socket
 
class  SocketUDP
 

Functions

std::vector< void * > allocate_locked_pages (size_t count)
 
std::string BOTAN_TEST_API format_time (time_t time, const std::string &format)
 
void free_locked_pages (const std::vector< void * > &pages)
 
std::optional< std::pair< unsigned long, unsigned long > > get_auxval_hwcap ()
 
size_t BOTAN_TEST_API get_cpu_available ()
 
uint64_t BOTAN_TEST_API get_cpu_cycle_counter ()
 
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 (std::string_view hostname, std::string_view service, std::chrono::milliseconds timeout)
 
std::unique_ptr< SocketUDP > BOTAN_TEST_API open_socket_udp (std::string_view hostname, std::string_view service, std::chrono::microseconds timeout)
 
std::unique_ptr< SocketUDP > BOTAN_TEST_API open_socket_udp (std::string_view uri, std::chrono::microseconds timeout)
 
void page_allow_access (void *page)
 
void page_named (void *page, size_t size)
 
void page_prohibit_access (void *page)
 
bool read_env_variable (std::string &value_out, std::string_view var_name)
 
size_t read_env_variable_sz (std::string_view var_name, size_t def_value=0)
 
int BOTAN_TEST_API run_cpu_instruction_probe (const std::function< int()> &probe_fn)
 
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 516 of file os_utils.cpp.

516 {
517 std::vector<void*> result;
518
519#if(defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)) || \
520 defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
521
522 result.reserve(count);
523
524 const size_t page_size = OS::system_page_size();
525
526 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
527 static const int locked_fd = get_locked_fd();
528 #endif
529
530 for(size_t i = 0; i != count; ++i) {
531 void* ptr = nullptr;
532
533 #if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
534
535 int mmap_flags = MAP_PRIVATE;
536
537 #if defined(MAP_ANONYMOUS)
538 mmap_flags |= MAP_ANONYMOUS;
539 #elif defined(MAP_ANON)
540 mmap_flags |= MAP_ANON;
541 #endif
542
543 #if defined(MAP_CONCEAL)
544 mmap_flags |= MAP_CONCEAL;
545 #elif defined(MAP_NOCORE)
546 mmap_flags |= MAP_NOCORE;
547 #endif
548
549 int mmap_prot = PROT_READ | PROT_WRITE;
550
551 #if defined(PROT_MAX)
552 mmap_prot |= PROT_MAX(mmap_prot);
553 #endif
554
555 ptr = ::mmap(nullptr,
556 3 * page_size,
557 mmap_prot,
558 mmap_flags,
559 /*fd=*/locked_fd,
560 /*offset=*/0);
561
562 if(ptr == MAP_FAILED) {
563 continue;
564 }
565
566 // lock the data page
567 if(::mlock(static_cast<uint8_t*>(ptr) + page_size, page_size) != 0) {
568 ::munmap(ptr, 3 * page_size);
569 continue;
570 }
571
572 #if defined(MADV_DONTDUMP)
573 // we ignore errors here, as DONTDUMP is just a bonus
574 ::madvise(static_cast<uint8_t*>(ptr) + page_size, page_size, MADV_DONTDUMP);
575 #endif
576
577 #elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
578 ptr = ::VirtualAlloc(nullptr, 3 * page_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
579
580 if(ptr == nullptr)
581 continue;
582
583 if(::VirtualLock(static_cast<uint8_t*>(ptr) + page_size, page_size) == 0) {
584 ::VirtualFree(ptr, 0, MEM_RELEASE);
585 continue;
586 }
587 #endif
588
589 std::memset(ptr, 0, 3 * page_size); // zero data page and both guard pages
590
591 // Attempts to name the data page
592 page_named(ptr, 3 * page_size);
593 // Make guard page preceeding the data page
594 page_prohibit_access(static_cast<uint8_t*>(ptr));
595 // Make guard page following the data page
596 page_prohibit_access(static_cast<uint8_t*>(ptr) + 2 * page_size);
597
598 result.push_back(static_cast<uint8_t*>(ptr) + page_size);
599 }
600#else
601 BOTAN_UNUSED(count);
602#endif
603
604 return result;
605}
#define BOTAN_UNUSED
Definition assert.h:118
void page_prohibit_access(void *page)
Definition os_utils.cpp:621
void page_named(void *page, size_t size)
Definition os_utils.cpp:657

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

Referenced by Botan::mlock_allocator::mlock_allocator().

◆ format_time()

std::string Botan::OS::format_time ( time_t time,
const std::string & format )

Format a time

Converts the time_t to a local time representation, then invokes std::put_time with the specified format.

Definition at line 342 of file os_utils.cpp.

342 {
343 std::tm tm;
344
345#if defined(BOTAN_TARGET_OS_HAS_WIN32)
346 localtime_s(&tm, &time);
347#elif defined(BOTAN_TARGET_OS_HAS_POSIX1)
348 localtime_r(&time, &tm);
349#else
350 if(auto tmp = std::localtime(&time)) {
351 tm = *tmp;
352 } else {
353 throw Encoding_Error("Could not convert time_t to localtime");
354 }
355#endif
356
357 std::ostringstream oss;
358 oss << std::put_time(&tm, format.c_str());
359 return oss.str();
360}

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

635 {
636 const size_t page_size = OS::system_page_size();
637
638 for(size_t i = 0; i != pages.size(); ++i) {
639 void* ptr = pages[i];
640
641 secure_scrub_memory(ptr, page_size);
642
643 // ptr points to the data page, guard pages are before and after
644 page_allow_access(static_cast<uint8_t*>(ptr) - page_size);
645 page_allow_access(static_cast<uint8_t*>(ptr) + page_size);
646
647#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
648 ::munlock(ptr, page_size);
649 ::munmap(static_cast<uint8_t*>(ptr) - page_size, 3 * page_size);
650#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
651 ::VirtualUnlock(ptr, page_size);
652 ::VirtualFree(static_cast<uint8_t*>(ptr) - page_size, 0, MEM_RELEASE);
653#endif
654 }
655}
void page_allow_access(void *page)
Definition os_utils.cpp:607
void secure_scrub_memory(void *ptr, size_t n)
Definition mem_utils.cpp:19

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

Referenced by Botan::mlock_allocator::~mlock_allocator().

◆ get_auxval_hwcap()

std::optional< std::pair< unsigned long, unsigned long > > Botan::OS::get_auxval_hwcap ( )

If this system supports getauxval (or an equivalent interface, like FreeBSD's elf_aux_info) queries AT_HWCAP and AT_HWCAP2 and returns both.

Otherwise returns nullopt.

Definition at line 150 of file os_utils.cpp.

150 {
151 if(const auto hwcap = get_auxval(auxval_hwcap())) {
152 // If hwcap worked/was valid, we don't require hwcap2 to also
153 // succeed but instead will return zeros if it failed.
154 auto hwcap2 = get_auxval(auxval_hwcap2()).value_or(0);
155 return std::make_pair(*hwcap, hwcap2);
156 } else {
157 return {};
158 }
159}

◆ get_cpu_available()

size_t Botan::OS::get_cpu_available ( )

Definition at line 240 of file os_utils.cpp.

240 {
241#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
242
243 #if defined(_SC_NPROCESSORS_ONLN)
244 const long cpu_online = ::sysconf(_SC_NPROCESSORS_ONLN);
245 if(cpu_online > 0) {
246 return static_cast<size_t>(cpu_online);
247 }
248 #endif
249
250 #if defined(_SC_NPROCESSORS_CONF)
251 const long cpu_conf = ::sysconf(_SC_NPROCESSORS_CONF);
252 if(cpu_conf > 0) {
253 return static_cast<size_t>(cpu_conf);
254 }
255 #endif
256
257#endif
258
259#if defined(BOTAN_TARGET_OS_HAS_THREADS)
260 // hardware_concurrency is allowed to return 0 if the value is not
261 // well defined or not computable.
262 const size_t hw_concur = std::thread::hardware_concurrency();
263
264 if(hw_concur > 0) {
265 return hw_concur;
266 }
267#endif
268
269 return 1;
270}

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

183 {
184 uint64_t rtc = 0;
185
186#if defined(BOTAN_TARGET_OS_HAS_WIN32)
187 LARGE_INTEGER tv;
188 ::QueryPerformanceCounter(&tv);
189 rtc = tv.QuadPart;
190
191#elif defined(BOTAN_USE_GCC_INLINE_ASM)
192
193 #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
194
195 if(CPUID::has_rdtsc()) {
196 uint32_t rtc_low = 0, rtc_high = 0;
197 asm volatile("rdtsc" : "=d"(rtc_high), "=a"(rtc_low));
198 rtc = (static_cast<uint64_t>(rtc_high) << 32) | rtc_low;
199 }
200
201 #elif defined(BOTAN_TARGET_ARCH_IS_PPC64)
202
203 for(;;) {
204 uint32_t rtc_low = 0, rtc_high = 0, rtc_high2 = 0;
205 asm volatile("mftbu %0" : "=r"(rtc_high));
206 asm volatile("mftb %0" : "=r"(rtc_low));
207 asm volatile("mftbu %0" : "=r"(rtc_high2));
208
209 if(rtc_high == rtc_high2) {
210 rtc = (static_cast<uint64_t>(rtc_high) << 32) | rtc_low;
211 break;
212 }
213 }
214
215 #elif defined(BOTAN_TARGET_ARCH_IS_ALPHA)
216 asm volatile("rpcc %0" : "=r"(rtc));
217
218 // OpenBSD does not trap access to the %tick register
219 #elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD)
220 asm volatile("rd %%tick, %0" : "=r"(rtc));
221
222 #elif defined(BOTAN_TARGET_ARCH_IS_IA64)
223 asm volatile("mov %0=ar.itc" : "=r"(rtc));
224
225 #elif defined(BOTAN_TARGET_ARCH_IS_S390X)
226 asm volatile("stck 0(%0)" : : "a"(&rtc) : "memory", "cc");
227
228 #elif defined(BOTAN_TARGET_ARCH_IS_HPPA)
229 asm volatile("mfctl 16,%0" : "=r"(rtc)); // 64-bit only?
230
231 #else
232 //#warning "OS::get_cpu_cycle_counter not implemented"
233 #endif
234
235#endif
236
237 return rtc;
238}

Referenced by get_high_resolution_clock().

◆ get_high_resolution_clock()

uint64_t Botan::OS::get_high_resolution_clock ( )

Definition at line 272 of file os_utils.cpp.

272 {
273 if(uint64_t cpu_clock = OS::get_cpu_cycle_counter()) {
274 return cpu_clock;
275 }
276
277#if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
278 return emscripten_get_now();
279#endif
280
281 /*
282 If we got here either we either don't have an asm instruction
283 above, or (for x86) RDTSC is not available at runtime. Try some
284 clock_gettimes and return the first one that works, or otherwise
285 fall back to std::chrono.
286 */
287
288#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
289
290 // The ordering here is somewhat arbitrary...
291 const clockid_t clock_types[] = {
292 #if defined(CLOCK_MONOTONIC_HR)
293 CLOCK_MONOTONIC_HR,
294 #endif
295 #if defined(CLOCK_MONOTONIC_RAW)
296 CLOCK_MONOTONIC_RAW,
297 #endif
298 #if defined(CLOCK_MONOTONIC)
299 CLOCK_MONOTONIC,
300 #endif
301 #if defined(CLOCK_PROCESS_CPUTIME_ID)
302 CLOCK_PROCESS_CPUTIME_ID,
303 #endif
304 #if defined(CLOCK_THREAD_CPUTIME_ID)
305 CLOCK_THREAD_CPUTIME_ID,
306 #endif
307 };
308
309 for(clockid_t clock : clock_types) {
310 struct timespec ts;
311 if(::clock_gettime(clock, &ts) == 0) {
312 return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
313 }
314 }
315#endif
316
317#if defined(BOTAN_TARGET_OS_HAS_SYSTEM_CLOCK)
318 // Plain C++11 fallback
319 auto now = std::chrono::high_resolution_clock::now().time_since_epoch();
320 return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
321#else
322 return 0;
323#endif
324}

References get_cpu_cycle_counter().

Referenced by Botan::RandomNumberGenerator::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 382 of file os_utils.cpp.

382 {
383 /*
384 * Linux defaults to only 64 KiB of mlockable memory per process (too small)
385 * but BSDs offer a small fraction of total RAM (more than we need). Bound the
386 * total mlock size to 512 KiB which is enough to run the entire test suite
387 * without spilling to non-mlock memory (and thus presumably also enough for
388 * many useful programs), but small enough that we should not cause problems
389 * even if many processes are mlocking on the same machine.
390 */
391 const size_t max_locked_kb = 512;
392
393 /*
394 * If RLIMIT_MEMLOCK is not defined, likely the OS does not support
395 * unprivileged mlock calls.
396 */
397#if defined(RLIMIT_MEMLOCK) && defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
398 const size_t mlock_requested =
399 std::min<size_t>(read_env_variable_sz("BOTAN_MLOCK_POOL_SIZE", max_locked_kb), max_locked_kb);
400
401 if(mlock_requested > 0) {
402 struct ::rlimit limits;
403
404 ::getrlimit(RLIMIT_MEMLOCK, &limits);
405
406 if(limits.rlim_cur < limits.rlim_max) {
407 limits.rlim_cur = limits.rlim_max;
408 ::setrlimit(RLIMIT_MEMLOCK, &limits);
409 ::getrlimit(RLIMIT_MEMLOCK, &limits);
410 }
411
412 return std::min<size_t>(limits.rlim_cur, mlock_requested * 1024);
413 }
414
415#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
416 const size_t mlock_requested =
417 std::min<size_t>(read_env_variable_sz("BOTAN_MLOCK_POOL_SIZE", max_locked_kb), max_locked_kb);
418
419 SIZE_T working_min = 0, working_max = 0;
420 if(!::GetProcessWorkingSetSize(::GetCurrentProcess(), &working_min, &working_max)) {
421 return 0;
422 }
423
424 // According to Microsoft MSDN:
425 // 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
426 // In the book "Windows Internals Part 2": the maximum lockable pages are minimum working set size - 8 pages
427 // But the information in the book seems to be inaccurate/outdated
428 // I've tested this on Windows 8.1 x64, Windows 10 x64 and Windows 7 x86
429 // On all three OS the value is 11 instead of 8
430 const size_t overhead = OS::system_page_size() * 11;
431 if(working_min > overhead) {
432 const size_t lockable_bytes = working_min - overhead;
433 return std::min<size_t>(lockable_bytes, mlock_requested * 1024);
434 }
435#else
436 // Not supported on this platform
437 BOTAN_UNUSED(max_locked_kb);
438#endif
439
440 return 0;
441}
size_t read_env_variable_sz(std::string_view var_name, size_t def_value=0)
Definition os_utils.cpp:476

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

Referenced by Botan::mlock_allocator::mlock_allocator().

◆ 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 systems where there is no processes to speak of (for example on baremetal systems or within a unikernel), this function returns zero.

Definition at line 82 of file os_utils.cpp.

82 {
83#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
84 return ::getpid();
85#elif defined(BOTAN_TARGET_OS_HAS_WIN32)
86 return ::GetCurrentProcessId();
87#elif defined(BOTAN_TARGET_OS_IS_LLVM) || defined(BOTAN_TARGET_OS_IS_NONE)
88 return 0; // truly no meaningful value
89#else
90 #error "Missing get_process_id"
91#endif
92}

Referenced by Botan::RandomNumberGenerator::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, using Unix epoch.

If the system does not have a real time clock this function will throw Not_Implemented

Definition at line 326 of file os_utils.cpp.

326 {
327#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
328 struct timespec ts;
329 if(::clock_gettime(CLOCK_REALTIME, &ts) == 0) {
330 return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
331 }
332#endif
333
334#if defined(BOTAN_TARGET_OS_HAS_SYSTEM_CLOCK)
335 auto now = std::chrono::system_clock::now().time_since_epoch();
336 return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
337#else
338 throw Not_Implemented("OS::get_system_timestamp_ns this system does not support a clock");
339#endif
340}

Referenced by Botan::measure_cost().

◆ open_socket()

std::unique_ptr< OS::Socket > Botan::OS::open_socket ( std::string_view hostname,
std::string_view 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 349 of file socket.cpp.

351 {
352#if defined(BOTAN_HAS_BOOST_ASIO)
353 return std::make_unique<Asio_Socket>(hostname, service, timeout);
354
355#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2)
356 return std::make_unique<BSD_Socket>(hostname, service, timeout);
357
358#else
359 BOTAN_UNUSED(hostname, service, timeout);
360 // No sockets for you
361 return std::unique_ptr<Socket>();
362#endif
363}

References BOTAN_UNUSED.

◆ open_socket_udp() [1/2]

std::unique_ptr< OS::SocketUDP > Botan::OS::open_socket_udp ( std::string_view hostname,
std::string_view 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 317 of file socket_udp.cpp.

319 {
320#if defined(BOTAN_HAS_BOOST_ASIO)
321 return std::make_unique<Asio_SocketUDP>(hostname, service, timeout);
322#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2)
323 return std::make_unique<BSD_SocketUDP>(hostname, service, timeout);
324#else
325 BOTAN_UNUSED(hostname);
326 BOTAN_UNUSED(service);
327 BOTAN_UNUSED(timeout);
328 return std::unique_ptr<OS::SocketUDP>();
329#endif
330}

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 ( std::string_view 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 332 of file socket_udp.cpp.

332 {
333 const auto uri = URI::from_any(uri_string);
334 if(uri.port() == 0) {
335 throw Invalid_Argument("UDP port not specified");
336 }
337 return open_socket_udp(uri.host(), std::to_string(uri.port()), timeout);
338}

References Botan::URI::from_any(), and open_socket_udp().

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

607 {
608#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
609 const size_t page_size = OS::system_page_size();
610 ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
611#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
612 const size_t page_size = OS::system_page_size();
613 DWORD old_perms = 0;
614 ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
615 BOTAN_UNUSED(old_perms);
616#else
617 BOTAN_UNUSED(page);
618#endif
619}

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

void Botan::OS::page_named ( void * page,
size_t size )

Set a ID to a page's range expressed by size bytes

Definition at line 657 of file os_utils.cpp.

657 {
658#if defined(BOTAN_TARGET_OS_HAS_PRCTL) && defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME)
659 static constexpr char name[] = "Botan mlock pool";
660 int r = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, reinterpret_cast<uintptr_t>(page), size, name);
661 BOTAN_UNUSED(r);
662#else
663 BOTAN_UNUSED(page, size);
664#endif
665}
std::string name

References BOTAN_UNUSED, and name.

Referenced by allocate_locked_pages().

◆ page_prohibit_access()

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

Set the MMU to prohibit access to this page

Definition at line 621 of file os_utils.cpp.

621 {
622#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
623 const size_t page_size = OS::system_page_size();
624 ::mprotect(page, page_size, PROT_NONE);
625#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
626 const size_t page_size = OS::system_page_size();
627 DWORD old_perms = 0;
628 ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms);
629 BOTAN_UNUSED(old_perms);
630#else
631 BOTAN_UNUSED(page);
632#endif
633}

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

◆ read_env_variable()

bool Botan::OS::read_env_variable ( std::string & value_out,
std::string_view 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 443 of file os_utils.cpp.

443 {
444 value_out = "";
445
446 if(running_in_privileged_state()) {
447 return false;
448 }
449
450#if defined(BOTAN_TARGET_OS_HAS_WIN32) && defined(BOTAN_BUILD_COMPILER_IS_MSVC)
451 const std::string name(name_view);
452 char val[128] = {0};
453 size_t req_size = 0;
454 if(getenv_s(&req_size, val, sizeof(val), name.c_str()) == 0) {
455 // Microsoft's implementation always writes a terminating \0,
456 // and includes it in the reported length of the environment variable
457 // if a value exists.
458 if(req_size > 0 && val[req_size - 1] == '\0') {
459 value_out = std::string(val);
460 } else {
461 value_out = std::string(val, req_size);
462 }
463 return true;
464 }
465#else
466 const std::string name(name_view);
467 if(const char* val = std::getenv(name.c_str())) {
468 value_out = val;
469 return true;
470 }
471#endif
472
473 return false;
474}

References name.

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 ( std::string_view 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 476 of file os_utils.cpp.

476 {
477 std::string value;
478 if(read_env_variable(value, name) && !value.empty()) {
479 try {
480 const size_t val = std::stoul(value, nullptr);
481 return val;
482 } catch(std::exception&) { /* ignore it */
483 }
484 }
485
486 return def;
487}
bool read_env_variable(std::string &value_out, std::string_view var_name)
Definition os_utils.cpp:443

References name, and read_env_variable().

Referenced by get_memory_locking_limit().

◆ run_cpu_instruction_probe()

int Botan::OS::run_cpu_instruction_probe ( const 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 717 of file os_utils.cpp.

717 {
718 volatile int probe_result = -3;
719
720#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
721 struct sigaction old_sigaction;
722 struct sigaction sigaction;
723
724 sigaction.sa_handler = botan_sigill_handler;
725 sigemptyset(&sigaction.sa_mask);
726 sigaction.sa_flags = 0;
727
728 int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction);
729
730 if(rc != 0) {
731 throw System_Error("run_cpu_instruction_probe sigaction failed", errno);
732 }
733
734 rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/ 1);
735
736 if(rc == 0) {
737 // first call to sigsetjmp
738 probe_result = probe_fn();
739 } else if(rc == 1) {
740 // non-local return from siglongjmp in signal handler: return error
741 probe_result = -1;
742 }
743
744 // Restore old SIGILL handler, if any
745 rc = ::sigaction(SIGILL, &old_sigaction, nullptr);
746 if(rc != 0) {
747 throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno);
748 }
749
750#else
751 BOTAN_UNUSED(probe_fn);
752#endif
753
754 return probe_result;
755}

References BOTAN_UNUSED.

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

757 {
758#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
759 class POSIX_Echo_Suppression : public Echo_Suppression {
760 public:
761 POSIX_Echo_Suppression() {
762 m_stdin_fd = fileno(stdin);
763 if(::tcgetattr(m_stdin_fd, &m_old_termios) != 0) {
764 throw System_Error("Getting terminal status failed", errno);
765 }
766
767 struct termios noecho_flags = m_old_termios;
768 noecho_flags.c_lflag &= ~ECHO;
769 noecho_flags.c_lflag |= ECHONL;
770
771 if(::tcsetattr(m_stdin_fd, TCSANOW, &noecho_flags) != 0) {
772 throw System_Error("Clearing terminal echo bit failed", errno);
773 }
774 }
775
776 void reenable_echo() override {
777 if(m_stdin_fd > 0) {
778 if(::tcsetattr(m_stdin_fd, TCSANOW, &m_old_termios) != 0) {
779 throw System_Error("Restoring terminal echo bit failed", errno);
780 }
781 m_stdin_fd = -1;
782 }
783 }
784
785 ~POSIX_Echo_Suppression() override {
786 try {
788 } catch(...) {}
789 }
790
791 POSIX_Echo_Suppression(const POSIX_Echo_Suppression& other) = delete;
792 POSIX_Echo_Suppression(POSIX_Echo_Suppression&& other) = delete;
793 POSIX_Echo_Suppression& operator=(const POSIX_Echo_Suppression& other) = delete;
794 POSIX_Echo_Suppression& operator=(POSIX_Echo_Suppression&& other) = delete;
795
796 private:
797 int m_stdin_fd;
798 struct termios m_old_termios;
799 };
800
801 return std::make_unique<POSIX_Echo_Suppression>();
802
803#elif defined(BOTAN_TARGET_OS_HAS_WIN32)
804
805 class Win32_Echo_Suppression : public Echo_Suppression {
806 public:
807 Win32_Echo_Suppression() {
808 m_input_handle = ::GetStdHandle(STD_INPUT_HANDLE);
809 if(::GetConsoleMode(m_input_handle, &m_console_state) == 0)
810 throw System_Error("Getting console mode failed", ::GetLastError());
811
812 DWORD new_mode = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
813 if(::SetConsoleMode(m_input_handle, new_mode) == 0)
814 throw System_Error("Setting console mode failed", ::GetLastError());
815 }
816
817 void reenable_echo() override {
818 if(m_input_handle != INVALID_HANDLE_VALUE) {
819 if(::SetConsoleMode(m_input_handle, m_console_state) == 0)
820 throw System_Error("Setting console mode failed", ::GetLastError());
821 m_input_handle = INVALID_HANDLE_VALUE;
822 }
823 }
824
825 ~Win32_Echo_Suppression() override {
826 try {
827 reenable_echo();
828 } catch(...) {}
829 }
830
831 Win32_Echo_Suppression(const Win32_Echo_Suppression& other) = delete;
832 Win32_Echo_Suppression(Win32_Echo_Suppression&& other) = delete;
833 Win32_Echo_Suppression& operator=(const Win32_Echo_Suppression& other) = delete;
834 Win32_Echo_Suppression& operator=(Win32_Echo_Suppression&& other) = delete;
835
836 private:
837 HANDLE m_input_handle;
838 DWORD m_console_state;
839 };
840
841 return std::make_unique<Win32_Echo_Suppression>();
842
843#else
844
845 // Not supported on this platform, return null
846 return nullptr;
847#endif
848}
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 362 of file os_utils.cpp.

362 {
363 const size_t default_page_size = 4096;
364
365#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
366 long p = ::sysconf(_SC_PAGESIZE);
367 if(p > 1) {
368 return static_cast<size_t>(p);
369 } else {
370 return default_page_size;
371 }
372#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
373 BOTAN_UNUSED(default_page_size);
374 SYSTEM_INFO sys_info;
375 ::GetSystemInfo(&sys_info);
376 return sys_info.dwPageSize;
377#else
378 return default_page_size;
379#endif
380}

References BOTAN_UNUSED.

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