Botan 3.0.0
Crypto and TLS for C&
Classes | Functions
Botan::OS Namespace Reference

Classes

class  Echo_Suppression
 
class  Socket
 
class  SocketUDP
 

Functions

std::vector< void * > allocate_locked_pages (size_t count)
 
void free_locked_pages (const std::vector< void * > &pages)
 
unsigned long get_auxval (unsigned long id)
 
size_t BOTAN_TEST_API get_cpu_available ()
 
uint64_t BOTAN_TEST_API get_cpu_cycle_counter ()
 
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)
 
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 496 of file os_utils.cpp.

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

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

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

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

619 {
620 const size_t page_size = OS::system_page_size();
621
622 for(size_t i = 0; i != pages.size(); ++i)
623 {
624 void* ptr = pages[i];
625
626 secure_scrub_memory(ptr, page_size);
627
628 // ptr points to the data page, guard pages are before and after
629 page_allow_access(static_cast<uint8_t*>(ptr) - page_size);
630 page_allow_access(static_cast<uint8_t*>(ptr) + page_size);
631
632#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
633 ::munlock(ptr, page_size);
634 ::munmap(static_cast<uint8_t*>(ptr) - page_size, 3*page_size);
635#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
636 ::VirtualUnlock(ptr, page_size);
637 ::VirtualFree(static_cast<uint8_t*>(ptr) - page_size, 0, MEM_RELEASE);
638#endif
639 }
640 }
void page_allow_access(void *page)
Definition: os_utils.cpp:588
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().

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

125 {
126#if defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
127 return ::getauxval(id);
128#elif defined(BOTAN_TARGET_OS_IS_ANDROID) && defined(BOTAN_TARGET_ARCH_IS_ARM32)
129
130 if(id == 0)
131 return 0;
132
133 char **p = environ;
134
135 while(*p++ != nullptr)
136 ;
137
138 Elf32_auxv_t *e = reinterpret_cast<Elf32_auxv_t*>(p);
139
140 while(e != nullptr)
141 {
142 if(e->a_type == id)
143 return e->a_un.a_val;
144 e++;
145 }
146
147 return 0;
148#elif defined(BOTAN_TARGET_OS_HAS_ELF_AUX_INFO)
149 unsigned long auxinfo = 0;
150 ::elf_aux_info(static_cast<int>(id), &auxinfo, sizeof(auxinfo));
151 return auxinfo;
152#elif defined(BOTAN_TARGET_OS_HAS_AUXINFO)
153 for (const AuxInfo *auxinfo = static_cast<AuxInfo *>(::_dlauxinfo()); auxinfo != AT_NULL; ++auxinfo)
154 {
155 if (id == auxinfo->a_type)
156 return auxinfo->a_v;
157 }
158
159 return 0;
160#else
161 BOTAN_UNUSED(id);
162 return 0;
163#endif
164 }

References BOTAN_UNUSED.

Referenced by running_in_privileged_state().

◆ get_cpu_available()

size_t Botan::OS::get_cpu_available ( )

Definition at line 238 of file os_utils.cpp.

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

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

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

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

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

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

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

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

321 {
322#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
323 struct timespec ts;
324 if(::clock_gettime(CLOCK_REALTIME, &ts) == 0)
325 {
326 return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
327 }
328#endif
329
330 auto now = std::chrono::system_clock::now().time_since_epoch();
331 return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
332 }

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

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

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

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

331 {
332#if defined(BOTAN_HAS_BOOST_ASIO)
333 return std::make_unique<Asio_SocketUDP>(hostname, service, timeout);
334#elif defined(BOTAN_TARGET_OS_HAS_SOCKETS) || defined(BOTAN_TARGET_OS_HAS_WINSOCK2)
335 return std::make_unique<BSD_SocketUDP>(hostname, service, timeout);
336#else
337 BOTAN_UNUSED(hostname);
338 BOTAN_UNUSED(service);
339 BOTAN_UNUSED(timeout);
340 return std::unique_ptr<OS::SocketUDP>();
341#endif
342 }

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

