Botan 3.0.0-alpha0
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 get_cache_line_size ()
 
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 (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_named (void *page, size_t size)
 
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 (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 524 of file os_utils.cpp.

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

References BOTAN_UNUSED, page_named(), 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
pagesa list of pages returned by allocate_locked_pages

Definition at line 644 of file os_utils.cpp.

645 {
646 const size_t page_size = OS::system_page_size();
647
648 for(size_t i = 0; i != pages.size(); ++i)
649 {
650 void* ptr = pages[i];
651
652 secure_scrub_memory(ptr, page_size);
653
654 // ptr points to the data page, guard pages are before and after
655 page_allow_access(static_cast<uint8_t*>(ptr) - page_size);
656 page_allow_access(static_cast<uint8_t*>(ptr) + page_size);
657
658#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
659 ::munlock(ptr, page_size);
660 ::munmap(static_cast<uint8_t*>(ptr) - page_size, 3*page_size);
661#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
662 ::VirtualUnlock(ptr, page_size);
663 ::VirtualFree(static_cast<uint8_t*>(ptr) - page_size, 0, MEM_RELEASE);
664#endif
665 }
666 }
void page_allow_access(void *page)
Definition: os_utils.cpp:614
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:81

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

163 {
164#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
165 return ::getauxval(id);
166#elif defined(BOTAN_TARGET_OS_IS_ANDROID) && defined(BOTAN_TARGET_ARCH_IS_ARM32)
167
168 if(id == 0)
169 return 0;
170
171 char **p = environ;
172
173 while(*p++ != nullptr)
174 ;
175
176 Elf32_auxv_t *e = reinterpret_cast<Elf32_auxv_t*>(p);
177
178 while(e != nullptr)
179 {
180 if(e->a_type == id)
181 return e->a_un.a_val;
182 e++;
183 }
184
185 return 0;
186#elif defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
187 unsigned long auxinfo = 0;
188 ::elf_aux_info(static_cast<int>(id), &auxinfo, sizeof(auxinfo));
189 return auxinfo;
190#elif defined(BOTAN_TARGET_OS_HAS_AUXINFO)
191 for (const AuxInfo *auxinfo = static_cast<AuxInfo *>(::_dlauxinfo()); auxinfo != AT_NULL; ++auxinfo)
192 {
193 if (id == auxinfo->a_type)
194 return auxinfo->a_v;
195 }
196
197 return 0;
198#else
199 BOTAN_UNUSED(id);
200 return 0;
201#endif
202 }

References BOTAN_UNUSED.

Referenced by get_cache_line_size(), and running_in_privileged_state().

◆ get_cache_line_size()

size_t Botan::OS::get_cache_line_size ( )

Return the cache line size of the current processor using some OS specific interface, or 0 if not available on this platform.

Definition at line 124 of file os_utils.cpp.

125 {
126#if defined(BOTAN_TARGET_OS_IS_IOS) || defined(BOTAN_TARGET_OS_IS_MACOS)
127 unsigned long cache_line_size_vl;
128 size_t size = sizeof(cache_line_size_vl);
129 if(::sysctlbyname("hw.cachelinesize", &cache_line_size_vl, &size, nullptr, 0) == 0)
130 return static_cast<size_t>(cache_line_size_vl);
131#endif
132
133#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_LEVEL1_DCACHE_LINESIZE)
134 const long res = ::sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
135 if(res > 0)
136 return static_cast<size_t>(res);
137#endif
138
139#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
140
141 #if defined(AT_L1D_CACHEGEOMETRY)
142 // Cache line size is bottom 16 bits
143 const unsigned long dcache_info = OS::get_auxval(AT_L1D_CACHEGEOMETRY);
144 if(dcache_info != 0)
145 return static_cast<size_t>(dcache_info & 0xFFFF);
146 #endif
147
148 #if defined(AT_DCACHEBSIZE)
149 const unsigned long dcache_bsize = OS::get_auxval(AT_DCACHEBSIZE);
150 if(dcache_bsize != 0)
151 return static_cast<size_t>(dcache_bsize);
152 #endif
153
154#endif
155
156 // TODO: on Windows this is returned by GetLogicalProcessorInformation
157
158 // not available on this platform
159 return 0;
160 }
unsigned long get_auxval(unsigned long id)
Definition: os_utils.cpp:162

References get_auxval().

◆ get_cpu_available()

size_t Botan::OS::get_cpu_available ( )

Definition at line 276 of file os_utils.cpp.

277 {
278#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
279
280#if defined(_SC_NPROCESSORS_ONLN)
281 const long cpu_online = ::sysconf(_SC_NPROCESSORS_ONLN);
282 if(cpu_online > 0)
283 return static_cast<size_t>(cpu_online);
284#endif
285
286#if defined(_SC_NPROCESSORS_CONF)
287 const long cpu_conf = ::sysconf(_SC_NPROCESSORS_CONF);
288 if(cpu_conf > 0)
289 return static_cast<size_t>(cpu_conf);
290#endif
291
292#endif
293
294#if defined(BOTAN_TARGET_OS_HAS_THREADS)
295 // hardware_concurrency is allowed to return 0 if the value is not
296 // well defined or not computable.
297 const size_t hw_concur = std::thread::hardware_concurrency();
298
299 if(hw_concur > 0)
300 return hw_concur;
301#endif
302
303 return 1;
304 }

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

216 {
217 uint64_t rtc = 0;
218
219#if defined(BOTAN_TARGET_OS_HAS_WIN32)
220 LARGE_INTEGER tv;
221 ::QueryPerformanceCounter(&tv);
222 rtc = tv.QuadPart;
223
224#elif defined(BOTAN_USE_GCC_INLINE_ASM)
225
226#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
227
228 if(CPUID::has_rdtsc())
229 {
230 uint32_t rtc_low = 0, rtc_high = 0;
231 asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low));
232 rtc = (static_cast<uint64_t>(rtc_high) << 32) | rtc_low;
233 }
234
235#elif defined(BOTAN_TARGET_ARCH_IS_PPC64)
236
237 for(;;)
238 {
239 uint32_t rtc_low = 0, rtc_high = 0, rtc_high2 = 0;
240 asm volatile("mftbu %0" : "=r" (rtc_high));
241 asm volatile("mftb %0" : "=r" (rtc_low));
242 asm volatile("mftbu %0" : "=r" (rtc_high2));
243
244 if(rtc_high == rtc_high2)
245 {
246 rtc = (static_cast<uint64_t>(rtc_high) << 32) | rtc_low;
247 break;
248 }
249 }
250
251#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA)
252 asm volatile("rpcc %0" : "=r" (rtc));
253
254 // OpenBSD does not trap access to the %tick register
255#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD)
256 asm volatile("rd %%tick, %0" : "=r" (rtc));
257
258#elif defined(BOTAN_TARGET_ARCH_IS_IA64)
259 asm volatile("mov %0=ar.itc" : "=r" (rtc));
260
261#elif defined(BOTAN_TARGET_ARCH_IS_S390X)
262 asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc");
263
264#elif defined(BOTAN_TARGET_ARCH_IS_HPPA)
265 asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only?
266
267#else
268 //#warning "OS::get_cpu_cycle_counter not implemented"
269#endif
270
271#endif
272
273 return rtc;
274 }

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

