diff options
author | lloyd <[email protected]> | 2012-05-25 22:52:00 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-05-25 22:52:00 +0000 |
commit | 12090a7148d9ee73572cc1a7268fc489504a8173 (patch) | |
tree | 51e50ce0852c56231e9e6dc13f168b10edd45d01 /src/alloc | |
parent | 9594979caf775dc4062850044715b804d1fda60c (diff) | |
parent | 65cc04445f8d40497f02a14bd8cb97081790e54b (diff) |
propagate from branch 'net.randombit.botan.x509-path-validation' (head 63b5a20eab129ca13287fda33d2d02eec329708f)
to branch 'net.randombit.botan' (head 8b8150f09c55184f028f2929c4e7f7cd0d46d96e)
Diffstat (limited to 'src/alloc')
-rw-r--r-- | src/alloc/alloc_mmap/info.txt | 28 | ||||
-rw-r--r-- | src/alloc/alloc_mmap/mmap_mem.cpp | 143 | ||||
-rw-r--r-- | src/alloc/alloc_mmap/mmap_mem.h | 36 | ||||
-rw-r--r-- | src/alloc/allocate.h | 65 | ||||
-rw-r--r-- | src/alloc/info.txt | 1 | ||||
-rw-r--r-- | src/alloc/locking_allocator/info.txt | 1 | ||||
-rw-r--r-- | src/alloc/locking_allocator/locking_allocator.cpp | 236 | ||||
-rw-r--r-- | src/alloc/locking_allocator/locking_allocator.h | 39 | ||||
-rw-r--r-- | src/alloc/mem_pool/info.txt | 12 | ||||
-rw-r--r-- | src/alloc/mem_pool/mem_pool.cpp | 252 | ||||
-rw-r--r-- | src/alloc/mem_pool/mem_pool.h | 77 | ||||
-rw-r--r-- | src/alloc/secmem.h | 439 | ||||
-rw-r--r-- | src/alloc/system_alloc/defalloc.cpp | 103 | ||||
-rw-r--r-- | src/alloc/system_alloc/defalloc.h | 46 | ||||
-rw-r--r-- | src/alloc/system_alloc/info.txt | 13 |
15 files changed, 366 insertions, 1125 deletions
diff --git a/src/alloc/alloc_mmap/info.txt b/src/alloc/alloc_mmap/info.txt deleted file mode 100644 index 562277a37..000000000 --- a/src/alloc/alloc_mmap/info.txt +++ /dev/null @@ -1,28 +0,0 @@ -define ALLOC_MMAP - -<source> -mmap_mem.cpp -</source> - -<header:internal> -mmap_mem.h -</header:internal> - -<os> -linux -freebsd -dragonfly -openbsd -netbsd -solaris -qnx -darwin -tru64 - -# Only without -ansi, otherwise can't get mkstemp -#cygwin -</os> - -<requires> -mem_pool -</requires> diff --git a/src/alloc/alloc_mmap/mmap_mem.cpp b/src/alloc/alloc_mmap/mmap_mem.cpp deleted file mode 100644 index e4b602764..000000000 --- a/src/alloc/alloc_mmap/mmap_mem.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* -* Memory Mapping Allocator -* (C) 1999-2010 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/internal/mmap_mem.h> -#include <vector> -#include <cstring> - -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <unistd.h> -#include <stdlib.h> -#include <fcntl.h> -#include <errno.h> - -#ifndef MAP_FAILED - #define MAP_FAILED -1 -#endif - -namespace Botan { - -namespace { - -/* -* MemoryMapping_Allocator Exception -*/ -class BOTAN_DLL MemoryMapping_Failed : public Exception - { - public: - MemoryMapping_Failed(const std::string& msg) : - Exception("MemoryMapping_Allocator: " + msg) {} - }; - -} - -/* -* Memory Map a File into Memory -*/ -void* MemoryMapping_Allocator::alloc_block(size_t n) - { - class TemporaryFile - { - public: - int get_fd() const { return fd; } - - TemporaryFile(const std::string& base) - { - const std::string mkstemp_template = base + "XXXXXX"; - - std::vector<char> filepath(mkstemp_template.begin(), - mkstemp_template.end()); - filepath.push_back(0); // add terminating NULL - - mode_t old_umask = ::umask(077); - fd = ::mkstemp(&filepath[0]); - ::umask(old_umask); - - if(fd == -1) - throw MemoryMapping_Failed("Temporary file allocation failed"); - - if(::unlink(&filepath[0]) != 0) - throw MemoryMapping_Failed("Could not unlink temporary file"); - } - - ~TemporaryFile() - { - /* - * We can safely close here, because post-mmap the file - * will continue to exist until the mmap is unmapped from - * our address space upon deallocation (or process exit). - */ - if(fd != -1 && ::close(fd) == -1) - throw MemoryMapping_Failed("Could not close file"); - } - private: - int fd; - }; - - TemporaryFile file("/tmp/botan_"); - - if(file.get_fd() == -1) - throw MemoryMapping_Failed("Could not create file"); - - std::vector<byte> zeros(4096); - - size_t remaining = n; - - while(remaining) - { - const size_t write_try = std::min(zeros.size(), remaining); - - ssize_t wrote_got = ::write(file.get_fd(), - &zeros[0], - write_try); - - if(wrote_got == -1 && errno != EINTR) - throw MemoryMapping_Failed("Could not write to file"); - - remaining -= wrote_got; - } - -#ifndef MAP_NOSYNC - #define MAP_NOSYNC 0 -#endif - - void* ptr = ::mmap(0, n, - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_NOSYNC, - file.get_fd(), 0); - - if(ptr == static_cast<void*>(MAP_FAILED)) - throw MemoryMapping_Failed("Could not map file"); - - return ptr; - } - -/* -* Remove a Memory Mapping -*/ -void MemoryMapping_Allocator::dealloc_block(void* ptr, size_t n) - { - if(ptr == 0) - return; - - const byte PATTERNS[] = { 0x00, 0xF5, 0x5A, 0xAF, 0x00 }; - - for(size_t i = 0; i != sizeof(PATTERNS); ++i) - { - std::memset(ptr, PATTERNS[i], n); - - if(::msync((char*)ptr, n, MS_SYNC)) - throw MemoryMapping_Failed("Sync operation failed"); - } - - if(::munmap((char*)ptr, n)) - throw MemoryMapping_Failed("Could not unmap file"); - } - -} diff --git a/src/alloc/alloc_mmap/mmap_mem.h b/src/alloc/alloc_mmap/mmap_mem.h deleted file mode 100644 index fa4e5e715..000000000 --- a/src/alloc/alloc_mmap/mmap_mem.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -* Memory Mapping Allocator -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_MMAP_ALLOCATOR_H__ -#define BOTAN_MMAP_ALLOCATOR_H__ - -#include <botan/internal/mem_pool.h> - -namespace Botan { - -/** -* Allocator that uses memory maps backed by disk. We zeroize the map -* upon deallocation. If swap occurs, the VM will swap to the shared -* file backing rather than to a swap device, which means we know where -* it is and can zap it later. -*/ -class MemoryMapping_Allocator : public Pooling_Allocator - { - public: - /** - * @param mutex used for internal locking - */ - MemoryMapping_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {} - std::string type() const { return "mmap"; } - private: - void* alloc_block(size_t); - void dealloc_block(void*, size_t); - }; - -} - -#endif diff --git a/src/alloc/allocate.h b/src/alloc/allocate.h deleted file mode 100644 index b8574be1e..000000000 --- a/src/alloc/allocate.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -* Allocator -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_ALLOCATOR_H__ -#define BOTAN_ALLOCATOR_H__ - -#include <botan/types.h> -#include <string> - -namespace Botan { - -/** -* Allocator Interface -*/ -class BOTAN_DLL Allocator - { - public: - /** - * Acquire a pointer to an allocator - * @param locking is true if the allocator should attempt to - * secure the memory (eg for using to store keys) - * @return pointer to an allocator; ownership remains with library, - * so do not delete - */ - static Allocator* get(bool locking); - - /** - * Allocate a block of memory - * @param n how many bytes to allocate - * @return pointer to n bytes of memory - */ - virtual void* allocate(size_t n) = 0; - - /** - * Deallocate memory allocated with allocate() - * @param ptr the pointer returned by allocate() - * @param n the size of the block pointed to by ptr - */ - virtual void deallocate(void* ptr, size_t n) = 0; - - /** - * @return name of this allocator type - */ - virtual std::string type() const = 0; - - /** - * Initialize the allocator - */ - virtual void init() {} - - /** - * Shutdown the allocator - */ - virtual void destroy() {} - - virtual ~Allocator() {} - }; - -} - -#endif diff --git a/src/alloc/info.txt b/src/alloc/info.txt index 40e7bacdf..0ab7fa768 100644 --- a/src/alloc/info.txt +++ b/src/alloc/info.txt @@ -1,4 +1,3 @@ <header:public> -allocate.h secmem.h </header:public> diff --git a/src/alloc/locking_allocator/info.txt b/src/alloc/locking_allocator/info.txt new file mode 100644 index 000000000..34877e6bd --- /dev/null +++ b/src/alloc/locking_allocator/info.txt @@ -0,0 +1 @@ +define LOCKING_ALLOCATOR diff --git a/src/alloc/locking_allocator/locking_allocator.cpp b/src/alloc/locking_allocator/locking_allocator.cpp new file mode 100644 index 000000000..cc7d24c8d --- /dev/null +++ b/src/alloc/locking_allocator/locking_allocator.cpp @@ -0,0 +1,236 @@ +/* +* Mlock Allocator +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/locking_allocator.h> +#include <botan/internal/assert.h> +#include <algorithm> +#include <cstring> +#include <sys/mman.h> +#include <sys/resource.h> + +namespace Botan { + +namespace { + +size_t mlock_limit() + { + 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); + } + + /* + * 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); + } + +bool ptr_in_pool(const void* pool_ptr, size_t poolsize, + const void* buf_ptr, size_t bufsize) + { + const size_t pool = reinterpret_cast<size_t>(pool_ptr); + const size_t buf = reinterpret_cast<size_t>(buf_ptr); + + if(buf < pool || buf >= pool + poolsize) + return false; + + BOTAN_ASSERT(buf + bufsize <= pool + poolsize, + "Invalid pointer/length halfway into mem pool"); + + return true; + } + +size_t padding_for_alignment(size_t offset, size_t desired_alignment) + { + size_t mod = offset % desired_alignment; + if(mod == 0) + return 0; // already right on + return desired_alignment - mod; + } + +} + +void* mlock_allocator::allocate(size_t n, size_t alignment) + { + if(!m_pool || n >= m_poolsize) + return nullptr; // bigger than the whole pool! + + std::lock_guard<std::mutex> lock(m_mutex); + + auto best_fit = m_freelist.end(); + + for(auto i = m_freelist.begin(); i != m_freelist.end(); ++i) + { + // If we have a perfect fit, use it immediately + if(i->second == n && (i->first % alignment) == 0) + { + const size_t offset = i->first; + m_freelist.erase(i); + ::memset(m_pool + offset, 0, n); + + BOTAN_ASSERT((reinterpret_cast<size_t>(m_pool) + offset) % alignment == 0, + "Returning correctly aligned pointer"); + + return m_pool + offset; + } + + if((i->second >= (n + padding_for_alignment(i->first, alignment)) && + ((best_fit == m_freelist.end()) || (best_fit->second > i->second)))) + { + best_fit = i; + } + } + + if(best_fit != m_freelist.end()) + { + const size_t offset = best_fit->first; + + const size_t alignment_padding = padding_for_alignment(offset, alignment); + + best_fit->first += n + alignment_padding; + best_fit->second -= n + alignment_padding; + + // Need to realign, split the block + if(alignment_padding) + { + /* + If we used the entire block except for small piece used for + alignment at the beginning, so just update the entry already + in place (as it is in the correct location), rather than + deleting the empty range and inserting the new one in the + same location. + */ + if(best_fit->second == 0) + { + best_fit->first = offset; + best_fit->second = alignment_padding; + } + else + m_freelist.insert(best_fit, std::make_pair(offset, alignment_padding)); + } + + ::memset(m_pool + offset + alignment_padding, 0, n); + + BOTAN_ASSERT((reinterpret_cast<size_t>(m_pool) + offset + alignment_padding) % alignment == 0, + "Returning correctly aligned pointer"); + + return m_pool + offset + alignment_padding; + } + + return nullptr; + } + +bool mlock_allocator::deallocate(void* p, size_t n) + { + if(!m_pool || !ptr_in_pool(m_pool, m_poolsize, p, n)) + return false; + + std::lock_guard<std::mutex> lock(m_mutex); + + const size_t start = static_cast<byte*>(p) - m_pool; + + auto comp = [](std::pair<size_t, size_t> x, std::pair<size_t, size_t> y){ return x.first < y.first; }; + + auto i = std::lower_bound(m_freelist.begin(), m_freelist.end(), + std::make_pair(start, 0), comp); + + // try to merge with later block + if(i != m_freelist.end() && start + n == i->first) + { + i->first = start; + i->second += n; + n = 0; + } + + // try to merge with previous block + if(i != m_freelist.begin()) + { + auto prev = std::prev(i); + + if(prev->first + prev->second == start) + { + if(n) + { + prev->second += n; + n = 0; + } + else + { + // merge adjoining + prev->second += i->second; + m_freelist.erase(i); + } + } + } + + if(n != 0) // no merge possible? + m_freelist.insert(i, std::make_pair(start, n)); + + return true; + } + +mlock_allocator::mlock_allocator() : + m_poolsize(mlock_limit()), + m_pool(nullptr) + { +#if !defined(MAP_NOCORE) + #define MAP_NOCORE 0 +#endif + + if(m_poolsize) + { + 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)) + throw std::runtime_error("Failed to mmap pool"); + + std::memset(m_pool, 0x00, m_poolsize); + + if(::mlock(m_pool, m_poolsize) != 0) + { + ::munmap(m_pool, m_poolsize); + m_pool = nullptr; + throw std::runtime_error("Failed to lock pool"); + } + + m_freelist.push_back(std::make_pair(0, m_poolsize)); + } + } + +mlock_allocator::~mlock_allocator() + { + if(m_pool) + { + std::memset(m_pool, 0, m_poolsize); + ::munlock(m_pool, m_poolsize); + ::munmap(m_pool, m_poolsize); + m_pool = nullptr; + } + } + +mlock_allocator& mlock_allocator::instance() + { + static mlock_allocator mlock; + return mlock; + } + +} diff --git a/src/alloc/locking_allocator/locking_allocator.h b/src/alloc/locking_allocator/locking_allocator.h new file mode 100644 index 000000000..2c756fcd1 --- /dev/null +++ b/src/alloc/locking_allocator/locking_allocator.h @@ -0,0 +1,39 @@ +/* +* Mlock Allocator +* (C) 2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MLOCK_ALLOCATOR_H__ +#define BOTAN_MLOCK_ALLOCATOR_H__ + +#include <botan/types.h> +#include <vector> +#include <mutex> + +namespace Botan { + +class BOTAN_DLL mlock_allocator + { + public: + static mlock_allocator& instance(); + + void* allocate(size_t n, size_t alignment); + + bool deallocate(void* p, size_t n); + + private: + mlock_allocator(); + + ~mlock_allocator(); + + std::mutex m_mutex; + size_t m_poolsize; + std::vector<std::pair<size_t, size_t>> m_freelist; + byte* m_pool; + }; + +} + +#endif diff --git a/src/alloc/mem_pool/info.txt b/src/alloc/mem_pool/info.txt deleted file mode 100644 index 5097c325f..000000000 --- a/src/alloc/mem_pool/info.txt +++ /dev/null @@ -1,12 +0,0 @@ - -<source> -mem_pool.cpp -</source> - -<header:internal> -mem_pool.h -</header:internal> - -<requires> -mutex -</requires> diff --git a/src/alloc/mem_pool/mem_pool.cpp b/src/alloc/mem_pool/mem_pool.cpp deleted file mode 100644 index f32eb9604..000000000 --- a/src/alloc/mem_pool/mem_pool.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* -* Pooling Allocator -* (C) 1999-2008 Jack Lloyd -* 2005 Matthew Gregan -* 2005-2006 Matt Johnston -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/internal/mem_pool.h> -#include <botan/internal/rounding.h> -#include <botan/mem_ops.h> -#include <algorithm> -#include <exception> - -namespace Botan { - -/* -* Memory_Block Constructor -*/ -Pooling_Allocator::Memory_Block::Memory_Block(void* buf) - { - buffer = static_cast<byte*>(buf); - bitmap = 0; - buffer_end = buffer + (BLOCK_SIZE * BITMAP_SIZE); - } - -/* -* See if ptr is contained by this block -*/ -bool Pooling_Allocator::Memory_Block::contains(void* ptr, - size_t length) const - { - return ((buffer <= ptr) && - (buffer_end >= static_cast<byte*>(ptr) + length * BLOCK_SIZE)); - } - -/* -* Allocate some memory, if possible -*/ -byte* Pooling_Allocator::Memory_Block::alloc(size_t n) - { - if(n == 0 || n > BITMAP_SIZE) - return 0; - - if(n == BITMAP_SIZE) - { - if(bitmap) - return 0; - else - { - bitmap = ~bitmap; - return buffer; - } - } - - bitmap_type mask = (static_cast<bitmap_type>(1) << n) - 1; - size_t offset = 0; - - while(bitmap & mask) - { - mask <<= 1; - ++offset; - - if((bitmap & mask) == 0) - break; - if(mask >> 63) - break; - } - - if(bitmap & mask) - return 0; - - bitmap |= mask; - return buffer + offset * BLOCK_SIZE; - } - -/* -* Mark this memory as free, if we own it -*/ -void Pooling_Allocator::Memory_Block::free(void* ptr, size_t blocks) - { - clear_mem(static_cast<byte*>(ptr), blocks * BLOCK_SIZE); - - const size_t offset = (static_cast<byte*>(ptr) - buffer) / BLOCK_SIZE; - - if(offset == 0 && blocks == BITMAP_SIZE) - bitmap = ~bitmap; - else - { - for(size_t j = 0; j != blocks; ++j) - bitmap &= ~(static_cast<bitmap_type>(1) << (j+offset)); - } - } - -/* -* Pooling_Allocator Constructor -*/ -Pooling_Allocator::Pooling_Allocator(Mutex* m) : mutex(m) - { - last_used = blocks.begin(); - } - -/* -* Pooling_Allocator Destructor -*/ -Pooling_Allocator::~Pooling_Allocator() - { - delete mutex; - if(blocks.size()) - throw Invalid_State("Pooling_Allocator: Never released memory"); - } - -/* -* Free all remaining memory -*/ -void Pooling_Allocator::destroy() - { - Mutex_Holder lock(mutex); - - blocks.clear(); - - for(size_t j = 0; j != allocated.size(); ++j) - dealloc_block(allocated[j].first, allocated[j].second); - allocated.clear(); - } - -/* -* Allocation -*/ -void* Pooling_Allocator::allocate(size_t n) - { - const size_t BITMAP_SIZE = Memory_Block::bitmap_size(); - const size_t BLOCK_SIZE = Memory_Block::block_size(); - - Mutex_Holder lock(mutex); - - if(n <= BITMAP_SIZE * BLOCK_SIZE) - { - const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; - - byte* mem = allocate_blocks(block_no); - if(mem) - return mem; - - get_more_core(BOTAN_MEM_POOL_CHUNK_SIZE); - - mem = allocate_blocks(block_no); - if(mem) - return mem; - - throw Memory_Exhaustion(); - } - - void* new_buf = alloc_block(n); - if(new_buf) - return new_buf; - - throw Memory_Exhaustion(); - } - -/* -* Deallocation -*/ -void Pooling_Allocator::deallocate(void* ptr, size_t n) - { - const size_t BITMAP_SIZE = Memory_Block::bitmap_size(); - const size_t BLOCK_SIZE = Memory_Block::block_size(); - - if(ptr == 0 && n == 0) - return; - - Mutex_Holder lock(mutex); - - if(n > BITMAP_SIZE * BLOCK_SIZE) - dealloc_block(ptr, n); - else - { - const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; - - std::vector<Memory_Block>::iterator i = - std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); - - if(i == blocks.end() || !i->contains(ptr, block_no)) - throw Invalid_State("Pointer released to the wrong allocator"); - - i->free(ptr, block_no); - } - } - -/* -* Try to get some memory from an existing block -*/ -byte* Pooling_Allocator::allocate_blocks(size_t n) - { - if(blocks.empty()) - return 0; - - std::vector<Memory_Block>::iterator i = last_used; - - do - { - byte* mem = i->alloc(n); - if(mem) - { - last_used = i; - return mem; - } - - ++i; - if(i == blocks.end()) - i = blocks.begin(); - } - while(i != last_used); - - return 0; - } - -/* -* Allocate more memory for the pool -*/ -void Pooling_Allocator::get_more_core(size_t in_bytes) - { - const size_t BITMAP_SIZE = Memory_Block::bitmap_size(); - const size_t BLOCK_SIZE = Memory_Block::block_size(); - - const size_t TOTAL_BLOCK_SIZE = BLOCK_SIZE * BITMAP_SIZE; - - // upper bound on allocation is 1 MiB - in_bytes = std::min<size_t>(in_bytes, 1024 * 1024); - - const size_t in_blocks = round_up(in_bytes, BLOCK_SIZE) / TOTAL_BLOCK_SIZE; - const size_t to_allocate = in_blocks * TOTAL_BLOCK_SIZE; - - void* ptr = alloc_block(to_allocate); - if(ptr == 0) - throw Memory_Exhaustion(); - - allocated.push_back(std::make_pair(ptr, to_allocate)); - - for(size_t j = 0; j != in_blocks; ++j) - { - byte* byte_ptr = static_cast<byte*>(ptr); - blocks.push_back(Memory_Block(byte_ptr + j * TOTAL_BLOCK_SIZE)); - } - - std::sort(blocks.begin(), blocks.end()); - last_used = std::lower_bound(blocks.begin(), blocks.end(), - Memory_Block(ptr)); - } - -} diff --git a/src/alloc/mem_pool/mem_pool.h b/src/alloc/mem_pool/mem_pool.h deleted file mode 100644 index 28d4dd903..000000000 --- a/src/alloc/mem_pool/mem_pool.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -* Pooling Allocator -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_POOLING_ALLOCATOR_H__ -#define BOTAN_POOLING_ALLOCATOR_H__ - -#include <botan/allocate.h> -#include <botan/exceptn.h> -#include <botan/internal/mutex.h> -#include <utility> -#include <vector> - -namespace Botan { - -/** -* Pooling Allocator -*/ -class Pooling_Allocator : public Allocator - { - public: - void* allocate(size_t); - void deallocate(void*, size_t); - - void destroy(); - - /** - * @param mutex used for internal locking - */ - Pooling_Allocator(Mutex* mutex); - ~Pooling_Allocator(); - private: - void get_more_core(size_t); - byte* allocate_blocks(size_t); - - virtual void* alloc_block(size_t) = 0; - virtual void dealloc_block(void*, size_t) = 0; - - class Memory_Block - { - public: - Memory_Block(void*); - - static size_t bitmap_size() { return BITMAP_SIZE; } - static size_t block_size() { return BLOCK_SIZE; } - - bool contains(void*, size_t) const; - byte* alloc(size_t); - void free(void*, size_t); - - bool operator<(const Memory_Block& other) const - { - if(buffer < other.buffer && other.buffer < buffer_end) - return false; - return (buffer < other.buffer); - } - private: - typedef u64bit bitmap_type; - static const size_t BITMAP_SIZE = 8 * sizeof(bitmap_type); - static const size_t BLOCK_SIZE = 64; - - bitmap_type bitmap; - byte* buffer, *buffer_end; - }; - - std::vector<Memory_Block> blocks; - std::vector<Memory_Block>::iterator last_used; - std::vector<std::pair<void*, size_t> > allocated; - Mutex* mutex; - }; - -} - -#endif diff --git a/src/alloc/secmem.h b/src/alloc/secmem.h index 6c8a75c44..739ba63a5 100644 --- a/src/alloc/secmem.h +++ b/src/alloc/secmem.h @@ -1,6 +1,6 @@ /* * Secure Memory Buffers -* (C) 1999-2007 Jack Lloyd +* (C) 1999-2007,2012 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -8,369 +8,121 @@ #ifndef BOTAN_SECURE_MEMORY_BUFFERS_H__ #define BOTAN_SECURE_MEMORY_BUFFERS_H__ -#include <botan/allocate.h> #include <botan/mem_ops.h> #include <algorithm> +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + #include <botan/locking_allocator.h> +#endif + namespace Botan { -/** -* This class represents variable length memory buffers. -*/ template<typename T> -class MemoryRegion +class secure_allocator { public: - /** - * Find out the size of the buffer, i.e. how many objects of type T it - * contains. - * @return size of the buffer - */ - size_t size() const { return used; } - - /** - * Find out whether this buffer is empty. - * @return true if the buffer is empty, false otherwise - */ - bool empty() const { return (used == 0); } - - /** - * Get a pointer to the first element in the buffer. - * @return pointer to the first element in the buffer - */ - operator T* () { return buf; } - - /** - * Get a constant pointer to the first element in the buffer. - * @return constant pointer to the first element in the buffer - */ - operator const T* () const { return buf; } - - /** - * Get a pointer to the first element in the buffer. - * @return pointer to the first element in the buffer - */ - T* begin() { return buf; } - - /** - * Get a constant pointer to the first element in the buffer. - * @return constant pointer to the first element in the buffer - */ - const T* begin() const { return buf; } - - /** - * Get a pointer to the last element in the buffer. - * @return pointer to the last element in the buffer - */ - T* end() { return (buf + size()); } - - /** - * Get a constant pointer to the last element in the buffer. - * @return constant pointer to the last element in the buffer - */ - const T* end() const { return (buf + size()); } - - /** - * Check two buffers for equality. - * @return true iff the content of both buffers is byte-wise equal - */ - bool operator==(const MemoryRegion<T>& other) const - { - return (size() == other.size() && - same_mem(buf, other.buf, size())); - } + typedef T value_type; - /** - * Compare two buffers - * @return true iff this is ordered before other - */ - bool operator<(const MemoryRegion<T>& other) const; - - /** - * Check two buffers for inequality. - * @return false if the content of both buffers is byte-wise equal, true - * otherwise. - */ - bool operator!=(const MemoryRegion<T>& other) const - { return (!(*this == other)); } - - /** - * Copy the contents of another buffer into this buffer. - * The former contents of *this are discarded. - * @param other the buffer to copy the contents from. - * @return reference to *this - */ - MemoryRegion<T>& operator=(const MemoryRegion<T>& other) - { - if(this != &other) - { - this->resize(other.size()); - this->copy(&other[0], other.size()); - } - return (*this); - } + typedef T* pointer; + typedef const T* const_pointer; + + typedef T& reference; + typedef const T& const_reference; - /** - * Copy the contents of an array of objects of type T into this buffer. - * The former contents of *this are discarded. - * The length of *this must be at least n, otherwise memory errors occur. - * @param in the array to copy the contents from - * @param n the length of in - */ - void copy(const T in[], size_t n) + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + secure_allocator() noexcept {} + + ~secure_allocator() noexcept {} + + pointer address(reference x) const noexcept + { return std::addressof(x); } + + const_pointer address(const_reference x) const noexcept + { return std::addressof(x); } + + pointer allocate(size_type n, const void* = 0) { - copy_mem(buf, in, std::min(n, size())); +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + if(pointer p = static_cast<pointer>(mlock_allocator::instance().allocate(n*sizeof(T), sizeof(T)))) + return p; +#endif + + pointer p = new T[n]; + clear_mem(p, n); + return p; } - /** - * Copy the contents of an array of objects of type T into this buffer. - * The former contents of *this are discarded. - * The length of *this must be at least n, otherwise memory errors occur. - * @param off the offset position inside this buffer to start inserting - * the copied bytes - * @param in the array to copy the contents from - * @param n the length of in - */ - void copy(size_t off, const T in[], size_t n) + void deallocate(pointer p, size_type n) { - copy_mem(buf + off, in, std::min(n, size() - off)); + clear_mem(p, n); + +#if defined(BOTAN_HAS_LOCKING_ALLOCATOR) + if(mlock_allocator::instance().deallocate(p, n*sizeof(T))) + return; +#endif + + delete [] p; } - /** - * Append a single element. - * @param x the element to append - */ - void push_back(T x) + size_type max_size() const noexcept { - resize(size() + 1); - buf[size()-1] = x; + return static_cast<size_type>(-1) / sizeof(T); } - /** - * Reset this buffer to an empty buffer with size zero. - */ - void clear() { resize(0); } - - /** - * Inserts or erases elements at the end such that the size - * becomes n, leaving elements in the range 0...n unmodified if - * set or otherwise zero-initialized - * @param n length of the new buffer - */ - void resize(size_t n); - - /** - * Swap this buffer with another object. - */ - void swap(MemoryRegion<T>& other); - - virtual ~MemoryRegion() { deallocate(buf, allocated); } - protected: - MemoryRegion() : buf(0), used(0), allocated(0), alloc(0) {} - - /** - * Copy constructor - * @param other the other region to copy - */ - MemoryRegion(const MemoryRegion<T>& other) + template<typename U, typename... Args> + void construct(U* p, Args&&... args) { - buf = 0; - used = allocated = 0; - alloc = other.alloc; - resize(other.size()); - copy(&other[0], other.size()); + ::new(static_cast<void*>(p)) U(std::forward<Args>(args)...); } - /** - * @param locking should we use a locking allocator - * @param length the initial length to use - */ - void init(bool locking, size_t length = 0) - { alloc = Allocator::get(locking); resize(length); } + template<typename U> void destroy(U* p) { p->~U(); } + }; - private: - T* allocate(size_t n) - { - return static_cast<T*>(alloc->allocate(sizeof(T)*n)); - } +template<typename T> inline bool +operator==(const secure_allocator<T>&, const secure_allocator<T>&) + { return true; } - void deallocate(T* p, size_t n) - { if(alloc && p && n) alloc->deallocate(p, sizeof(T)*n); } +template<typename T> inline bool +operator!=(const secure_allocator<T>&, const secure_allocator<T>&) + { return false; } - T* buf; - size_t used; - size_t allocated; - Allocator* alloc; - }; +template<typename T> using secure_vector = std::vector<T, secure_allocator<T>>; -/* -* Change the size of the buffer -*/ template<typename T> -void MemoryRegion<T>::resize(size_t n) +std::vector<T> unlock(const secure_vector<T>& in) { - if(n <= allocated) - { - size_t zap = std::min(used, n); - clear_mem(buf + zap, allocated - zap); - used = n; - } - else - { - T* new_buf = allocate(n); - copy_mem(new_buf, buf, used); - deallocate(buf, allocated); - buf = new_buf; - allocated = used = n; - } + std::vector<T> out(in.size()); + copy_mem(&out[0], &in[0], in.size()); + return out; } -/* -* Compare this buffer with another one -*/ -template<typename T> -bool MemoryRegion<T>::operator<(const MemoryRegion<T>& other) const +template<typename T, typename Alloc> +size_t buffer_insert(std::vector<T, Alloc>& buf, + size_t buf_offset, + const T input[], + size_t input_length) { - const size_t min_size = std::min(size(), other.size()); - - // This should probably be rewritten to run in constant time - for(size_t i = 0; i != min_size; ++i) - { - if(buf[i] < other[i]) - return true; - if(buf[i] > other[i]) - return false; - } - - // First min_size bytes are equal, shorter is first - return (size() < other.size()); + const size_t to_copy = std::min(input_length, buf.size() - buf_offset); + copy_mem(&buf[buf_offset], input, to_copy); + return to_copy; } -/* -* Swap this buffer with another one -*/ -template<typename T> -void MemoryRegion<T>::swap(MemoryRegion<T>& x) +template<typename T, typename Alloc, typename Alloc2> +size_t buffer_insert(std::vector<T, Alloc>& buf, + size_t buf_offset, + const std::vector<T, Alloc2>& input) { - std::swap(buf, x.buf); - std::swap(used, x.used); - std::swap(allocated, x.allocated); - std::swap(alloc, x.alloc); + const size_t to_copy = std::min(input.size(), buf.size() - buf_offset); + copy_mem(&buf[buf_offset], &input[0], to_copy); + return to_copy; } -/** -* This class represents variable length buffers that do not -* make use of memory locking. -*/ -template<typename T> -class MemoryVector : public MemoryRegion<T> - { - public: - /** - * Copy the contents of another buffer into this buffer. - * @param in the buffer to copy the contents from - * @return reference to *this - */ - MemoryVector<T>& operator=(const MemoryRegion<T>& in) - { - if(this != &in) - { - this->resize(in.size()); - this->copy(&in[0], in.size()); - } - return (*this); - } - - /** - * Create a buffer of the specified length. - * @param n the length of the buffer to create. - */ - MemoryVector(size_t n = 0) { this->init(false, n); } - - /** - * Create a buffer with the specified contents. - * @param in the array containing the data to be initially copied - * into the newly created buffer - * @param n the size of the arry in - */ - MemoryVector(const T in[], size_t n) - { - this->init(false); - this->resize(n); - this->copy(in, n); - } - - /** - * Copy constructor. - */ - MemoryVector(const MemoryRegion<T>& in) - { - this->init(false); - this->resize(in.size()); - this->copy(&in[0], in.size()); - } - }; - -/** -* This class represents variable length buffers using the operating -* systems capability to lock memory, i.e. keeping it from being -* swapped out to disk. In this way, a security hole allowing attackers -* to find swapped out secret keys is closed. -*/ -template<typename T> -class SecureVector : public MemoryRegion<T> - { - public: - /** - * Copy the contents of another buffer into this buffer. - * @param other the buffer to copy the contents from - * @return reference to *this - */ - SecureVector<T>& operator=(const MemoryRegion<T>& other) - { - if(this != &other) - { - this->resize(other.size()); - this->copy(&other[0], other.size()); - } - return (*this); - } - - /** - * Create a buffer of the specified length. - * @param n the length of the buffer to create. - */ - SecureVector(size_t n = 0) { this->init(true, n); } - - /** - * Create a buffer with the specified contents. - * @param in the array containing the data to be initially copied - * into the newly created buffer - * @param n the size of the array in - */ - SecureVector(const T in[], size_t n) - { - this->init(true); - this->resize(n); - this->copy(&in[0], n); - } - - /** - * Create a buffer with contents specified contents. - * @param in the buffer holding the contents that will be - * copied into the newly created buffer. - */ - SecureVector(const MemoryRegion<T>& in) - { - this->init(true); - this->resize(in.size()); - this->copy(&in[0], in.size()); - } - }; - -template<typename T> -MemoryRegion<T>& operator+=(MemoryRegion<T>& out, - const MemoryRegion<T>& in) +template<typename T, typename Alloc, typename Alloc2> +std::vector<T, Alloc>& +operator+=(std::vector<T, Alloc>& out, + const std::vector<T, Alloc2>& in) { const size_t copy_offset = out.size(); out.resize(out.size() + in.size()); @@ -378,17 +130,16 @@ MemoryRegion<T>& operator+=(MemoryRegion<T>& out, return out; } -template<typename T> -MemoryRegion<T>& operator+=(MemoryRegion<T>& out, - T in) +template<typename T, typename Alloc> +std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out, T in) { out.push_back(in); return out; } -template<typename T, typename L> -MemoryRegion<T>& operator+=(MemoryRegion<T>& out, - const std::pair<const T*, L>& in) +template<typename T, typename Alloc, typename L> +std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out, + const std::pair<const T*, L>& in) { const size_t copy_offset = out.size(); out.resize(out.size() + in.second); @@ -396,9 +147,9 @@ MemoryRegion<T>& operator+=(MemoryRegion<T>& out, return out; } -template<typename T, typename L> -MemoryRegion<T>& operator+=(MemoryRegion<T>& out, - const std::pair<T*, L>& in) +template<typename T, typename Alloc, typename L> +std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out, + const std::pair<T*, L>& in) { const size_t copy_offset = out.size(); out.resize(out.size() + in.second); @@ -410,22 +161,12 @@ MemoryRegion<T>& operator+=(MemoryRegion<T>& out, * Zeroise the values; length remains unchanged * @param vec the vector to zeroise */ -template<typename T> -void zeroise(MemoryRegion<T>& vec) +template<typename T, typename Alloc> +void zeroise(std::vector<T, Alloc>& vec) { clear_mem(&vec[0], vec.size()); } } -namespace std { - -template<typename T> -inline void swap(Botan::MemoryRegion<T>& x, Botan::MemoryRegion<T>& y) - { - x.swap(y); - } - -} - #endif diff --git a/src/alloc/system_alloc/defalloc.cpp b/src/alloc/system_alloc/defalloc.cpp deleted file mode 100644 index 8e178bb14..000000000 --- a/src/alloc/system_alloc/defalloc.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* -* Basic Allocators -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/internal/defalloc.h> -#include <botan/internal/mlock.h> -#include <botan/libstate.h> -#include <cstdlib> -#include <cstring> - -namespace Botan { - -namespace { - -/* -* Perform Memory Allocation -*/ -void* do_malloc(size_t n, bool do_lock) - { - void* ptr = std::malloc(n); - - if(!ptr) - return 0; - - if(do_lock) - lock_mem(ptr, n); - - std::memset(ptr, 0, n); - return ptr; - } - -/* -* Perform Memory Deallocation -*/ -void do_free(void* ptr, size_t n, bool do_lock) - { - if(!ptr) - return; - - std::memset(ptr, 0, n); - if(do_lock) - unlock_mem(ptr, n); - - std::free(ptr); - } - -} - -/* -* Malloc_Allocator's Allocation -*/ -void* Malloc_Allocator::allocate(size_t n) - { - void* ptr = do_malloc(n, false); - if(!ptr) - throw Memory_Exhaustion(); - return ptr; - } - -/* -* Malloc_Allocator's Deallocation -*/ -void Malloc_Allocator::deallocate(void* ptr, size_t n) - { - do_free(ptr, n, false); - } - -/* -* Locking_Allocator's Allocation -*/ -void* Locking_Allocator::alloc_block(size_t n) - { - return do_malloc(n, true); - } - -/* -* Locking_Allocator's Deallocation -*/ -void Locking_Allocator::dealloc_block(void* ptr, size_t n) - { - do_free(ptr, n, true); - } - -/* -* Get an allocator -*/ -Allocator* Allocator::get(bool locking) - { - std::string type = ""; - if(!locking) - type = "malloc"; - - Allocator* alloc = global_state().get_allocator(type); - if(alloc) - return alloc; - - throw Internal_Error("Couldn't find an allocator to use in get_allocator"); - } - -} diff --git a/src/alloc/system_alloc/defalloc.h b/src/alloc/system_alloc/defalloc.h deleted file mode 100644 index 6fba0e511..000000000 --- a/src/alloc/system_alloc/defalloc.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -* Basic Allocators -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_BASIC_ALLOC_H__ -#define BOTAN_BASIC_ALLOC_H__ - -#include <botan/internal/mem_pool.h> - -namespace Botan { - -/** -* Allocator using malloc -*/ -class Malloc_Allocator : public Allocator - { - public: - void* allocate(size_t); - void deallocate(void*, size_t); - - std::string type() const { return "malloc"; } - }; - -/** -* Allocator using malloc plus locking -*/ -class Locking_Allocator : public Pooling_Allocator - { - public: - /** - * @param mutex used for internal locking - */ - Locking_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {} - - std::string type() const { return "locking"; } - private: - void* alloc_block(size_t); - void dealloc_block(void*, size_t); - }; - -} - -#endif diff --git a/src/alloc/system_alloc/info.txt b/src/alloc/system_alloc/info.txt deleted file mode 100644 index 87de0cb67..000000000 --- a/src/alloc/system_alloc/info.txt +++ /dev/null @@ -1,13 +0,0 @@ - -<source> -defalloc.cpp -</source> - -<header:internal> -defalloc.h -</header:internal> - -<requires> -libstate -mem_pool -</requires> |