security_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // Copyright (c) 2013 The Chromium 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. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/stat.h>
  9. #include <sys/types.h>
  10. #include <algorithm>
  11. #include <limits>
  12. #include "butil/file_util.h"
  13. #include "butil/logging.h"
  14. #include "butil/memory/scoped_ptr.h"
  15. #include "butil/build_config.h"
  16. #include <gtest/gtest.h>
  17. #if defined(OS_POSIX)
  18. #include <sys/mman.h>
  19. #include <unistd.h>
  20. #endif
  21. using std::nothrow;
  22. using std::numeric_limits;
  23. namespace {
  24. // This function acts as a compiler optimization barrier. We use it to
  25. // prevent the compiler from making an expression a compile-time constant.
  26. // We also use it so that the compiler doesn't discard certain return values
  27. // as something we don't need (see the comment with calloc below).
  28. template <typename Type>
  29. Type HideValueFromCompiler(volatile Type value) {
  30. #if defined(__GNUC__)
  31. // In a GCC compatible compiler (GCC or Clang), make this compiler barrier
  32. // more robust than merely using "volatile".
  33. __asm__ volatile ("" : "+r" (value));
  34. #endif // __GNUC__
  35. return value;
  36. }
  37. // - NO_TCMALLOC (should be defined if compiled with use_allocator!="tcmalloc")
  38. // - ADDRESS_SANITIZER and SYZYASAN because they have their own memory allocator
  39. // - IOS does not use tcmalloc
  40. // - OS_MACOSX does not use tcmalloc
  41. #if !defined(NO_TCMALLOC) && !defined(ADDRESS_SANITIZER) && \
  42. !defined(OS_IOS) && !defined(OS_MACOSX) && !defined(SYZYASAN)
  43. #define TCMALLOC_TEST(function) function
  44. #else
  45. #define TCMALLOC_TEST(function) DISABLED_##function
  46. #endif
  47. // TODO(jln): switch to std::numeric_limits<int>::max() when we switch to
  48. // C++11.
  49. const size_t kTooBigAllocSize = INT_MAX;
  50. // Detect runtime TCMalloc bypasses.
  51. bool IsTcMallocBypassed() {
  52. #if defined(OS_LINUX)
  53. // This should detect a TCMalloc bypass from Valgrind.
  54. char* g_slice = getenv("G_SLICE");
  55. if (g_slice && !strcmp(g_slice, "always-malloc"))
  56. return true;
  57. #elif defined(OS_WIN)
  58. // This should detect a TCMalloc bypass from setting
  59. // the CHROME_ALLOCATOR environment variable.
  60. char* allocator = getenv("CHROME_ALLOCATOR");
  61. if (allocator && strcmp(allocator, "tcmalloc"))
  62. return true;
  63. #endif
  64. return false;
  65. }
  66. bool CallocDiesOnOOM() {
  67. // The sanitizers' calloc dies on OOM instead of returning NULL.
  68. // The wrapper function in butil/process_util_linux.cc that is used when we
  69. // compile without TCMalloc will just die on OOM instead of returning NULL.
  70. #if defined(ADDRESS_SANITIZER) || \
  71. defined(MEMORY_SANITIZER) || \
  72. defined(THREAD_SANITIZER) || \
  73. (defined(OS_LINUX) && defined(NO_TCMALLOC))
  74. return true;
  75. #else
  76. return false;
  77. #endif
  78. }
  79. // Fake test that allow to know the state of TCMalloc by looking at bots.
  80. TEST(SecurityTest, TCMALLOC_TEST(IsTCMallocDynamicallyBypassed)) {
  81. printf("Malloc is dynamically bypassed: %s\n",
  82. IsTcMallocBypassed() ? "yes." : "no.");
  83. }
  84. // The MemoryAllocationRestrictions* tests test that we can not allocate a
  85. // memory range that cannot be indexed via an int. This is used to mitigate
  86. // vulnerabilities in libraries that use int instead of size_t. See
  87. // crbug.com/169327.
  88. TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsMalloc)) {
  89. if (!IsTcMallocBypassed()) {
  90. scoped_ptr<char, butil::FreeDeleter> ptr(static_cast<char*>(
  91. HideValueFromCompiler(malloc(kTooBigAllocSize))));
  92. ASSERT_TRUE(!ptr);
  93. }
  94. }
  95. TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsCalloc)) {
  96. if (!IsTcMallocBypassed()) {
  97. scoped_ptr<char, butil::FreeDeleter> ptr(static_cast<char*>(
  98. HideValueFromCompiler(calloc(kTooBigAllocSize, 1))));
  99. ASSERT_TRUE(!ptr);
  100. }
  101. }
  102. TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsRealloc)) {
  103. if (!IsTcMallocBypassed()) {
  104. char* orig_ptr = static_cast<char*>(malloc(1));
  105. ASSERT_TRUE(orig_ptr);
  106. scoped_ptr<char, butil::FreeDeleter> ptr(static_cast<char*>(
  107. HideValueFromCompiler(realloc(orig_ptr, kTooBigAllocSize))));
  108. ASSERT_TRUE(!ptr);
  109. // If realloc() did not succeed, we need to free orig_ptr.
  110. free(orig_ptr);
  111. }
  112. }
  113. typedef struct {
  114. char large_array[kTooBigAllocSize];
  115. } VeryLargeStruct;
  116. TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNew)) {
  117. if (!IsTcMallocBypassed()) {
  118. scoped_ptr<VeryLargeStruct> ptr(
  119. HideValueFromCompiler(new (nothrow) VeryLargeStruct));
  120. ASSERT_TRUE(!ptr);
  121. }
  122. }
  123. TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNewArray)) {
  124. if (!IsTcMallocBypassed()) {
  125. scoped_ptr<char[]> ptr(
  126. HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize]));
  127. ASSERT_TRUE(!ptr);
  128. }
  129. }
  130. // The tests bellow check for overflows in new[] and calloc().
  131. #if defined(OS_IOS) || defined(OS_WIN) || defined(THREAD_SANITIZER)
  132. #define DISABLE_ON_IOS_AND_WIN_AND_TSAN(function) DISABLED_##function
  133. #else
  134. #define DISABLE_ON_IOS_AND_WIN_AND_TSAN(function) function
  135. #endif
  136. // FIXME(gejun): following logic of the case, it definitely should crash, I don't
  137. // know why it's judged as failure.
  138. #if defined(FixedNewOverflow)
  139. // There are platforms where these tests are known to fail. We would like to
  140. // be able to easily check the status on the bots, but marking tests as
  141. // FAILS_ is too clunky.
  142. void OverflowTestsSoftExpectTrue(bool overflow_detected) {
  143. if (!overflow_detected) {
  144. #if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX)
  145. // Sadly, on Linux, Android, and OSX we don't have a good story yet. Don't
  146. // fail the test, but report.
  147. printf("Platform has overflow: %s\n",
  148. !overflow_detected ? "yes." : "no.");
  149. #else
  150. // Otherwise, fail the test. (Note: EXPECT are ok in subfunctions, ASSERT
  151. // aren't).
  152. EXPECT_TRUE(overflow_detected);
  153. #endif
  154. }
  155. }
  156. // Test array[TooBig][X] and array[X][TooBig] allocations for int overflows.
  157. // IOS doesn't honor nothrow, so disable the test there.
  158. // Crashes on Windows Dbg builds, disable there as well.
  159. TEST(SecurityTest, DISABLE_ON_IOS_AND_WIN_AND_TSAN(NewOverflow)) {
  160. const size_t kArraySize = 4096;
  161. // We want something "dynamic" here, so that the compiler doesn't
  162. // immediately reject crazy arrays.
  163. const size_t kDynamicArraySize = HideValueFromCompiler(kArraySize);
  164. // numeric_limits are still not constexpr until we switch to C++11, so we
  165. // use an ugly cast.
  166. const size_t kMaxSizeT = ~static_cast<size_t>(0);
  167. ASSERT_EQ(numeric_limits<size_t>::max(), kMaxSizeT);
  168. const size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
  169. const size_t kDynamicArraySize2 = HideValueFromCompiler(kArraySize2);
  170. {
  171. scoped_ptr<char[][kArraySize]> array_pointer(new (nothrow)
  172. char[kDynamicArraySize2][kArraySize]);
  173. OverflowTestsSoftExpectTrue(!array_pointer);
  174. }
  175. // On windows, the compiler prevents static array sizes of more than
  176. // 0x7fffffff (error C2148).
  177. #if !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS)
  178. {
  179. scoped_ptr<char[][kArraySize2]> array_pointer(new (nothrow)
  180. char[kDynamicArraySize][kArraySize2]);
  181. OverflowTestsSoftExpectTrue(!array_pointer);
  182. }
  183. #endif // !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS)
  184. }
  185. #endif
  186. // Call calloc(), eventually free the memory and return whether or not
  187. // calloc() did succeed.
  188. bool CallocReturnsNull(size_t nmemb, size_t size) {
  189. scoped_ptr<char, butil::FreeDeleter> array_pointer(
  190. static_cast<char*>(calloc(nmemb, size)));
  191. // We need the call to HideValueFromCompiler(): we have seen LLVM
  192. // optimize away the call to calloc() entirely and assume
  193. // the pointer to not be NULL.
  194. return HideValueFromCompiler(array_pointer.get()) == NULL;
  195. }
  196. // Test if calloc() can overflow.
  197. TEST(SecurityTest, CallocOverflow) {
  198. const size_t kArraySize = 4096;
  199. const size_t kMaxSizeT = numeric_limits<size_t>::max();
  200. const size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
  201. if (!CallocDiesOnOOM()) {
  202. EXPECT_TRUE(CallocReturnsNull(kArraySize, kArraySize2));
  203. EXPECT_TRUE(CallocReturnsNull(kArraySize2, kArraySize));
  204. } else {
  205. // It's also ok for calloc to just terminate the process.
  206. // NOTE(gejun): butil/process/memory.cc is not linked right now,
  207. // disable following assertions on calloc
  208. //#if defined(GTEST_HAS_DEATH_TEST)
  209. // EXPECT_DEATH(CallocReturnsNull(kArraySize, kArraySize2), "");
  210. // EXPECT_DEATH(CallocReturnsNull(kArraySize2, kArraySize), "");
  211. //#endif // GTEST_HAS_DEATH_TEST
  212. }
  213. }
  214. #if defined(OS_LINUX) && defined(__x86_64__)
  215. // Check if ptr1 and ptr2 are separated by less than size chars.
  216. bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) {
  217. ptrdiff_t ptr_diff = reinterpret_cast<char*>(std::max(ptr1, ptr2)) -
  218. reinterpret_cast<char*>(std::min(ptr1, ptr2));
  219. return static_cast<size_t>(ptr_diff) <= size;
  220. }
  221. // Check if TCMalloc uses an underlying random memory allocator.
  222. TEST(SecurityTest, TCMALLOC_TEST(RandomMemoryAllocations)) {
  223. if (IsTcMallocBypassed())
  224. return;
  225. size_t kPageSize = 4096; // We support x86_64 only.
  226. // Check that malloc() returns an address that is neither the kernel's
  227. // un-hinted mmap area, nor the current brk() area. The first malloc() may
  228. // not be at a random address because TCMalloc will first exhaust any memory
  229. // that it has allocated early on, before starting the sophisticated
  230. // allocators.
  231. void* default_mmap_heap_address =
  232. mmap(0, kPageSize, PROT_READ|PROT_WRITE,
  233. MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  234. ASSERT_NE(default_mmap_heap_address,
  235. static_cast<void*>(MAP_FAILED));
  236. ASSERT_EQ(munmap(default_mmap_heap_address, kPageSize), 0);
  237. void* brk_heap_address = sbrk(0);
  238. ASSERT_NE(brk_heap_address, reinterpret_cast<void*>(-1));
  239. ASSERT_TRUE(brk_heap_address != NULL);
  240. // 1 MB should get us past what TCMalloc pre-allocated before initializing
  241. // the sophisticated allocators.
  242. size_t kAllocSize = 1<<20;
  243. scoped_ptr<char, butil::FreeDeleter> ptr(
  244. static_cast<char*>(malloc(kAllocSize)));
  245. ASSERT_TRUE(ptr != NULL);
  246. // If two pointers are separated by less than 512MB, they are considered
  247. // to be in the same area.
  248. // Our random pointer could be anywhere within 0x3fffffffffff (46bits),
  249. // and we are checking that it's not withing 1GB (30 bits) from two
  250. // addresses (brk and mmap heap). We have roughly one chance out of
  251. // 2^15 to flake.
  252. const size_t kAreaRadius = 1<<29;
  253. bool in_default_mmap_heap = ArePointersToSameArea(
  254. ptr.get(), default_mmap_heap_address, kAreaRadius);
  255. EXPECT_FALSE(in_default_mmap_heap);
  256. bool in_default_brk_heap = ArePointersToSameArea(
  257. ptr.get(), brk_heap_address, kAreaRadius);
  258. EXPECT_FALSE(in_default_brk_heap);
  259. // In the implementation, we always mask our random addresses with
  260. // kRandomMask, so we use it as an additional detection mechanism.
  261. const uintptr_t kRandomMask = 0x3fffffffffffULL;
  262. bool impossible_random_address =
  263. reinterpret_cast<uintptr_t>(ptr.get()) & ~kRandomMask;
  264. EXPECT_FALSE(impossible_random_address);
  265. }
  266. #endif // defined(OS_LINUX) && defined(__x86_64__)
  267. } // namespace