347 {
348 const auto uri = URI::fromAny(uri_string);
349 if(uri.port == 0)
350 { throw Invalid_Argument("UDP port not specified"); }
351 return open_socket_udp(uri.host, std::to_string(uri.port), timeout);
352 }

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

589 {
590#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
591 const size_t page_size = OS::system_page_size();
592 ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
593#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
594 const size_t page_size = OS::system_page_size();
595 DWORD old_perms = 0;
596 ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
597 BOTAN_UNUSED(old_perms);
598#else
599 BOTAN_UNUSED(page);
600#endif
601 }

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

643 {
644#if defined(BOTAN_TARGET_OS_HAS_PRCTL)
645 static constexpr char name[] = "Botan mlock pool";
646 int r = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, reinterpret_cast<uintptr_t>(page), size, name);
647 BOTAN_UNUSED(r);
648#else
649 BOTAN_UNUSED(page, size);
650#endif
651 }
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 603 of file os_utils.cpp.

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

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

423 {
424 value_out = "";
425
427 return false;
428
429#if defined(BOTAN_TARGET_OS_HAS_WIN32) && defined(BOTAN_BUILD_COMPILER_IS_MSVC)
430 const std::string name(name_view);
431 char val[128] = { 0 };
432 size_t req_size = 0;
433 if(getenv_s(&req_size, val, sizeof(val), name.c_str()) == 0)
434 {
435 value_out = std::string(val, req_size);
436 return true;
437 }
438#else
439 const std::string name(name_view);
440 if(const char* val = std::getenv(name.c_str()))
441 {
442 value_out = val;
443 return true;
444 }
445#endif
446
447 return false;
448 }
bool running_in_privileged_state()
Definition: os_utils.cpp:166

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

451 {
452 std::string value;
453 if(read_env_variable(value, name) && !value.empty())
454 {
455 try
456 {
457 const size_t val = std::stoul(value, nullptr);
458 return val;
459 }
460 catch(std::exception&) { /* ignore it */ }
461 }
462
463 return def;
464 }
bool read_env_variable(std::string &value_out, std::string_view var_name)
Definition: os_utils.cpp:422

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

669 {
670 volatile int probe_result = -3;
671
672#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && !defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
673 struct sigaction old_sigaction;
674 struct sigaction sigaction;
675
676 sigaction.sa_handler = botan_sigill_handler;
677 sigemptyset(&sigaction.sa_mask);
678 sigaction.sa_flags = 0;
679
680 int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction);
681
682 if(rc != 0)
683 throw System_Error("run_cpu_instruction_probe sigaction failed", errno);
684
685 rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1);
686
687 if(rc == 0)
688 {
689 // first call to sigsetjmp
690 probe_result = probe_fn();
691 }
692 else if(rc == 1)
693 {
694 // non-local return from siglongjmp in signal handler: return error
695 probe_result = -1;
696 }
697
698 // Restore old SIGILL handler, if any
699 rc = ::sigaction(SIGILL, &old_sigaction, nullptr);
700 if(rc != 0)
701 throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno);
702
703#else
704 BOTAN_UNUSED(probe_fn);
705#endif
706
707 return probe_result;
708 }

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

167 {
168#if defined(AT_SECURE)
169 return OS::get_auxval(AT_SECURE) != 0;
170#elif defined(BOTAN_TARGET_OS_HAS_POSIX1)
171 return (::getuid() != ::geteuid()) || (::getgid() != ::getegid());
172#else
173 return false;
174#endif
175 }

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

