Botan 3.5.0
Crypto and TLS for C&
Botan::OS Namespace Reference

Classes

class  Echo_Suppression
 
class  Socket
 
class  SocketUDP
 

Functions

std::vector< void * > allocate_locked_pages (size_t count)
 
std::string BOTAN_TEST_API format_time (time_t time, const std::string &format)
 
void free_locked_pages (const std::vector< void * > &pages)
 
unsigned long get_auxval (unsigned long id)
 
size_t BOTAN_TEST_API get_cpu_available ()
 
uint64_t BOTAN_TEST_API get_cpu_cycle_counter ()
 
uint64_t BOTAN_TEST_API get_high_resolution_clock ()
 
size_t get_memory_locking_limit ()
 
uint32_t BOTAN_TEST_API get_process_id ()
 
uint64_t BOTAN_TEST_API get_system_timestamp_ns ()
 
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 504 of file os_utils.cpp.

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

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

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

◆ format_time()

std::string Botan::OS::format_time ( time_t time,
const std::string & format )

Format a time

Converts the time_t to a local time representation, then invokes std::put_time with the specified format.

Definition at line 330 of file os_utils.cpp.

330 {
331 std::tm tm;
332
333#if defined(BOTAN_TARGET_OS_HAS_WIN32)
334 localtime_s(&tm, &time);
335#elif defined(BOTAN_TARGET_OS_HAS_POSIX1)
336 localtime_r(&time, &tm);
337#else
338 if(auto tmp = std::localtime(&time)) {
339 tm = *tmp;
340 } else {
341 throw Encoding_Error("Could not convert time_t to localtime");
342 }
343#endif
344
345 std::ostringstream oss;
346 oss << std::put_time(&tm, format.c_str());
347 return oss.str();
348}

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

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

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

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

References BOTAN_UNUSED.

Referenced by running_in_privileged_state().

◆ get_cpu_available()

size_t Botan::OS::get_cpu_available ( )

Definition at line 236 of file os_utils.cpp.

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

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

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.

268 {
269 if(uint64_t cpu_clock = OS::get_cpu_cycle_counter()) {
270 return cpu_clock;
271 }
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 struct timespec ts;
307 if(::clock_gettime(clock, &ts) == 0) {
308 return (static_cast<uint64_t>(ts.tv_sec) * 1000000000) + static_cast<uint64_t>(ts.tv_nsec);
309 }
310 }
311#endif
312
313 // Plain C++11 fallback
314 auto now = std::chrono::high_resolution_clock::now().time_since_epoch();
315 return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
316}

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

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

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

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

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

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

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

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

References BOTAN_UNUSED.

◆ open_socket_udp() [1/2]

std::unique_ptr< OS::SocketUDP > Botan::OS::open_socket_udp ( std::string_view hostname,
std::string_view service,
std::chrono::microseconds timeout )

Open up a socket. Will throw on error. Returns null if sockets are not available on this platform.

Definition at line 318 of file socket_udp.cpp.

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

References BOTAN_UNUSED.

Referenced by Botan::Roughtime::online_request(), and open_socket_udp().

◆ open_socket_udp() [2/2]

std::unique_ptr< OS::SocketUDP > Botan::OS::open_socket_udp ( std::string_view uri,
std::chrono::microseconds timeout )

Open up a socket. Will throw on error. Returns null if sockets are not available on this platform.

Definition at line 333 of file socket_udp.cpp.

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

References Botan::URI::fromAny(), and open_socket_udp().

◆ page_allow_access()

void Botan::OS::page_allow_access ( void * page)

Set the MMU to allow R/W access to this page

Definition at line 595 of file os_utils.cpp.

595 {
596#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
597 const size_t page_size = OS::system_page_size();
598 ::mprotect(page, page_size, PROT_READ | PROT_WRITE);
599#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
600 const size_t page_size = OS::system_page_size();
601 DWORD old_perms = 0;
602 ::VirtualProtect(page, page_size, PAGE_READWRITE, &old_perms);
603 BOTAN_UNUSED(old_perms);
604#else
605 BOTAN_UNUSED(page);
606#endif
607}

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

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

609 {
610#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
611 const size_t page_size = OS::system_page_size();
612 ::mprotect(page, page_size, PROT_NONE);
613#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
614 const size_t page_size = OS::system_page_size();
615 DWORD old_perms = 0;
616 ::VirtualProtect(page, page_size, PAGE_NOACCESS, &old_perms);
617 BOTAN_UNUSED(old_perms);
618#else
619 BOTAN_UNUSED(page);
620#endif
621}

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

431 {
432 value_out = "";
433
435 return false;
436 }
437
438#if defined(BOTAN_TARGET_OS_HAS_WIN32) && defined(BOTAN_BUILD_COMPILER_IS_MSVC)
439 const std::string name(name_view);
440 char val[128] = {0};
441 size_t req_size = 0;
442 if(getenv_s(&req_size, val, sizeof(val), name.c_str()) == 0) {
443 // Microsoft's implementation always writes a terminating \0,
444 // and includes it in the reported length of the environment variable
445 // if a value exists.
446 if(req_size > 0 && val[req_size - 1] == '\0') {
447 value_out = std::string(val);
448 } else {
449 value_out = std::string(val, req_size);
450 }
451 return true;
452 }
453#else
454 const std::string name(name_view);
455 if(const char* val = std::getenv(name.c_str())) {
456 value_out = val;
457 return true;
458 }
459#endif
460
461 return false;
462}
bool running_in_privileged_state()
Definition os_utils.cpp:169

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

464 {
465 std::string value;
466 if(read_env_variable(value, name) && !value.empty()) {
467 try {
468 const size_t val = std::stoul(value, nullptr);
469 return val;
470 } catch(std::exception&) { /* ignore it */
471 }
472 }
473
474 return def;
475}
bool read_env_variable(std::string &value_out, std::string_view var_name)
Definition os_utils.cpp:431

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

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

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

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

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

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

350 {
351 const size_t default_page_size = 4096;
352
353#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
354 long p = ::sysconf(_SC_PAGESIZE);
355 if(p > 1) {
356 return static_cast<size_t>(p);
357 } else {
358 return default_page_size;
359 }
360#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK)
361 BOTAN_UNUSED(default_page_size);
362 SYSTEM_INFO sys_info;
363 ::GetSystemInfo(&sys_info);
364 return sys_info.dwPageSize;
365#else
366 return default_page_size;
367#endif
368}

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