diff options
Diffstat (limited to 'src/lib/utils/os_utils.cpp')
-rw-r--r-- | src/lib/utils/os_utils.cpp | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp new file mode 100644 index 000000000..ae93d58d7 --- /dev/null +++ b/src/lib/utils/os_utils.cpp @@ -0,0 +1,131 @@ +/* +* OS and machine specific utility functions +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/os_utils.h> +#include <botan/exceptn.h> +#include <botan/mem_ops.h> + +//TODO: defined(BOTAN_TARGET_OS_TYPE_IS_POSIX) + +#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + #include <sys/types.h> + #include <sys/mman.h> + #include <sys/resource.h> + #include <unistd.h> +#endif + +namespace Botan { + +namespace OS { + +size_t get_memory_locking_limit() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + /* + * Linux defaults to only 64 KiB of mlockable memory per process + * (too small) but BSDs offer a small fraction of total RAM (more + * than we need). Bound the total mlock size to 512 KiB which is + * enough to run the entire test suite without spilling to non-mlock + * memory (and thus presumably also enough for many useful + * programs), but small enough that we should not cause problems + * even if many processes are mlocking on the same machine. + */ + size_t mlock_requested = BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB; + + /* + * Allow override via env variable + */ + if(const char* env = ::getenv("BOTAN_MLOCK_POOL_SIZE")) + { + try + { + const size_t user_req = std::stoul(env, nullptr); + mlock_requested = std::min(user_req, mlock_requested); + } + catch(std::exception&) { /* ignore it */ } + } + + if(mlock_requested > 0) + { + struct ::rlimit limits; + + ::getrlimit(RLIMIT_MEMLOCK, &limits); + + if(limits.rlim_cur < limits.rlim_max) + { + limits.rlim_cur = limits.rlim_max; + ::setrlimit(RLIMIT_MEMLOCK, &limits); + ::getrlimit(RLIMIT_MEMLOCK, &limits); + } + + return std::min<size_t>(limits.rlim_cur, mlock_requested * 1024); + } +#endif + + return 0; + } + +void* allocate_locked_pages(size_t length) + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + +#if !defined(MAP_NOCORE) + #define MAP_NOCORE 0 +#endif + +#if !defined(MAP_ANONYMOUS) + #define MAP_ANONYMOUS MAP_ANON +#endif + + void* ptr = ::mmap(nullptr, + length, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED | MAP_NOCORE, + /*fd*/-1, + /*offset*/0); + + if(ptr == MAP_FAILED) + { + return nullptr; + } + +#if defined(MADV_DONTDUMP) + ::madvise(ptr, length, MADV_DONTDUMP); +#endif + + if(::mlock(ptr, length) != 0) + { + ::munmap(ptr, length); + return nullptr; // failed to lock + } + + ::memset(ptr, 0, length); + + return ptr; +#else + return nullptr; /* not implemented */ +#endif + } + +void free_locked_pages(void* ptr, size_t length) + { + if(ptr == nullptr || length == 0) + return; + +#if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) + zero_mem(ptr, length); + ::munlock(ptr, length); + ::munmap(ptr, length); +#else + // Invalid argument because no way this pointer was allocated by us + throw Invalid_Argument("Invalid ptr to free_locked_pages"); +#endif + } + +} + +} |