307 {
308 if(uint64_t cpu_clock = OS::get_cpu_cycle_counter())
309 return cpu_clock;
310
311#if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
312 return emscripten_get_now();
313#endif
314
315 /*
316 If we got here either we either don't have an asm instruction
317 above, or (for x86) RDTSC is not available at runtime. Try some
318 clock_gettimes and return the first one that works, or otherwise
319 fall back to std::chrono.
320 */
321
322#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
323
324 // The ordering here is somewhat arbitrary...
325 const clockid_t clock_types[] = {
326#if defined(CLOCK_MONOTONIC_HR)
327 CLOCK_MONOTONIC_HR,
328#endif
329#if defined(CLOCK_MONOTONIC_RAW)
330 CLOCK_MONOTONIC_RAW,
331#endif
332#if defined(CLOCK_MONOTONIC)
333 CLOCK_MONOTONIC,
334#endif
335#if defined(CLOCK_PROCESS_CPUTIME_ID)
336 CLOCK_PROCESS_CPUTIME_ID,
337#endif
338#if defined(CLOCK_THREAD_CPUTIME_ID)
339 CLOCK_THREAD_CPUTIME_ID,
340#endif
341 };
342
343 for(clockid_t clock : clock_types)
344 {
345 struct timespec ts;
346 if(::clock_gettime(clock, &ts) == 0)
347 {
348 return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
349 }
350 }
351#endif
352
353 // Plain C++11 fallback
354 auto now = std::chrono::high_resolution_clock::now().time_since_epoch();
355 return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
356 }
uint64_t BOTAN_TEST_API get_cpu_cycle_counter()
Definition: os_utils.cpp:215

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

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

References BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB, 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 111 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_INCLUDEOS) || 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::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 358 of file os_utils.cpp.

359 {
360#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
361 struct timespec ts;
362 if(::clock_gettime(CLOCK_REALTIME, &ts) == 0)
363 {
364 return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
365 }
366#endif
367
368 auto now = std::chrono::system_clock::now().time_since_epoch();
369 return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
370 }

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

360 {
361#if defined(BOTAN_HAS_BOOST_ASIO)
362 return std::make_unique<Asio_Socket>(hostname, service, timeout);
363
364#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2)
365 return std::make_unique<BSD_Socket>(hostname, service, timeout);
366
367#else
368 BOTAN_UNUSED(hostname);
369 BOTAN_UNUSED(service);
370 BOTAN_UNUSED(timeout);
371 // No sockets for you
372 return std::unique_ptr<Socket>();
373#endif
374 }

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

