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 "config.h" 6 #include "wtf/AddressSpaceRandomization.h" 7 8 #include "wtf/PageAllocator.h" 9 #include "wtf/ProcessID.h" 10 #include "wtf/SpinLock.h" 11 12 namespace WTF { 13 14 namespace { 15 16 // This is the same PRNG as used by tcmalloc for mapping address randomness; 17 // see http://burtleburtle.net/bob/rand/smallprng.html 18 struct ranctx { 19 int lock; 20 bool initialized; 21 uint32_t a; 22 uint32_t b; 23 uint32_t c; 24 uint32_t d; 25 }; 26 27 #define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) 28 ranvalInternal(ranctx * x)29uint32_t ranvalInternal(ranctx* x) 30 { 31 uint32_t e = x->a - rot(x->b, 27); 32 x->a = x->b ^ rot(x->c, 17); 33 x->b = x->c + x->d; 34 x->c = x->d + e; 35 x->d = e + x->a; 36 return x->d; 37 } 38 39 #undef rot 40 ranval(ranctx * x)41uint32_t ranval(ranctx* x) 42 { 43 spinLockLock(&x->lock); 44 if (UNLIKELY(!x->initialized)) { 45 x->initialized = true; 46 char c; 47 uint32_t seed = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&c)); 48 seed ^= static_cast<uint32_t>(getCurrentProcessID()); 49 x->a = 0xf1ea5eed; 50 x->b = x->c = x->d = seed; 51 for (int i = 0; i < 20; ++i) { 52 (void) ranvalInternal(x); 53 } 54 } 55 uint32_t ret = ranvalInternal(x); 56 spinLockUnlock(&x->lock); 57 return ret; 58 } 59 60 static struct ranctx s_ranctx; 61 62 } 63 64 // Calculates a random preferred mapping address. In calculating an 65 // address, we balance good ASLR against not fragmenting the address 66 // space too badly. getRandomPageBase()67void* getRandomPageBase() 68 { 69 uintptr_t random; 70 random = static_cast<uintptr_t>(ranval(&s_ranctx)); 71 #if CPU(X86_64) 72 random <<= 32UL; 73 random |= static_cast<uintptr_t>(ranval(&s_ranctx)); 74 // This address mask gives a low liklihood of address space collisions. 75 // We handle the situation gracefully if there is a collision. 76 #if OS(WIN) 77 // 64-bit Windows has a bizarrely small 8TB user address space. 78 // Allocates in the 1-5TB region. 79 random &= 0x3ffffffffffUL; 80 random += 0x10000000000UL; 81 #else 82 // Linux and OS X support the full 47-bit user space of x64 processors. 83 random &= 0x3fffffffffffUL; 84 #endif 85 #elif CPU(ARM64) 86 // ARM64 on Linux has 39-bit user space. 87 random &= 0x3fffffffffUL; 88 random += 0x1000000000UL; 89 #else // !CPU(X86_64) && !CPU(ARM64) 90 // This is a good range on Windows, Linux and Mac. 91 // Allocates in the 0.5-1.5GB region. 92 random &= 0x3fffffff; 93 random += 0x20000000; 94 #endif // CPU(X86_64) 95 random &= kPageAllocationGranularityBaseMask; 96 return reinterpret_cast<void*>(random); 97 } 98 99 } 100