| 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 |