aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build-data/buildh.in6
-rw-r--r--src/lib/utils/info.txt1
-rw-r--r--src/lib/utils/locking_allocator/info.txt9
-rw-r--r--src/lib/utils/locking_allocator/locking_allocator.cpp107
-rw-r--r--src/lib/utils/locking_allocator/locking_allocator.h5
-rw-r--r--src/lib/utils/os_utils.cpp131
-rw-r--r--src/lib/utils/os_utils.h40
7 files changed, 197 insertions, 102 deletions
diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in
index 8b950177f..d993a7ee9 100644
--- a/src/build-data/buildh.in
+++ b/src/build-data/buildh.in
@@ -41,6 +41,12 @@
#define BOTAN_MLOCK_ALLOCATOR_MIN_ALLOCATION 16
#define BOTAN_MLOCK_ALLOCATOR_MAX_ALLOCATION 128
+/*
+* Total maximum amount of RAM (in KiB) we will lock into memory, even
+* if the OS would let us lock more
+*/
+#define BOTAN_MLOCK_ALLOCATOR_MAX_LOCKED_KB 512
+
/* Multiplier on a block cipher's native parallelism */
#define BOTAN_BLOCK_CIPHER_PAR_MULT 4
diff --git a/src/lib/utils/info.txt b/src/lib/utils/info.txt
index 228fccd82..348992ddf 100644
--- a/src/lib/utils/info.txt
+++ b/src/lib/utils/info.txt
@@ -25,6 +25,7 @@ bit_ops.h
ct_utils.h
donna128.h
filesystem.h
+os_utils.h
prefetch.h
rounding.h
semaphore.h
diff --git a/src/lib/utils/locking_allocator/info.txt b/src/lib/utils/locking_allocator/info.txt
index d3b5e86f8..c815bdbcc 100644
--- a/src/lib/utils/locking_allocator/info.txt
+++ b/src/lib/utils/locking_allocator/info.txt
@@ -1,10 +1 @@
define LOCKING_ALLOCATOR 20131128
-
-<os>
-android
-linux
-freebsd
-netbsd
-openbsd
-solaris
-</os>
diff --git a/src/lib/utils/locking_allocator/locking_allocator.cpp b/src/lib/utils/locking_allocator/locking_allocator.cpp
index c145cfd7f..c6181d4c0 100644
--- a/src/lib/utils/locking_allocator/locking_allocator.cpp
+++ b/src/lib/utils/locking_allocator/locking_allocator.cpp
@@ -1,72 +1,22 @@
/*
* Mlock Allocator
-* (C) 2012,2014 Jack Lloyd
+* (C) 2012,2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/locking_allocator.h>
+#include <botan/internal/os_utils.h>
#include <botan/mem_ops.h>
#include <algorithm>
#include <cstdlib>
#include <string>
-
-#include <sys/mman.h>
-#include <sys/resource.h>
+#include <mutex>
namespace Botan {
namespace {
-size_t reset_mlock_limit(size_t max_req)
- {
-#if defined(RLIMIT_MEMLOCK)
- 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, max_req);
-#endif
-
- return 0;
- }
-
-size_t mlock_limit()
- {
- /*
- * 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 = 512;
-
- /*
- * 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 */ }
- }
-
- return reset_mlock_limit(mlock_requested*1024);
- }
-
bool ptr_in_pool(const void* pool_ptr, size_t poolsize,
const void* buf_ptr, size_t bufsize)
{
@@ -240,47 +190,25 @@ bool mlock_allocator::deallocate(void* p, size_t num_elems, size_t elem_size)
return true;
}
-mlock_allocator::mlock_allocator() :
- m_poolsize(mlock_limit()),
- m_pool(nullptr)
+mlock_allocator::mlock_allocator()
{
-#if !defined(MAP_NOCORE)
- #define MAP_NOCORE 0
-#endif
+ const size_t mem_to_lock = OS::get_memory_locking_limit();
-#if !defined(MAP_ANONYMOUS)
- #define MAP_ANONYMOUS MAP_ANON
-#endif
+ /*
+ TODO: split into multiple single page allocations to
+ help ASLR and guard pages to help reduce the damage of
+ a wild reads or write by the application.
+ */
- if(m_poolsize)
+ if(mem_to_lock)
{
- m_pool = static_cast<byte*>(
- ::mmap(
- nullptr, m_poolsize,
- PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_SHARED | MAP_NOCORE,
- -1, 0));
-
- if(m_pool == static_cast<byte*>(MAP_FAILED))
- {
- m_pool = nullptr;
- throw std::runtime_error("Failed to mmap locking_allocator pool");
- }
+ m_pool = static_cast<byte*>(OS::allocate_locked_pages(mem_to_lock));
- clear_mem(m_pool, m_poolsize);
-
- if(::mlock(m_pool, m_poolsize) != 0)
+ if(m_pool != nullptr)
{
- ::munmap(m_pool, m_poolsize);
- m_pool = nullptr;
- throw std::runtime_error("Could not mlock " + std::to_string(m_poolsize) + " bytes");
+ m_poolsize = mem_to_lock;
+ m_freelist.push_back(std::make_pair(0, m_poolsize));
}
-
-#if defined(MADV_DONTDUMP)
- ::madvise(m_pool, m_poolsize, MADV_DONTDUMP);
-#endif
-
- m_freelist.push_back(std::make_pair(0, m_poolsize));
}
}
@@ -288,9 +216,8 @@ mlock_allocator::~mlock_allocator()
{
if(m_pool)
{
- clear_mem(m_pool, m_poolsize);
- ::munlock(m_pool, m_poolsize);
- ::munmap(m_pool, m_poolsize);
+ zero_mem(m_pool, m_poolsize);
+ OS::free_locked_pages(m_pool, m_poolsize);
m_pool = nullptr;
}
}
diff --git a/src/lib/utils/locking_allocator/locking_allocator.h b/src/lib/utils/locking_allocator/locking_allocator.h
index 2aca2dfa9..db75bc02a 100644
--- a/src/lib/utils/locking_allocator/locking_allocator.h
+++ b/src/lib/utils/locking_allocator/locking_allocator.h
@@ -32,11 +32,10 @@ class BOTAN_DLL mlock_allocator
~mlock_allocator();
- const size_t m_poolsize;
-
std::mutex m_mutex;
std::vector<std::pair<size_t, size_t>> m_freelist;
- byte* m_pool;
+ byte* m_pool = nullptr;
+ size_t m_poolsize = 0;
};
}
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
+ }
+
+}
+
+}
diff --git a/src/lib/utils/os_utils.h b/src/lib/utils/os_utils.h
new file mode 100644
index 000000000..0030f88c9
--- /dev/null
+++ b/src/lib/utils/os_utils.h
@@ -0,0 +1,40 @@
+/*
+* OS specific utility functions
+* (C) 2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_OS_UTILS_H__
+#define BOTAN_OS_UTILS_H__
+
+#include <botan/types.h>
+
+namespace Botan {
+
+namespace OS {
+
+/*
+* Returns the maximum amount of memory (in bytes) we could/should
+* hyptothetically allocate. Reads "BOTAN_MLOCK_POOL_SIZE" from
+* environment which can be set to zero.
+*/
+size_t get_memory_locking_limit();
+
+/*
+* Request so many bytes of page-aligned RAM locked into memory OS
+* calls (mlock, VirtualLock, or similar). Returns null on failure. The
+* memory returned is zeroed. Free it with free_locked_pages.
+*/
+void* allocate_locked_pages(size_t length);
+
+/*
+* Free memory allocated by allocate_locked_pages
+*/
+void free_locked_pages(void* ptr, size_t length);
+
+}
+
+}
+
+#endif