Botan 3.2.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 471 of file os_utils.cpp.

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

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

590 {
591 const size_t page_size = OS::system_page_size();
592
593 for(size_t i = 0; i != pages.size(); ++i) {
594 void* ptr = pages[i];
595
596 secure_scrub_memory(ptr, page_size);
597
598 // ptr points to the data page, guard pages are before and after
599 page_allow_access(static_cast<uint8_t*>(ptr) - page_size);
600 page_allow_access(static_cast<uint8_t*>(ptr) + page_size);
601
602#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK)
603 ::munlock(ptr, page_size);
604 ::munmap(static_cast<uint8_t*>(ptr) - page_size, 3 * page_size);
605#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
606 ::VirtualUnlock(ptr, page_size);
607 ::VirtualFree(static_cast<uint8_t*>(ptr) - page_size, 0, MEM_RELEASE);
608#endif
609 }
610}
void page_allow_access(void *page)
Definition os_utils.cpp:562
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 124 of file os_utils.cpp.

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

References BOTAN_UNUSED.

Referenced by running_in_privileged_state().

◆ get_cpu_available()

size_t Botan::OS::get_cpu_available ( )

Definition at line 230 of file os_utils.cpp.

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

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

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

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

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

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

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

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

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

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

562 {
563#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
564 const size_t page_size = OS::system_page_size();
565 ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
566#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
567 const size_t page_size = OS::system_page_size();
568 DWORD old_perms = 0;
569 ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
570 BOTAN_UNUSED(old_perms);
571#else
572 BOTAN_UNUSED(page);
573#endif
574}

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

612 {
613#if defined(BOTAN_TARGET_OS_HAS_PRCTL) && defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME)
614 static constexpr char name[] = "Botan mlock pool";
615 int r = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, reinterpret_cast<uintptr_t>(page), size, name);
616 BOTAN_UNUSED(r);
617#else
618 BOTAN_UNUSED(page, size);
619#endif
620}
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 576 of file os_utils.cpp.

576 {
577#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
578 const size_t page_size = OS::system_page_size();
579 ::mprotect(page, page_size, PROT_NONE);
580#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
581 const size_t page_size = OS::system_page_size();
582 DWORD old_perms = 0;
583 ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms);
584 BOTAN_UNUSED(old_perms);
585#else
586 BOTAN_UNUSED(page);
587#endif
588}

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

405 {
406 value_out = "";
407
409 return false;
410 }
411
412#if defined(BOTAN_TARGET_OS_HAS_WIN32) && defined(BOTAN_BUILD_COMPILER_IS_MSVC)
413 const std::string name(name_view);
414 char val[128] = {0};
415 size_t req_size = 0;
416 if(getenv_s(&req_size, val, sizeof(val), name.c_str()) == 0) {
417 value_out = std::string(val, req_size);
418 return true;
419 }
420#else
421 const std::string name(name_view);
422 if(const char* val = std::getenv(name.c_str())) {
423 value_out = val;
424 return true;
425 }
426#endif
427
428 return false;
429}
bool running_in_privileged_state()
Definition os_utils.cpp:163

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

431 {
432 std::string value;
433 if(read_env_variable(value, name) && !value.empty()) {
434 try {
435 const size_t val = std::stoul(value, nullptr);
436 return val;
437 } catch(std::exception&) { /* ignore it */
438 }
439 }
440
441 return def;
442}
bool read_env_variable(std::string &value_out, std::string_view var_name)
Definition os_utils.cpp:405

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

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

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

163 {
164#if defined(AT_SECURE)
165 return OS::get_auxval(AT_SECURE) != 0;
166#elif defined(BOTAN_TARGET_OS_HAS_POSIX1)
167 return (::getuid() != ::geteuid()) || (::getgid() != ::getegid());
168#else
169 return false;
170#endif
171}

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

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

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

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