326 {
327#if defined(BOTAN_HAS_BOOST_ASIO)
328 return std::make_unique<Asio_SocketUDP>(hostname, service, timeout);
329#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2)
330 return std::make_unique<BSD_SocketUDP>(hostname, service, timeout);
331#else
332 BOTAN_UNUSED(hostname);
333 BOTAN_UNUSED(service);
334 BOTAN_UNUSED(timeout);
335 return std::unique_ptr<OS::SocketUDP>();
336#endif
337 }

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

342 {
343 const auto uri = URI::fromAny(uri_string);
344 if(uri.port == 0)
345 { throw Invalid_Argument("UDP port not specified"); }
346 return open_socket_udp(uri.host, std::to_string(uri.port), timeout);
347 }
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:209
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:323

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

615 {
616#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
617 const size_t page_size = OS::system_page_size();
618 ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
619#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
620 const size_t page_size = OS::system_page_size();
621 DWORD old_perms = 0;
622 ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
623 BOTAN_UNUSED(old_perms);
624#else
625 BOTAN_UNUSED(page);
626#endif
627 }

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

669 {
670#if defined(BOTAN_TARGET_OS_HAS_PRCTL)
671 static constexpr char name[] = "Botan mlock pool";
672 int r = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, reinterpret_cast<uintptr_t>(page), size, name);
673 BOTAN_UNUSED(r);
674#else
675 BOTAN_UNUSED(page, size);
676#endif
677 }
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 629 of file os_utils.cpp.

630 {
631#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
632 const size_t page_size = OS::system_page_size();
633 ::mprotect(page, page_size, PROT_NONE);
634#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
635 const size_t page_size = OS::system_page_size();
636 DWORD old_perms = 0;
637 ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms);
638 BOTAN_UNUSED(old_perms);
639#else
640 BOTAN_UNUSED(page);
641#endif
642 }

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

453 {
454 value_out = "";
455
457 return false;
458
459#if defined(BOTAN_TARGET_OS_HAS_WIN32) && defined(BOTAN_BUILD_COMPILER_IS_MSVC)
460 char val[128] = { 0 };
461 size_t req_size = 0;
462 if(getenv_s(&req_size, val, sizeof(val), name.c_str()) == 0)
463 {
464 value_out = std::string(val, req_size);
465 return true;
466 }
467#else
468 if(const char* val = std::getenv(name.c_str()))
469 {
470 value_out = val;
471 return true;
472 }
473#endif
474
475 return false;
476 }
bool running_in_privileged_state()
Definition: os_utils.cpp:204

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

479 {
480 std::string value;
481 if(read_env_variable(value, name))
482 {
483 try
484 {
485 const size_t val = std::stoul(value, nullptr);
486 return val;
487 }
488 catch(std::exception&) { /* ignore it */ }
489 }
490
491 return def;
492 }
bool read_env_variable(std::string &value_out, const std::string &var_name)
Definition: os_utils.cpp:452

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

695 {
696 volatile int probe_result = -3;
697
698#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
699 struct sigaction old_sigaction;
700 struct sigaction sigaction;
701
702 sigaction.sa_handler = botan_sigill_handler;
703 sigemptyset(&sigaction.sa_mask);
704 sigaction.sa_flags = 0;
705
706 int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction);
707
708 if(rc != 0)
709 throw System_Error("run_cpu_instruction_probe sigaction failed", errno);
710
711 rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1);
712
713 if(rc == 0)
714 {
715 // first call to sigsetjmp
716 probe_result = probe_fn();
717 }
718 else if(rc == 1)
719 {
720 // non-local return from siglongjmp in signal handler: return error
721 probe_result = -1;
722 }
723
724 // Restore old SIGILL handler, if any
725 rc = ::sigaction(SIGILL, &old_sigaction, nullptr);
726 if(rc != 0)
727 throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno);
728
729#else
730 BOTAN_UNUSED(probe_fn);
731#endif
732
733 return probe_result;
734 }

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

205 {
206#if defined(AT_SECURE)
207 return OS::get_auxval(AT_SECURE) != 0;
208#elif defined(BOTAN_TARGET_OS_HAS_POSIX1)
209 return (::getuid() != ::geteuid()) || (::getgid() != ::getegid());
210#else
211 return false;
212#endif
213 }

References get_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 736 of file os_utils.cpp.

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

373 {
374 const size_t default_page_size = 4096;
375
376#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
377 long p = ::sysconf(_SC_PAGESIZE);
378 if(p > 1)
379 return static_cast<size_t>(p);
380 else
381 return default_page_size;
382#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
383 BOTAN_UNUSED(default_page_size);
384 SYSTEM_INFO sys_info;
385 ::GetSystemInfo(&sys_info);
386 return sys_info.dwPageSize;
387#else
388 return default_page_size;
389#endif
390 }

References BOTAN_UNUSED.

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