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