711 {
712#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
713 class POSIX_Echo_Suppression : public Echo_Suppression
714 {
715 public:
716 POSIX_Echo_Suppression()
717 {
718 m_stdin_fd = fileno(stdin);
719 if(::tcgetattr(m_stdin_fd, &m_old_termios) != 0)
720 throw System_Error("Getting terminal status failed", errno);
721
722 struct termios noecho_flags = m_old_termios;
723 noecho_flags.c_lflag &= ~ECHO;
724 noecho_flags.c_lflag |= ECHONL;
725
726 if(::tcsetattr(m_stdin_fd, TCSANOW, &noecho_flags) != 0)
727 throw System_Error("Clearing terminal echo bit failed", errno);
728 }
729
730 void reenable_echo() override
731 {
732 if(m_stdin_fd > 0)
733 {
734 if(::tcsetattr(m_stdin_fd, TCSANOW, &m_old_termios) != 0)
735 throw System_Error("Restoring terminal echo bit failed", errno);
736 m_stdin_fd = -1;
737 }
738 }
739
740 ~POSIX_Echo_Suppression() override
741 {
742 try
743 {
745 }
746 catch(...)
747 {
748 }
749 }
750
751 POSIX_Echo_Suppression(const POSIX_Echo_Suppression& other) = delete;
752 POSIX_Echo_Suppression(POSIX_Echo_Suppression&& other) = delete;
753 POSIX_Echo_Suppression& operator=(const POSIX_Echo_Suppression& other) = delete;
754 POSIX_Echo_Suppression& operator=(POSIX_Echo_Suppression&& other) = delete;
755
756 private:
757 int m_stdin_fd;
758 struct termios m_old_termios;
759 };
760
761 return std::make_unique<POSIX_Echo_Suppression>();
762
763#elif defined(BOTAN_TARGET_OS_HAS_WIN32)
764
765 class Win32_Echo_Suppression : public Echo_Suppression
766 {
767 public:
768 Win32_Echo_Suppression()
769 {
770 m_input_handle = ::GetStdHandle(STD_INPUT_HANDLE);
771 if(::GetConsoleMode(m_input_handle, &m_console_state) == 0)
772 throw System_Error("Getting console mode failed", ::GetLastError());
773
774 DWORD new_mode = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
775 if(::SetConsoleMode(m_input_handle, new_mode) == 0)
776 throw System_Error("Setting console mode failed", ::GetLastError());
777 }
778
779 void reenable_echo() override
780 {
781 if(m_input_handle != INVALID_HANDLE_VALUE)
782 {
783 if(::SetConsoleMode(m_input_handle, m_console_state) == 0)
784 throw System_Error("Setting console mode failed", ::GetLastError());
785 m_input_handle = INVALID_HANDLE_VALUE;
786 }
787 }
788
789 ~Win32_Echo_Suppression() override
790 {
791 try
792 {
793 reenable_echo();
794 }
795 catch(...)
796 {
797 }
798 }
799
800 Win32_Echo_Suppression(const Win32_Echo_Suppression& other) = delete;
801 Win32_Echo_Suppression(Win32_Echo_Suppression&& other) = delete;
802 Win32_Echo_Suppression& operator=(const Win32_Echo_Suppression& other) = delete;
803 Win32_Echo_Suppression& operator=(Win32_Echo_Suppression&& other) = delete;
804
805 private:
806 HANDLE m_input_handle;
807 DWORD m_console_state;
808 };
809
810 return std::make_unique<Win32_Echo_Suppression>();
811
812#else
813
814 // Not supported on this platform, return null
815 return nullptr;
816#endif
817 }
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 334 of file os_utils.cpp.

335 {
336 const size_t default_page_size = 4096;
337
338#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
339 long p = ::sysconf(_SC_PAGESIZE);
340 if(p > 1)
341 return static_cast<size_t>(p);
342 else
343 return default_page_size;
344#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
345 BOTAN_UNUSED(default_page_size);
346 SYSTEM_INFO sys_info;
347 ::GetSystemInfo(&sys_info);
348 return sys_info.dwPageSize;
349#else
350 return default_page_size;
351#endif
352 }

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