Botan 3.3.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 482 of file os_utils.cpp.

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

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

601 {
602 const size_t page_size = OS::system_page_size();
603
604 for(size_t i = 0; i != pages.size(); ++i) {
605 void* ptr = pages[i];
606
607 secure_scrub_memory(ptr, page_size);
608
609 // ptr points to the data page, guard pages are before and after
610 page_allow_access(static_cast<uint8_t*>(ptr) - page_size);
611 page_allow_access(static_cast<uint8_t*>(ptr) + page_size);
612
613#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
614 ::munlock(ptr, page_size);
615 ::munmap(static_cast<uint8_t*>(ptr) - page_size, 3 * page_size);
616#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
617 ::VirtualUnlock(ptr, page_size);
618 ::VirtualFree(static_cast<uint8_t*>(ptr) - page_size, 0, MEM_RELEASE);
619#endif
620 }
621}
void page_allow_access(void *page)
Definition os_utils.cpp:573
void secure_scrub_memory(void *ptr, size_t n)
Definition os_utils.cpp:87

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

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

References BOTAN_UNUSED.

Referenced by running_in_privileged_state().

◆ get_cpu_available()

size_t Botan::OS::get_cpu_available ( )

Definition at line 234 of file os_utils.cpp.

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

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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

573 {
574#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
575 const size_t page_size = OS::system_page_size();
576 ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
577#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
578 const size_t page_size = OS::system_page_size();
579 DWORD old_perms = 0;
580 ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
581 BOTAN_UNUSED(old_perms);
582#else
583 BOTAN_UNUSED(page);
584#endif
585}

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

623 {
624#if defined(BOTAN_TARGET_OS_HAS_PRCTL) && defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME)
625 static constexpr char name[] = "Botan mlock pool";
626 int r = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, reinterpret_cast<uintptr_t>(page), size, name);
627 BOTAN_UNUSED(r);
628#else
629 BOTAN_UNUSED(page, size);
630#endif
631}
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 587 of file os_utils.cpp.

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

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

409 {
410 value_out = "";
411
413 return false;
414 }
415
416#if defined(BOTAN_TARGET_OS_HAS_WIN32) && defined(BOTAN_BUILD_COMPILER_IS_MSVC)
417 const std::string name(name_view);
418 char val[128] = {0};
419 size_t req_size = 0;
420 if(getenv_s(&req_size, val, sizeof(val), name.c_str()) == 0) {
421 // Microsoft's implementation always writes a terminating \0,
422 // and includes it in the reported length of the environment variable
423 // if a value exists.
424 if(req_size > 0 && val[req_size - 1] == '\0') {
425 value_out = std::string(val);
426 } else {
427 value_out = std::string(val, req_size);
428 }
429 return true;
430 }
431#else
432 const std::string name(name_view);
433 if(const char* val = std::getenv(name.c_str())) {
434 value_out = val;
435 return true;
436 }
437#endif
438
439 return false;
440}
bool running_in_privileged_state()
Definition os_utils.cpp:167

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

442 {
443 std::string value;
444 if(read_env_variable(value, name) && !value.empty()) {
445 try {
446 const size_t val = std::stoul(value, nullptr);
447 return val;
448 } catch(std::exception&) { /* ignore it */
449 }
450 }
451
452 return def;
453}
bool read_env_variable(std::string &value_out, std::string_view var_name)
Definition os_utils.cpp:409

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

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

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

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

328 {
329 const size_t default_page_size = 4096;
330
331#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
332 long p = ::sysconf(_SC_PAGESIZE);
333 if(p > 1) {
334 return static_cast<size_t>(p);
335 } else {
336 return default_page_size;
337 }
338#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
339 BOTAN_UNUSED(default_page_size);
340 SYSTEM_INFO sys_info;
341 ::GetSystemInfo(&sys_info);
342 return sys_info.dwPageSize;
343#else
344 return default_page_size;
345#endif
346}

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