diff options
author | lloyd <[email protected]> | 2012-06-11 15:56:03 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-06-11 15:56:03 +0000 |
commit | 9494cb23020e18b9ff5272fa55cb9d125bb0b003 (patch) | |
tree | 7ae29aa1ce278faba1e746ee38ccd357e0440c8b | |
parent | 8d30d35141f43c784bbce356974fd3c6c70031f0 (diff) |
Avoid integer overflows in calls to the mlock allocator, changing the
interface to more of a calloc style. Alignment remains set to the
underlying type size.
Increase the maximum mlock size to 512 KB.
-rw-r--r-- | src/alloc/locking_allocator/locking_allocator.cpp | 56 | ||||
-rw-r--r-- | src/alloc/locking_allocator/locking_allocator.h | 4 | ||||
-rw-r--r-- | src/alloc/secmem.h | 4 |
3 files changed, 44 insertions, 20 deletions
diff --git a/src/alloc/locking_allocator/locking_allocator.cpp b/src/alloc/locking_allocator/locking_allocator.cpp index a5c76f563..1595c526f 100644 --- a/src/alloc/locking_allocator/locking_allocator.cpp +++ b/src/alloc/locking_allocator/locking_allocator.cpp @@ -18,6 +18,17 @@ namespace { 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. + */ + const size_t MLOCK_UPPER_BOUND = 512*1024; + struct rlimit limits; ::getrlimit(RLIMIT_MEMLOCK, &limits); @@ -28,15 +39,7 @@ size_t mlock_limit() ::getrlimit(RLIMIT_MEMLOCK, &limits); } - /* - * 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 256 KiB which is - * enough to run the entire test suite without spilling to non-mlock - * memory, but small enough that we should not cause problems if - * multiple processes are mlocking on the same machine. - */ - return std::min<size_t>(limits.rlim_cur, 256*1024); + return std::min<size_t>(limits.rlim_cur, MLOCK_UPPER_BOUND); } bool ptr_in_pool(const void* pool_ptr, size_t poolsize, @@ -49,7 +52,7 @@ bool ptr_in_pool(const void* pool_ptr, size_t poolsize, return false; BOTAN_ASSERT(buf + bufsize <= pool + poolsize, - "Invalid pointer/length halfway into mem pool"); + "Pointer does not partially overlap pool"); return true; } @@ -64,9 +67,18 @@ size_t padding_for_alignment(size_t offset, size_t desired_alignment) } -void* mlock_allocator::allocate(size_t n, size_t alignment) +void* mlock_allocator::allocate(size_t num_elems, size_t elem_size) { - if(!m_pool || n >= m_poolsize) + if(!m_pool) + return; + + const size_t n = num_elems * elem_size; + const size_t alignment = elem_size; + + if(n / elem_size != num_elems) + return nullptr; // overflow! + + if(n >= m_poolsize) return nullptr; // bigger than the whole pool! std::lock_guard<std::mutex> lock(m_mutex); @@ -134,9 +146,21 @@ void* mlock_allocator::allocate(size_t n, size_t alignment) return nullptr; } -bool mlock_allocator::deallocate(void* p, size_t n) +bool mlock_allocator::deallocate(void* p, size_t num_elems, size_t elem_size) { - if(!m_pool || !ptr_in_pool(m_pool, m_poolsize, p, n)) + if(!m_pool) + return false; + + size_t n = num_elems * elem_size; + + /* + We return nullptr in allocate if there was an overflow, so we + should never ever see an overflow in a deallocation. + */ + BOTAN_ASSERT(n / elem_size == num_elems, + "No overflow in deallocation"); + + if(!ptr_in_pool(m_pool, m_poolsize, p, n)) return false; std::lock_guard<std::mutex> lock(m_mutex); @@ -201,7 +225,7 @@ mlock_allocator::mlock_allocator() : -1, 0)); if(m_pool == static_cast<byte*>(MAP_FAILED)) - throw std::runtime_error("Failed to mmap pool"); + throw std::runtime_error("Failed to mmap locking_allocator pool"); clear_mem(m_pool, m_poolsize); @@ -209,7 +233,7 @@ mlock_allocator::mlock_allocator() : { ::munmap(m_pool, m_poolsize); m_pool = nullptr; - throw std::runtime_error("Failed to lock pool"); + throw std::runtime_error("Failed to lock pool in memory"); } m_freelist.push_back(std::make_pair(0, m_poolsize)); diff --git a/src/alloc/locking_allocator/locking_allocator.h b/src/alloc/locking_allocator/locking_allocator.h index 2c756fcd1..b2dd10dcc 100644 --- a/src/alloc/locking_allocator/locking_allocator.h +++ b/src/alloc/locking_allocator/locking_allocator.h @@ -19,9 +19,9 @@ class BOTAN_DLL mlock_allocator public: static mlock_allocator& instance(); - void* allocate(size_t n, size_t alignment); + void* allocate(size_t num_elems, size_t elem_size); - bool deallocate(void* p, size_t n); + bool deallocate(void* p, size_t num_elems, size_t elem_size); private: mlock_allocator(); diff --git a/src/alloc/secmem.h b/src/alloc/secmem.h index 739ba63a5..fd70eea71 100644 --- a/src/alloc/secmem.h +++ b/src/alloc/secmem.h @@ -45,7 +45,7 @@ class secure_allocator pointer allocate(size_type n, const void* = 0) { #if defined(BOTAN_HAS_LOCKING_ALLOCATOR) - if(pointer p = static_cast<pointer>(mlock_allocator::instance().allocate(n*sizeof(T), sizeof(T)))) + if(pointer p = static_cast<pointer>(mlock_allocator::instance().allocate(n, sizeof(T)))) return p; #endif @@ -59,7 +59,7 @@ class secure_allocator clear_mem(p, n); #if defined(BOTAN_HAS_LOCKING_ALLOCATOR) - if(mlock_allocator::instance().deallocate(p, n*sizeof(T))) + if(mlock_allocator::instance().deallocate(p, n, sizeof(T))) return; #endif |