1197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// found in the LICENSE file. 4197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 5197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "config.h" 6197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "wtf/AddressSpaceRandomization.h" 7197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 8197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "wtf/PageAllocator.h" 9197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "wtf/ProcessID.h" 10197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#include "wtf/SpinLock.h" 11197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 12197021e6b966cfb06891637935ef33fff06433d1Ben Murdochnamespace WTF { 13197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 14197021e6b966cfb06891637935ef33fff06433d1Ben Murdochnamespace { 15197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 16197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// This is the same PRNG as used by tcmalloc for mapping address randomness; 17197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// see http://burtleburtle.net/bob/rand/smallprng.html 18197021e6b966cfb06891637935ef33fff06433d1Ben Murdochstruct ranctx { 19197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch int lock; 20197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch bool initialized; 21197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch uint32_t a; 22197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch uint32_t b; 23197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch uint32_t c; 24197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch uint32_t d; 25197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch}; 26197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 27197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) 28197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 29197021e6b966cfb06891637935ef33fff06433d1Ben Murdochuint32_t ranvalInternal(ranctx* x) 30197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{ 31197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch uint32_t e = x->a - rot(x->b, 27); 32197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch x->a = x->b ^ rot(x->c, 17); 33197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch x->b = x->c + x->d; 34197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch x->c = x->d + e; 35197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch x->d = e + x->a; 36197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch return x->d; 37197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} 38197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 39197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#undef rot 40197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 41197021e6b966cfb06891637935ef33fff06433d1Ben Murdochuint32_t ranval(ranctx* x) 42197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{ 43197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch spinLockLock(&x->lock); 44197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if (UNLIKELY(!x->initialized)) { 45197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch x->initialized = true; 46197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch char c; 47197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch uint32_t seed = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&c)); 48197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch seed ^= static_cast<uint32_t>(getCurrentProcessID()); 49197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch x->a = 0xf1ea5eed; 50197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch x->b = x->c = x->d = seed; 51197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch for (int i = 0; i < 20; ++i) { 52197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch (void) ranvalInternal(x); 53197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch } 54197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch } 55197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch uint32_t ret = ranvalInternal(x); 56197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch spinLockUnlock(&x->lock); 57197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch return ret; 58197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} 59197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 60197021e6b966cfb06891637935ef33fff06433d1Ben Murdochstatic struct ranctx s_ranctx; 61197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 62197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} 63197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 64197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// Calculates a random preferred mapping address. In calculating an 65197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// address, we balance good ASLR against not fragmenting the address 66197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch// space too badly. 67197021e6b966cfb06891637935ef33fff06433d1Ben Murdochvoid* getRandomPageBase() 68197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{ 69197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch uintptr_t random; 70197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random = static_cast<uintptr_t>(ranval(&s_ranctx)); 71197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if CPU(X86_64) 72197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random <<= 32UL; 73197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random |= static_cast<uintptr_t>(ranval(&s_ranctx)); 74197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // This address mask gives a low liklihood of address space collisions. 75197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // We handle the situation gracefully if there is a collision. 76197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if OS(WIN) 77197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // 64-bit Windows has a bizarrely small 8TB user address space. 78197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Allocates in the 1-5TB region. 79197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random &= 0x3ffffffffffUL; 80197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random += 0x10000000000UL; 81197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#else 82197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Linux and OS X support the full 47-bit user space of x64 processors. 83197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random &= 0x3fffffffffffUL; 84197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#endif 85197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#elif CPU(ARM64) 86197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // ARM64 on Linux has 39-bit user space. 87197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random &= 0x3fffffffffUL; 88197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random += 0x1000000000UL; 89197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#else // !CPU(X86_64) && !CPU(ARM64) 90197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // This is a good range on Windows, Linux and Mac. 91197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Allocates in the 0.5-1.5GB region. 92197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random &= 0x3fffffff; 93197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random += 0x20000000; 94197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#endif // CPU(X86_64) 95197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch random &= kPageAllocationGranularityBaseMask; 96197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch return reinterpret_cast<void*>(random); 97197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} 98197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 99197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} 100