1*1a96fba6SXin Li // Copyright 2018 The Chromium OS Authors. All rights reserved. 2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be 3*1a96fba6SXin Li // found in the LICENSE file. 4*1a96fba6SXin Li 5*1a96fba6SXin Li #ifndef LIBBRILLO_BRILLO_SECURE_ALLOCATOR_H_ 6*1a96fba6SXin Li #define LIBBRILLO_BRILLO_SECURE_ALLOCATOR_H_ 7*1a96fba6SXin Li 8*1a96fba6SXin Li #include <errno.h> 9*1a96fba6SXin Li #include <sys/mman.h> 10*1a96fba6SXin Li #include <unistd.h> 11*1a96fba6SXin Li 12*1a96fba6SXin Li #include <limits> 13*1a96fba6SXin Li #include <memory> 14*1a96fba6SXin Li 15*1a96fba6SXin Li #include <base/callback_helpers.h> 16*1a96fba6SXin Li #include <base/logging.h> 17*1a96fba6SXin Li #include <brillo/brillo_export.h> 18*1a96fba6SXin Li 19*1a96fba6SXin Li namespace brillo { 20*1a96fba6SXin Li // SecureAllocator is a stateless derivation of std::allocator that clears 21*1a96fba6SXin Li // the contents of the object on deallocation. Additionally, to prevent the 22*1a96fba6SXin Li // memory from being leaked, we use the following defensive mechanisms: 23*1a96fba6SXin Li // 24*1a96fba6SXin Li // 1. Use page-aligned memory so that it can be locked (therefore, use mmap() 25*1a96fba6SXin Li // instead of malloc()). Note that mlock()s are not inherited over fork(), 26*1a96fba6SXin Li // 27*1a96fba6SXin Li // 2. Always allocate memory in multiples of pages: this adds a memory overhead 28*1a96fba6SXin Li // of ~1 page for each object. Moreover, the extra memory is not available 29*1a96fba6SXin Li // for the allocated object to expand into: the container expects that the 30*1a96fba6SXin Li // memory allocated to it matches the size set in reserve(). 31*1a96fba6SXin Li // TODO(sarthakkukreti): Figure out if it is possible to propagate the real 32*1a96fba6SXin Li // capacity to the container without an intrusive change to the STL. 33*1a96fba6SXin Li // [Example: allow __recommend() override in allocators for containers.] 34*1a96fba6SXin Li // 35*1a96fba6SXin Li // 3. Mark the memory segments as undumpable, unmergeable. 36*1a96fba6SXin Li // 37*1a96fba6SXin Li // 4. Use MADV_WIPEONFORK: 38*1a96fba6SXin Li // this results in a new anonymous vma instead of copying over the contents 39*1a96fba6SXin Li // of the secure object after a fork(). By default [MADV_DOFORK], the vma is 40*1a96fba6SXin Li // marked as copy-on-write, and the first process which writes to the secure 41*1a96fba6SXin Li // object after fork get a new copy. This may break the security guarantees 42*1a96fba6SXin Li // setup above. Another alternative is to use MADV_DONTFORK which results in 43*1a96fba6SXin Li // the memory mapping not getting copied over to child process at all: this 44*1a96fba6SXin Li // may result in cases where if the child process gets segmentation faults 45*1a96fba6SXin Li // on attempts to access virtual addresses in the secure object's address 46*1a96fba6SXin Li // range, 47*1a96fba6SXin Li // 48*1a96fba6SXin Li // With MADV_WIPEONFORK, the child processes can access the secure object 49*1a96fba6SXin Li // memory safely, but the contents of the secure object appear as zero to 50*1a96fba6SXin Li // the child process. Note that threads share the virtual address space and 51*1a96fba6SXin Li // secure objects would be transparent across threads. 52*1a96fba6SXin Li // TODO(sarthakkukreti): Figure out patterns to pass secure data over fork(). 53*1a96fba6SXin Li template <typename T> 54*1a96fba6SXin Li class BRILLO_PRIVATE SecureAllocator : public std::allocator<T> { 55*1a96fba6SXin Li public: 56*1a96fba6SXin Li using typename std::allocator<T>::size_type; 57*1a96fba6SXin Li using typename std::allocator<T>::value_type; 58*1a96fba6SXin Li 59*1a96fba6SXin Li // Constructors that wrap over std::allocator. 60*1a96fba6SXin Li // Make sure that the allocator's static members are only allocated once. SecureAllocator()61*1a96fba6SXin Li SecureAllocator() noexcept : std::allocator<T>() {} SecureAllocator(const SecureAllocator & other)62*1a96fba6SXin Li SecureAllocator(const SecureAllocator& other) noexcept 63*1a96fba6SXin Li : std::allocator<T>(other) {} 64*1a96fba6SXin Li 65*1a96fba6SXin Li template <class U> SecureAllocator(const SecureAllocator<U> & other)66*1a96fba6SXin Li SecureAllocator(const SecureAllocator<U>& other) noexcept 67*1a96fba6SXin Li : std::allocator<T>(other) {} 68*1a96fba6SXin Li 69*1a96fba6SXin Li template <typename U> struct rebind { 70*1a96fba6SXin Li typedef SecureAllocator<U> other; 71*1a96fba6SXin Li }; 72*1a96fba6SXin Li 73*1a96fba6SXin Li // Return cached max_size. Deprecated in C++17, removed in C++20. max_size()74*1a96fba6SXin Li size_type max_size() const { return max_size_; } 75*1a96fba6SXin Li 76*1a96fba6SXin Li // Allocation: allocate ceil(size/pagesize) for holding the data. 77*1a96fba6SXin Li value_type* allocate(size_type n, value_type* hint = nullptr) { 78*1a96fba6SXin Li value_type* buffer = nullptr; 79*1a96fba6SXin Li // Check if n can be theoretically allocated. 80*1a96fba6SXin Li CHECK_LT(n, max_size()); 81*1a96fba6SXin Li 82*1a96fba6SXin Li // std::allocator is expected to throw a std::bad_alloc on failing to 83*1a96fba6SXin Li // allocate the memory correctly. Instead of returning a nullptr, which 84*1a96fba6SXin Li // confuses the standard template library, use CHECK(false) to crash on 85*1a96fba6SXin Li // the failure path. 86*1a96fba6SXin Li base::ScopedClosureRunner fail_on_allocation_error(base::Bind([]() { 87*1a96fba6SXin Li PLOG(ERROR) << "Failed to allocate secure memory"; 88*1a96fba6SXin Li CHECK(false); 89*1a96fba6SXin Li })); 90*1a96fba6SXin Li 91*1a96fba6SXin Li // Check if n = 0: there's nothing to allocate; 92*1a96fba6SXin Li if (n == 0) 93*1a96fba6SXin Li return nullptr; 94*1a96fba6SXin Li 95*1a96fba6SXin Li // Calculate the page-aligned buffer size. 96*1a96fba6SXin Li size_type buffer_size = CalculatePageAlignedBufferSize(n); 97*1a96fba6SXin Li 98*1a96fba6SXin Li // Memory locking granularity is per-page: mmap ceil(size/page size) pages. 99*1a96fba6SXin Li buffer = reinterpret_cast<value_type*>( 100*1a96fba6SXin Li mmap(nullptr, buffer_size, PROT_READ | PROT_WRITE, 101*1a96fba6SXin Li MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); 102*1a96fba6SXin Li if (buffer == MAP_FAILED) 103*1a96fba6SXin Li return nullptr; 104*1a96fba6SXin Li 105*1a96fba6SXin Li // Lock buffer into physical memory. 106*1a96fba6SXin Li if (mlock(buffer, buffer_size)) { 107*1a96fba6SXin Li CHECK_NE(errno, ENOMEM) << "It is likely that SecureAllocator have " 108*1a96fba6SXin Li "exceeded the RLIMIT_MEMLOCK limit"; 109*1a96fba6SXin Li return nullptr; 110*1a96fba6SXin Li } 111*1a96fba6SXin Li 112*1a96fba6SXin Li // Mark memory as non dumpable in a core dump. 113*1a96fba6SXin Li if (madvise(buffer, buffer_size, MADV_DONTDUMP)) 114*1a96fba6SXin Li return nullptr; 115*1a96fba6SXin Li 116*1a96fba6SXin Li // Mark memory as non mergeable with another page, even if the contents 117*1a96fba6SXin Li // are the same. 118*1a96fba6SXin Li if (madvise(buffer, buffer_size, MADV_UNMERGEABLE)) { 119*1a96fba6SXin Li // MADV_UNMERGEABLE is only available if the kernel has been configured 120*1a96fba6SXin Li // with CONFIG_KSM set. If the CONFIG_KSM flag has not been set, then 121*1a96fba6SXin Li // pages are not mergeable so this madvise option is not necessary. 122*1a96fba6SXin Li // 123*1a96fba6SXin Li // In the case where CONFIG_KSM is not set, EINVAL is the error set. 124*1a96fba6SXin Li // Since this error value is expected in some cases, we don't return a 125*1a96fba6SXin Li // nullptr. 126*1a96fba6SXin Li if (errno != EINVAL) 127*1a96fba6SXin Li return nullptr; 128*1a96fba6SXin Li } 129*1a96fba6SXin Li 130*1a96fba6SXin Li // Make this mapping available to child processes but don't copy data from 131*1a96fba6SXin Li // the secure object's pages during fork. With MADV_DONTFORK, the 132*1a96fba6SXin Li // vma is not mapped in the child process which leads to segmentation 133*1a96fba6SXin Li // faults if the child process tries to access this address. For example, 134*1a96fba6SXin Li // if the parent process creates a SecureObject, forks() and the child 135*1a96fba6SXin Li // process tries to call the destructor at the virtual address. 136*1a96fba6SXin Li if (madvise(buffer, buffer_size, MADV_WIPEONFORK)) 137*1a96fba6SXin Li return nullptr; 138*1a96fba6SXin Li 139*1a96fba6SXin Li ignore_result(fail_on_allocation_error.Release()); 140*1a96fba6SXin Li 141*1a96fba6SXin Li // Allocation was successful. 142*1a96fba6SXin Li return buffer; 143*1a96fba6SXin Li } 144*1a96fba6SXin Li 145*1a96fba6SXin Li // Destroy object before deallocation. Deprecated in C++17, removed in C++20. 146*1a96fba6SXin Li // After destroying the object, clear the contents of where the object was 147*1a96fba6SXin Li // stored. 148*1a96fba6SXin Li template <class U> destroy(U * p)149*1a96fba6SXin Li void destroy(U* p) { 150*1a96fba6SXin Li // Return if the pointer is invalid. 151*1a96fba6SXin Li if (!p) 152*1a96fba6SXin Li return; 153*1a96fba6SXin Li std::allocator<U>::destroy(p); 154*1a96fba6SXin Li clear_contents(p, sizeof(U)); 155*1a96fba6SXin Li } 156*1a96fba6SXin Li deallocate(value_type * p,size_type n)157*1a96fba6SXin Li virtual void deallocate(value_type* p, size_type n) { 158*1a96fba6SXin Li // Check if n can be theoretically deallocated. 159*1a96fba6SXin Li CHECK_LT(n, max_size()); 160*1a96fba6SXin Li 161*1a96fba6SXin Li // Check if n = 0 or p is a nullptr: there's nothing to deallocate; 162*1a96fba6SXin Li if (n == 0 || !p) 163*1a96fba6SXin Li return; 164*1a96fba6SXin Li 165*1a96fba6SXin Li // Calculate the page-aligned buffer size. 166*1a96fba6SXin Li size_type buffer_size = CalculatePageAlignedBufferSize(n); 167*1a96fba6SXin Li 168*1a96fba6SXin Li clear_contents(p, buffer_size); 169*1a96fba6SXin Li munlock(p, buffer_size); 170*1a96fba6SXin Li munmap(p, buffer_size); 171*1a96fba6SXin Li } 172*1a96fba6SXin Li 173*1a96fba6SXin Li protected: 174*1a96fba6SXin Li // Force memset to not be optimized out. 175*1a96fba6SXin Li // Original source commit: 31b02653c2560f8331934e879263beda44c6cc76 176*1a96fba6SXin Li // Repo: https://android.googlesource.com/platform/external/minijail 177*1a96fba6SXin Li #if defined(__clang__) 178*1a96fba6SXin Li #define __attribute_no_opt __attribute__((optnone)) 179*1a96fba6SXin Li #else 180*1a96fba6SXin Li #define __attribute_no_opt __attribute__((__optimize__(0))) 181*1a96fba6SXin Li #endif 182*1a96fba6SXin Li 183*1a96fba6SXin Li // Zero-out all bytes in the allocated buffer. clear_contents(value_type * v,size_type n)184*1a96fba6SXin Li virtual void __attribute_no_opt clear_contents(value_type* v, size_type n) { 185*1a96fba6SXin Li if (!v) 186*1a96fba6SXin Li return; 187*1a96fba6SXin Li memset(v, 0, n); 188*1a96fba6SXin Li } 189*1a96fba6SXin Li 190*1a96fba6SXin Li #undef __attribute_no_opt 191*1a96fba6SXin Li 192*1a96fba6SXin Li private: 193*1a96fba6SXin Li // Calculate the page-aligned buffer size. CalculatePageAlignedBufferSize(size_type n)194*1a96fba6SXin Li size_t CalculatePageAlignedBufferSize(size_type n) { 195*1a96fba6SXin Li size_type real_size = n * sizeof(value_type); 196*1a96fba6SXin Li size_type page_aligned_remainder = real_size % page_size_; 197*1a96fba6SXin Li size_type padding = 198*1a96fba6SXin Li page_aligned_remainder != 0 ? page_size_ - page_aligned_remainder : 0; 199*1a96fba6SXin Li return real_size + padding; 200*1a96fba6SXin Li } 201*1a96fba6SXin Li CalculatePageSize()202*1a96fba6SXin Li static size_t CalculatePageSize() { 203*1a96fba6SXin Li long ret = sysconf(_SC_PAGESIZE); // NOLINT [runtime/int] 204*1a96fba6SXin Li 205*1a96fba6SXin Li // Initialize page size. 206*1a96fba6SXin Li CHECK_GT(ret, 0L); 207*1a96fba6SXin Li return ret; 208*1a96fba6SXin Li } 209*1a96fba6SXin Li 210*1a96fba6SXin Li // Since the allocator reuses page size and max size consistently, 211*1a96fba6SXin Li // cache these values initially and reuse. GetMaxSizeForType(size_t page_size)212*1a96fba6SXin Li static size_t GetMaxSizeForType(size_t page_size) { 213*1a96fba6SXin Li // Initialize max size that can be theoretically allocated. 214*1a96fba6SXin Li // Calculate the max size that is page-aligned. 215*1a96fba6SXin Li size_t max_theoretical_size = std::numeric_limits<size_type>::max(); 216*1a96fba6SXin Li size_t max_page_aligned_size = 217*1a96fba6SXin Li max_theoretical_size - (max_theoretical_size % page_size); 218*1a96fba6SXin Li 219*1a96fba6SXin Li return max_page_aligned_size / sizeof(value_type); 220*1a96fba6SXin Li } 221*1a96fba6SXin Li 222*1a96fba6SXin Li // Page size on system. 223*1a96fba6SXin Li static const size_type page_size_; 224*1a96fba6SXin Li // Max theoretical count for type on system. 225*1a96fba6SXin Li static const size_type max_size_; 226*1a96fba6SXin Li }; 227*1a96fba6SXin Li 228*1a96fba6SXin Li // Inline definitions are only allowed for static const members with integral 229*1a96fba6SXin Li // constexpr initializers, define static members of SecureAllocator types here. 230*1a96fba6SXin Li template <typename T> 231*1a96fba6SXin Li const typename SecureAllocator<T>::size_type SecureAllocator<T>::page_size_ = 232*1a96fba6SXin Li SecureAllocator<T>::CalculatePageSize(); 233*1a96fba6SXin Li 234*1a96fba6SXin Li template <typename T> 235*1a96fba6SXin Li const typename SecureAllocator<T>::size_type SecureAllocator<T>::max_size_ = 236*1a96fba6SXin Li SecureAllocator<T>::GetMaxSizeForType(SecureAllocator<T>::page_size_); 237*1a96fba6SXin Li 238*1a96fba6SXin Li } // namespace brillo 239*1a96fba6SXin Li 240*1a96fba6SXin Li #endif // LIBBRILLO_BRILLO_SECURE_ALLOCATOR_H_ 241