OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <fcntl.h> | 5 #include <fcntl.h> |
6 #include <stdio.h> | 6 #include <stdio.h> |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 #include <string.h> | 8 #include <string.h> |
| 9 #include <sys/mman.h> |
9 #include <sys/stat.h> | 10 #include <sys/stat.h> |
10 #include <sys/types.h> | 11 #include <sys/types.h> |
| 12 #include <unistd.h> |
11 | 13 |
12 #include <algorithm> | 14 #include <algorithm> |
13 #include <limits> | 15 #include <limits> |
14 | 16 |
15 #include "base/file_util.h" | 17 #include "base/file_util.h" |
16 #include "base/logging.h" | 18 #include "base/logging.h" |
17 #include "base/memory/scoped_ptr.h" | 19 #include "base/memory/scoped_ptr.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
19 | 21 |
20 using std::nothrow; | 22 using std::nothrow; |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 file_util::ScopedFD fd_closer(&fd); | 205 file_util::ScopedFD fd_closer(&fd); |
204 ASSERT_GE(fd, 0); | 206 ASSERT_GE(fd, 0); |
205 char buffer[1<<13]; | 207 char buffer[1<<13]; |
206 int ret; | 208 int ret; |
207 ret = read(fd, buffer, sizeof(buffer) - 1); | 209 ret = read(fd, buffer, sizeof(buffer) - 1); |
208 ASSERT_GT(ret, 0); | 210 ASSERT_GT(ret, 0); |
209 buffer[ret - 1] = 0; | 211 buffer[ret - 1] = 0; |
210 fprintf(stdout, "%s\n", buffer); | 212 fprintf(stdout, "%s\n", buffer); |
211 } | 213 } |
212 | 214 |
| 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 |
213 // Check if TCMalloc uses an underlying random memory allocator. | 222 // Check if TCMalloc uses an underlying random memory allocator. |
214 TEST(SecurityTest, ALLOC_TEST(RandomMemoryAllocations)) { | 223 TEST(SecurityTest, ALLOC_TEST(RandomMemoryAllocations)) { |
215 if (IsTcMallocBypassed()) | 224 if (IsTcMallocBypassed()) |
216 return; | 225 return; |
217 // Two successsive calls to mmap() have roughly one chance out of 2^6 to | 226 size_t kPageSize = 4096; // We support x86_64 only. |
218 // have the same two high order nibbles, which is what we are looking at in | 227 // Check that malloc() returns an address that is neither the kernel's |
219 // this test. (In the implementation, we mask these two nibbles with 0x3f, | 228 // un-hinted mmap area, nor the current brk() area. The first malloc() may |
220 // hence the 6 bits). | 229 // not be at a random address because TCMalloc will first exhaust any memory |
221 // With 32 allocations, we see ~16 that end-up in different buckets (i.e. | 230 // that it has allocated early on, before starting the sophisticated |
222 // zones mapped via mmap(), so the chances of this test flaking is roughly | 231 // allocators. |
223 // 2^-(6*15). | 232 void* default_mmap_heap_address = |
224 const int kAllocNumber = 32; | 233 mmap(0, kPageSize, PROT_READ|PROT_WRITE, |
225 // Make kAllocNumber successive allocations of growing size and compare the | 234 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
226 // successive pointers to detect adjacent mappings. We grow the size because | 235 ASSERT_NE(default_mmap_heap_address, |
227 // TCMalloc can sometimes over-allocate. | 236 static_cast<void*>(MAP_FAILED)); |
228 scoped_ptr<char, base::FreeDeleter> ptr[kAllocNumber]; | 237 ASSERT_EQ(munmap(default_mmap_heap_address, kPageSize), 0); |
229 for (int i = 0; i < kAllocNumber; ++i) { | 238 void* brk_heap_address = sbrk(0); |
230 // Grow the Malloc size slightly sub-exponentially. | 239 ASSERT_NE(brk_heap_address, reinterpret_cast<void*>(-1)); |
231 const size_t kMallocSize = 1 << (12 + (i>>1)); | 240 ASSERT_TRUE(brk_heap_address != NULL); |
232 ptr[i].reset(static_cast<char*>(malloc(kMallocSize))); | 241 // 1 MB should get us past what TCMalloc pre-allocated before initializing |
233 ASSERT_TRUE(ptr[i] != NULL); | 242 // the sophisticated allocators. |
234 if (i > 0) { | 243 size_t kAllocSize = 1<<20; |
235 // Without mmap randomization, the two high order nibbles | 244 scoped_ptr<char, base::FreeDeleter> ptr( |
236 // of a 47 bits userland address address will be identical. | 245 static_cast<char*>(malloc(kAllocSize))); |
237 // We're only watching the 6 bits that we actually do touch | 246 ASSERT_TRUE(ptr != NULL); |
238 // in our implementation. | 247 // If two pointers are separated by less than 512MB, they are considered |
239 const uintptr_t kHighOrderMask = 0x3f0000000000ULL; | 248 // to be in the same area. |
240 bool pointer_have_same_high_order = | 249 // Our random pointer could be anywhere within 0x3fffffffffff (46bits), |
241 (reinterpret_cast<size_t>(ptr[i].get()) & kHighOrderMask) == | 250 // and we are checking that it's not withing 1GB (30 bits) from two |
242 (reinterpret_cast<size_t>(ptr[i - 1].get()) & kHighOrderMask); | 251 // addresses (brk and mmap heap). We have roughly one chance out of |
243 if (!pointer_have_same_high_order) { | 252 // 2^15 to flake. |
244 // PrintProcSelfMaps(); | 253 const size_t kAreaRadius = 1<<29; |
245 return; // Test passes. | 254 bool in_default_mmap_heap = ArePointersToSameArea( |
246 } | 255 ptr.get(), default_mmap_heap_address, kAreaRadius); |
247 } | 256 EXPECT_FALSE(in_default_mmap_heap); |
248 } | 257 |
249 ASSERT_TRUE(false); // NOTREACHED(); | 258 bool in_default_brk_heap = ArePointersToSameArea( |
| 259 ptr.get(), brk_heap_address, kAreaRadius); |
| 260 EXPECT_FALSE(in_default_brk_heap); |
| 261 |
| 262 // In the implementation, we always mask our random addresses with |
| 263 // kRandomMask, so we use it as an additional detection mechanism. |
| 264 const uintptr_t kRandomMask = 0x3fffffffffffULL; |
| 265 bool impossible_random_address = |
| 266 reinterpret_cast<uintptr_t>(ptr.get()) & ~kRandomMask; |
| 267 EXPECT_FALSE(impossible_random_address); |
250 } | 268 } |
251 | 269 |
252 #endif // (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(__x86_64__) | 270 #endif // (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(__x86_64__) |
253 | 271 |
254 } // namespace | 272 } // namespace |
OLD | NEW |