blob: 8f08f1198f15ae040ae6a9f2e77cdc6aacc9cb2f [file] [log] [blame]
[email protected]b5bf9a132013-01-15 20:16:331// 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
[email protected]1b556f82013-01-31 02:23:435#include <fcntl.h>
[email protected]b5bf9a132013-01-15 20:16:336#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
[email protected]1b556f82013-01-31 02:23:439#include <sys/stat.h>
10#include <sys/types.h>
[email protected]b5bf9a132013-01-15 20:16:3311
12#include <algorithm>
13#include <limits>
14
[email protected]1b556f82013-01-31 02:23:4315#include "base/file_util.h"
[email protected]b5bf9a132013-01-15 20:16:3316#include "base/logging.h"
17#include "base/memory/scoped_ptr.h"
[email protected]547683f2013-02-04 23:39:4818#include "build/build_config.h"
[email protected]b5bf9a132013-01-15 20:16:3319#include "testing/gtest/include/gtest/gtest.h"
20
[email protected]547683f2013-02-04 23:39:4821#if defined(OS_POSIX)
22#include <sys/mman.h>
23#include <unistd.h>
24#endif
25
[email protected]b5bf9a132013-01-15 20:16:3326using std::nothrow;
[email protected]9c4729b2013-01-26 04:41:1527using std::numeric_limits;
[email protected]b5bf9a132013-01-15 20:16:3328
29namespace {
30
[email protected]fe394f32013-02-06 03:23:4931// This function acts as a compiler optimization barrier. We use it to
32// prevent the compiler from making an expression a compile-time constant.
33// We also use it so that the compiler doesn't discard certain return values
34// as something we don't need (see the comment with calloc below).
35template <typename Type>
36Type HideValueFromCompiler(volatile Type value) {
[email protected]1cdfdb72013-04-04 12:02:3537#if defined(__GNUC__)
38 // In a GCC compatible compiler (GCC or Clang), make this compiler barrier
39 // more robust than merely using "volatile".
40 __asm__ volatile ("" : "+r" (value));
41#endif // __GNUC__
[email protected]fe394f32013-02-06 03:23:4942 return value;
43}
44
[email protected]d6a6cea2013-02-15 06:10:4045// - NO_TCMALLOC (should be defined if we compile with linux_use_tcmalloc=0)
[email protected]b5bf9a132013-01-15 20:16:3346// - ADDRESS_SANITIZER because it has its own memory allocator
[email protected]d6a6cea2013-02-15 06:10:4047// - IOS does not use tcmalloc
[email protected]b5bf9a132013-01-15 20:16:3348// - OS_MACOSX does not use tcmalloc
49#if !defined(NO_TCMALLOC) && !defined(ADDRESS_SANITIZER) && \
50 !defined(OS_IOS) && !defined(OS_MACOSX)
[email protected]d6a6cea2013-02-15 06:10:4051 #define TCMALLOC_TEST(function) function
[email protected]b5bf9a132013-01-15 20:16:3352#else
[email protected]d6a6cea2013-02-15 06:10:4053 #define TCMALLOC_TEST(function) DISABLED_##function
[email protected]b5bf9a132013-01-15 20:16:3354#endif
55
56// TODO(jln): switch to std::numeric_limits<int>::max() when we switch to
57// C++11.
58const size_t kTooBigAllocSize = INT_MAX;
59
60// Detect runtime TCMalloc bypasses.
61bool IsTcMallocBypassed() {
62#if defined(OS_LINUX) || defined(OS_CHROMEOS)
63 // This should detect a TCMalloc bypass from Valgrind.
64 char* g_slice = getenv("G_SLICE");
65 if (g_slice && !strcmp(g_slice, "always-malloc"))
66 return true;
67#endif
68 return false;
69}
70
[email protected]d6a6cea2013-02-15 06:10:4071bool CallocDiesOnOOM() {
72// The wrapper function in base/process_util_linux.cc that is used when we
73// compile without TCMalloc will just die on OOM instead of returning NULL.
[email protected]60840782013-03-25 18:04:1574// This function is explicitly disabled if we compile with AddressSanitizer,
75// MemorySanitizer or ThreadSanitizer.
76#if defined(OS_LINUX) && defined(NO_TCMALLOC) && \
77 (!defined(ADDRESS_SANITIZER) && \
78 !defined(MEMORY_SANITIZER) && \
79 !defined(THREAD_SANITIZER))
[email protected]d6a6cea2013-02-15 06:10:4080 return true;
81#else
82 return false;
83#endif
84}
85
[email protected]b5bf9a132013-01-15 20:16:3386// Fake test that allow to know the state of TCMalloc by looking at bots.
[email protected]d6a6cea2013-02-15 06:10:4087TEST(SecurityTest, TCMALLOC_TEST(IsTCMallocDynamicallyBypassed)) {
[email protected]b5bf9a132013-01-15 20:16:3388 printf("Malloc is dynamically bypassed: %s\n",
89 IsTcMallocBypassed() ? "yes." : "no.");
90}
91
[email protected]d6a6cea2013-02-15 06:10:4092// The MemoryAllocationRestrictions* tests test that we can not allocate a
93// memory range that cannot be indexed via an int. This is used to mitigate
94// vulnerabilities in libraries that use int instead of size_t. See
95// crbug.com/169327.
96
97TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsMalloc)) {
[email protected]b5bf9a132013-01-15 20:16:3398 if (!IsTcMallocBypassed()) {
[email protected]fe394f32013-02-06 03:23:4999 scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
100 HideValueFromCompiler(malloc(kTooBigAllocSize))));
101 ASSERT_TRUE(!ptr);
[email protected]b5bf9a132013-01-15 20:16:33102 }
103}
104
[email protected]d6a6cea2013-02-15 06:10:40105TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsCalloc)) {
[email protected]b5bf9a132013-01-15 20:16:33106 if (!IsTcMallocBypassed()) {
[email protected]fe394f32013-02-06 03:23:49107 scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
108 HideValueFromCompiler(calloc(kTooBigAllocSize, 1))));
109 ASSERT_TRUE(!ptr);
[email protected]b5bf9a132013-01-15 20:16:33110 }
111}
112
[email protected]d6a6cea2013-02-15 06:10:40113TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsRealloc)) {
[email protected]b5bf9a132013-01-15 20:16:33114 if (!IsTcMallocBypassed()) {
115 char* orig_ptr = static_cast<char*>(malloc(1));
[email protected]fe394f32013-02-06 03:23:49116 ASSERT_TRUE(orig_ptr);
117 scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
118 HideValueFromCompiler(realloc(orig_ptr, kTooBigAllocSize))));
119 ASSERT_TRUE(!ptr);
[email protected]b5bf9a132013-01-15 20:16:33120 // If realloc() did not succeed, we need to free orig_ptr.
121 free(orig_ptr);
122 }
123}
124
125typedef struct {
126 char large_array[kTooBigAllocSize];
127} VeryLargeStruct;
128
[email protected]d6a6cea2013-02-15 06:10:40129TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNew)) {
[email protected]b5bf9a132013-01-15 20:16:33130 if (!IsTcMallocBypassed()) {
[email protected]fe394f32013-02-06 03:23:49131 scoped_ptr<VeryLargeStruct> ptr(
132 HideValueFromCompiler(new (nothrow) VeryLargeStruct));
133 ASSERT_TRUE(!ptr);
[email protected]b5bf9a132013-01-15 20:16:33134 }
135}
136
[email protected]d6a6cea2013-02-15 06:10:40137TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNewArray)) {
[email protected]b5bf9a132013-01-15 20:16:33138 if (!IsTcMallocBypassed()) {
[email protected]fe394f32013-02-06 03:23:49139 scoped_ptr<char[]> ptr(
140 HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize]));
141 ASSERT_TRUE(!ptr);
[email protected]b5bf9a132013-01-15 20:16:33142 }
143}
144
[email protected]9c4729b2013-01-26 04:41:15145// The tests bellow check for overflows in new[] and calloc().
146
[email protected]47db5882013-04-03 10:40:19147#if defined(OS_IOS) || defined(OS_WIN)
148 #define DISABLE_ON_IOS_AND_WIN(function) DISABLED_##function
[email protected]9c4729b2013-01-26 04:41:15149#else
[email protected]47db5882013-04-03 10:40:19150 #define DISABLE_ON_IOS_AND_WIN(function) function
[email protected]9c4729b2013-01-26 04:41:15151#endif
152
153#if defined(ADDRESS_SANITIZER)
154 #define DISABLE_ON_ASAN(function) DISABLED_##function
155#else
156 #define DISABLE_ON_ASAN(function) function
157#endif
158
159// There are platforms where these tests are known to fail. We would like to
160// be able to easily check the status on the bots, but marking tests as
161// FAILS_ is too clunky.
162void OverflowTestsSoftExpectTrue(bool overflow_detected) {
163 if (!overflow_detected) {
164#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX)
165 // Sadly, on Linux, Android, and OSX we don't have a good story yet. Don't
166 // fail the test, but report.
167 printf("Platform has overflow: %s\n",
168 !overflow_detected ? "yes." : "no.");
169#else
170 // Otherwise, fail the test. (Note: EXPECT are ok in subfunctions, ASSERT
171 // aren't).
172 EXPECT_TRUE(overflow_detected);
173#endif
174 }
175}
176
[email protected]9c4729b2013-01-26 04:41:15177// Test array[TooBig][X] and array[X][TooBig] allocations for int overflows.
178// IOS doesn't honor nothrow, so disable the test there.
[email protected]1cdfdb72013-04-04 12:02:35179// Crashes on Windows Dbg builds, disable there as well.
[email protected]47db5882013-04-03 10:40:19180TEST(SecurityTest, DISABLE_ON_IOS_AND_WIN(NewOverflow)) {
[email protected]9c4729b2013-01-26 04:41:15181 const size_t kArraySize = 4096;
182 // We want something "dynamic" here, so that the compiler doesn't
183 // immediately reject crazy arrays.
184 const size_t kDynamicArraySize = HideValueFromCompiler(kArraySize);
185 // numeric_limits are still not constexpr until we switch to C++11, so we
186 // use an ugly cast.
187 const size_t kMaxSizeT = ~static_cast<size_t>(0);
188 ASSERT_EQ(numeric_limits<size_t>::max(), kMaxSizeT);
189 const size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
190 const size_t kDynamicArraySize2 = HideValueFromCompiler(kArraySize2);
191 {
192 scoped_ptr<char[][kArraySize]> array_pointer(new (nothrow)
193 char[kDynamicArraySize2][kArraySize]);
[email protected]fe394f32013-02-06 03:23:49194 OverflowTestsSoftExpectTrue(!array_pointer);
[email protected]9c4729b2013-01-26 04:41:15195 }
[email protected]1cdfdb72013-04-04 12:02:35196 // On windows, the compiler prevents static array sizes of more than
197 // 0x7fffffff (error C2148).
198#if !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS)
[email protected]9c4729b2013-01-26 04:41:15199 {
200 scoped_ptr<char[][kArraySize2]> array_pointer(new (nothrow)
201 char[kDynamicArraySize][kArraySize2]);
[email protected]fe394f32013-02-06 03:23:49202 OverflowTestsSoftExpectTrue(!array_pointer);
[email protected]9c4729b2013-01-26 04:41:15203 }
[email protected]1cdfdb72013-04-04 12:02:35204#endif // !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS)
[email protected]9c4729b2013-01-26 04:41:15205}
206
[email protected]d6a6cea2013-02-15 06:10:40207// Call calloc(), eventually free the memory and return whether or not
208// calloc() did succeed.
209bool CallocReturnsNull(size_t nmemb, size_t size) {
210 scoped_ptr<char, base::FreeDeleter> array_pointer(
211 static_cast<char*>(calloc(nmemb, size)));
212 // We need the call to HideValueFromCompiler(): we have seen LLVM
213 // optimize away the call to calloc() entirely and assume
214 // the pointer to not be NULL.
215 return HideValueFromCompiler(array_pointer.get()) == NULL;
216}
217
[email protected]9c4729b2013-01-26 04:41:15218// Test if calloc() can overflow. Disable on ASAN for now since the
[email protected]d6a6cea2013-02-15 06:10:40219// overflow seems present there (crbug.com/175554).
[email protected]9c4729b2013-01-26 04:41:15220TEST(SecurityTest, DISABLE_ON_ASAN(CallocOverflow)) {
221 const size_t kArraySize = 4096;
222 const size_t kMaxSizeT = numeric_limits<size_t>::max();
223 const size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
[email protected]d6a6cea2013-02-15 06:10:40224 if (!CallocDiesOnOOM()) {
225 EXPECT_TRUE(CallocReturnsNull(kArraySize, kArraySize2));
226 EXPECT_TRUE(CallocReturnsNull(kArraySize2, kArraySize));
227 } else {
228 // It's also ok for calloc to just terminate the process.
229#if defined(GTEST_HAS_DEATH_TEST)
230 EXPECT_DEATH(CallocReturnsNull(kArraySize, kArraySize2), "");
231 EXPECT_DEATH(CallocReturnsNull(kArraySize2, kArraySize), "");
232#endif // GTEST_HAS_DEATH_TEST
[email protected]9c4729b2013-01-26 04:41:15233 }
234}
235
[email protected]1b556f82013-01-31 02:23:43236#if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(__x86_64__)
237// Useful for debugging.
238void PrintProcSelfMaps() {
239 int fd = open("/proc/self/maps", O_RDONLY);
240 file_util::ScopedFD fd_closer(&fd);
241 ASSERT_GE(fd, 0);
242 char buffer[1<<13];
243 int ret;
244 ret = read(fd, buffer, sizeof(buffer) - 1);
245 ASSERT_GT(ret, 0);
246 buffer[ret - 1] = 0;
247 fprintf(stdout, "%s\n", buffer);
248}
249
[email protected]547683f2013-02-04 23:39:48250// Check if ptr1 and ptr2 are separated by less than size chars.
251bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) {
252 ptrdiff_t ptr_diff = reinterpret_cast<char*>(std::max(ptr1, ptr2)) -
253 reinterpret_cast<char*>(std::min(ptr1, ptr2));
254 return static_cast<size_t>(ptr_diff) <= size;
255}
256
[email protected]1b556f82013-01-31 02:23:43257// Check if TCMalloc uses an underlying random memory allocator.
[email protected]d6a6cea2013-02-15 06:10:40258TEST(SecurityTest, TCMALLOC_TEST(RandomMemoryAllocations)) {
[email protected]1b556f82013-01-31 02:23:43259 if (IsTcMallocBypassed())
260 return;
[email protected]547683f2013-02-04 23:39:48261 size_t kPageSize = 4096; // We support x86_64 only.
262 // Check that malloc() returns an address that is neither the kernel's
263 // un-hinted mmap area, nor the current brk() area. The first malloc() may
264 // not be at a random address because TCMalloc will first exhaust any memory
265 // that it has allocated early on, before starting the sophisticated
266 // allocators.
267 void* default_mmap_heap_address =
268 mmap(0, kPageSize, PROT_READ|PROT_WRITE,
269 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
270 ASSERT_NE(default_mmap_heap_address,
271 static_cast<void*>(MAP_FAILED));
272 ASSERT_EQ(munmap(default_mmap_heap_address, kPageSize), 0);
273 void* brk_heap_address = sbrk(0);
274 ASSERT_NE(brk_heap_address, reinterpret_cast<void*>(-1));
275 ASSERT_TRUE(brk_heap_address != NULL);
276 // 1 MB should get us past what TCMalloc pre-allocated before initializing
277 // the sophisticated allocators.
278 size_t kAllocSize = 1<<20;
279 scoped_ptr<char, base::FreeDeleter> ptr(
280 static_cast<char*>(malloc(kAllocSize)));
281 ASSERT_TRUE(ptr != NULL);
282 // If two pointers are separated by less than 512MB, they are considered
283 // to be in the same area.
284 // Our random pointer could be anywhere within 0x3fffffffffff (46bits),
285 // and we are checking that it's not withing 1GB (30 bits) from two
286 // addresses (brk and mmap heap). We have roughly one chance out of
287 // 2^15 to flake.
288 const size_t kAreaRadius = 1<<29;
289 bool in_default_mmap_heap = ArePointersToSameArea(
290 ptr.get(), default_mmap_heap_address, kAreaRadius);
291 EXPECT_FALSE(in_default_mmap_heap);
292
293 bool in_default_brk_heap = ArePointersToSameArea(
294 ptr.get(), brk_heap_address, kAreaRadius);
295 EXPECT_FALSE(in_default_brk_heap);
296
297 // In the implementation, we always mask our random addresses with
298 // kRandomMask, so we use it as an additional detection mechanism.
299 const uintptr_t kRandomMask = 0x3fffffffffffULL;
300 bool impossible_random_address =
301 reinterpret_cast<uintptr_t>(ptr.get()) & ~kRandomMask;
302 EXPECT_FALSE(impossible_random_address);
[email protected]1b556f82013-01-31 02:23:43303}
304
305#endif // (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(__x86_64__)
306
[email protected]b5bf9a132013-01-15 20:16:33307} // namespace