1 // Copyright 2014 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 5 #include "third_party/base/allocator/partition_allocator/address_space_randomization.h" 6 7 #include "third_party/base/allocator/partition_allocator/page_allocator.h" 8 #include "third_party/base/allocator/partition_allocator/spin_lock.h" 9 #include "third_party/build/build_config.h" 10 11 #if defined(OS_WIN) 12 #include <windows.h> 13 #else 14 #include <sys/time.h> 15 #include <unistd.h> 16 #endif 17 18 // VersionHelpers.h must be included after windows.h. 19 #if defined(OS_WIN) 20 #include <VersionHelpers.h> 21 #endif 22 23 namespace pdfium { 24 namespace base { 25 26 namespace { 27 28 // This is the same PRNG as used by tcmalloc for mapping address randomness; 29 // see http://burtleburtle.net/bob/rand/smallprng.html 30 struct ranctx { 31 subtle::SpinLock lock; 32 bool initialized; 33 uint32_t a; 34 uint32_t b; 35 uint32_t c; 36 uint32_t d; 37 }; 38 39 #define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) 40 ranvalInternal(ranctx * x)41uint32_t ranvalInternal(ranctx* x) { 42 uint32_t e = x->a - rot(x->b, 27); 43 x->a = x->b ^ rot(x->c, 17); 44 x->b = x->c + x->d; 45 x->c = x->d + e; 46 x->d = e + x->a; 47 return x->d; 48 } 49 50 #undef rot 51 ranval(ranctx * x)52uint32_t ranval(ranctx* x) { 53 subtle::SpinLock::Guard guard(x->lock); 54 if (UNLIKELY(!x->initialized)) { 55 x->initialized = true; 56 char c; 57 uint32_t seed = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&c)); 58 uint32_t pid; 59 uint32_t usec; 60 #if defined(OS_WIN) 61 pid = GetCurrentProcessId(); 62 SYSTEMTIME st; 63 GetSystemTime(&st); 64 usec = static_cast<uint32_t>(st.wMilliseconds * 1000); 65 #else 66 pid = static_cast<uint32_t>(getpid()); 67 struct timeval tv; 68 gettimeofday(&tv, 0); 69 usec = static_cast<uint32_t>(tv.tv_usec); 70 #endif 71 seed ^= pid; 72 seed ^= usec; 73 x->a = 0xf1ea5eed; 74 x->b = x->c = x->d = seed; 75 for (int i = 0; i < 20; ++i) { 76 (void)ranvalInternal(x); 77 } 78 } 79 uint32_t ret = ranvalInternal(x); 80 return ret; 81 } 82 83 static struct ranctx s_ranctx; 84 85 } // namespace 86 87 // Calculates a random preferred mapping address. In calculating an address, we 88 // balance good ASLR against not fragmenting the address space too badly. GetRandomPageBase()89void* GetRandomPageBase() { 90 uintptr_t random; 91 random = static_cast<uintptr_t>(ranval(&s_ranctx)); 92 #if defined(ARCH_CPU_X86_64) 93 random <<= 32UL; 94 random |= static_cast<uintptr_t>(ranval(&s_ranctx)); 95 // This address mask gives a low likelihood of address space collisions. We 96 // handle the situation gracefully if there is a collision. 97 #if defined(OS_WIN) 98 random &= 0x3ffffffffffUL; 99 // Windows >= 8.1 has the full 47 bits. Use them where available. 100 static bool windows_81 = false; 101 static bool windows_81_initialized = false; 102 if (!windows_81_initialized) { 103 windows_81 = IsWindows8Point1OrGreater(); 104 windows_81_initialized = true; 105 } 106 if (!windows_81) { 107 random += 0x10000000000UL; 108 } 109 #elif defined(MEMORY_TOOL_REPLACES_ALLOCATOR) 110 // This range is copied from the TSan source, but works for all tools. 111 random &= 0x007fffffffffUL; 112 random += 0x7e8000000000UL; 113 #else 114 // Linux and OS X support the full 47-bit user space of x64 processors. 115 random &= 0x3fffffffffffUL; 116 #endif 117 #elif defined(ARCH_CPU_ARM64) 118 // ARM64 on Linux has 39-bit user space. 119 random &= 0x3fffffffffUL; 120 random += 0x1000000000UL; 121 #else // !defined(ARCH_CPU_X86_64) && !defined(ARCH_CPU_ARM64) 122 #if defined(OS_WIN) 123 // On win32 host systems the randomization plus huge alignment causes 124 // excessive fragmentation. Plus most of these systems lack ASLR, so the 125 // randomization isn't buying anything. In that case we just skip it. 126 // TODO(jschuh): Just dump the randomization when HE-ASLR is present. 127 static BOOL isWow64 = -1; 128 if (isWow64 == -1 && !IsWow64Process(GetCurrentProcess(), &isWow64)) 129 isWow64 = FALSE; 130 if (!isWow64) 131 return nullptr; 132 #endif // defined(OS_WIN) 133 // This is a good range on Windows, Linux and Mac. 134 // Allocates in the 0.5-1.5GB region. 135 random &= 0x3fffffff; 136 random += 0x20000000; 137 #endif // defined(ARCH_CPU_X86_64) 138 random &= kPageAllocationGranularityBaseMask; 139 return reinterpret_cast<void*>(random); 140 } 141 142 } // namespace base 143 } // namespace pdfium 144