Botan 3.6.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)
 
unsigned long auxval_hwcap ()
 
unsigned long auxval_hwcap2 ()
 
std::string BOTAN_TEST_API format_time (time_t time, const std::string &format)
 
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 ()
 
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 ()
 
bool has_auxval ()
 
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)
 
bool running_in_privileged_state ()
 
std::unique_ptr< Echo_Suppression > BOTAN_UNSTABLE_API suppress_echo_on_terminal ()
 
size_t system_page_size ()
 

Function Documentation

◆ allocate_locked_pages()

std::vector< void * > Botan::OS::allocate_locked_pages ( size_t count)

Request count pages of RAM which are locked into memory using mlock, VirtualLock, or some similar OS specific API. Free it with free_locked_pages.

Returns an empty list on failure. This function is allowed to return fewer than count pages.

The contents of the allocated pages are undefined.

Each page is preceded by and followed by a page which is marked as noaccess, such that accessing it will cause a crash. This turns out of bound reads/writes into crash events.

Parameters
countrequested number of locked pages

Definition at line 515 of file os_utils.cpp.

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

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

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

◆ auxval_hwcap()

unsigned long Botan::OS::auxval_hwcap ( )

If get_auxval is supported, returns the relevant value for AT_HWCAP

If get_auxval is not supported on this system, arbitrarily returns 0

Definition at line 136 of file os_utils.cpp.

136 {
137#if defined(AT_HWCAP)
138 return AT_HWCAP;
139#else
140 // If the value is not defined in a header we can see,
141 // but auxval is supported, return the Linux/Android value
142 return (OS::has_auxval()) ? 16 : 0;
143#endif
144}

References has_auxval().

◆ auxval_hwcap2()

unsigned long Botan::OS::auxval_hwcap2 ( )

If get_auxval is supported, returns the relevant value for AT_HWCAP2

If get_auxval is not supported on this system, arbitrarily returns 0

Definition at line 146 of file os_utils.cpp.

146 {
147#if defined(AT_HWCAP2)
148 return AT_HWCAP2;
149#else
150 // If the value is not defined in a header we can see,
151 // but auxval is supported, return the Linux/Android value
152 return (OS::has_auxval()) ? 26 : 0;
153#endif
154}

References has_auxval().

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

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

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

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

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

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

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

156 {
157#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
158 return ::getauxval(id);
159#elif defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
160 unsigned long auxinfo = 0;
161 ::elf_aux_info(static_cast<int>(id), &auxinfo, sizeof(auxinfo));
162 return auxinfo;
163#elif defined(BOTAN_TARGET_OS_HAS_AUXINFO)
164 for(const AuxInfo* auxinfo = static_cast<AuxInfo*>(::_dlauxinfo()); auxinfo != AT_NULL; ++auxinfo) {
165 if(id == auxinfo->a_type)
166 return auxinfo->a_v;
167 }
168
169 return 0;
170#else
171 BOTAN_UNUSED(id);
172 return 0;
173#endif
174}

References BOTAN_UNUSED.

Referenced by running_in_privileged_state().

◆ get_cpu_available()

size_t Botan::OS::get_cpu_available ( )

Definition at line 247 of file os_utils.cpp.

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

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

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

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

◆ get_high_resolution_clock()

uint64_t Botan::OS::get_high_resolution_clock ( )

Definition at line 279 of file os_utils.cpp.

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

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

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

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

112 {
113#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
114 return ::getpid();
115#elif defined(BOTAN_TARGET_OS_HAS_WIN32)
116 return ::GetCurrentProcessId();
117#elif defined(BOTAN_TARGET_OS_IS_LLVM) || defined(BOTAN_TARGET_OS_IS_NONE)
118 return 0; // truly no meaningful value
119#else
120 #error "Missing get_process_id"
121#endif
122}

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.

Definition at line 329 of file os_utils.cpp.

329 {
330#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
331 struct timespec ts;
332 if(::clock_gettime(CLOCK_REALTIME, &ts) == 0) {
333 return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
334 }
335#endif
336
337 auto now = std::chrono::system_clock::now().time_since_epoch();
338 return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
339}

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

◆ has_auxval()

bool Botan::OS::has_auxval ( )

Return true if get_auxval is implemented on this system

Definition at line 124 of file os_utils.cpp.

124 {
125#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
126 return true;
127#elif defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
128 return true;
129#elif defined(BOTAN_TARGET_OS_HAS_AUXINFO)
130 return true;
131#else
132 return false;
133#endif
134}

Referenced by auxval_hwcap(), auxval_hwcap2(), and running_in_privileged_state().

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

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

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 318 of file socket_udp.cpp.

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

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 333 of file socket_udp.cpp.

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

References Botan::URI::fromAny(), 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 606 of file os_utils.cpp.

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

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

656 {
657#if defined(BOTAN_TARGET_OS_HAS_PRCTL) && defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME)
658 static constexpr char name[] = "Botan mlock pool";
659 int r = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, reinterpret_cast<uintptr_t>(page), size, name);
660 BOTAN_UNUSED(r);
661#else
662 BOTAN_UNUSED(page, size);
663#endif
664}
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 620 of file os_utils.cpp.

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

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

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

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

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

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

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

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

176 {
177#if defined(AT_SECURE)
178 if(OS::has_auxval()) {
179 return OS::get_auxval(AT_SECURE) != 0;
180 }
181#endif
182
183#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
184 return (::getuid() != ::geteuid()) || (::getgid() != ::getegid());
185#else
186 return false;
187#endif
188}

References get_auxval(), and has_auxval().

Referenced by 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 756 of file os_utils.cpp.

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

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

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