Home | History | Annotate | Download | only in wtf
      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 
     29 uint32_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 
     41 uint32_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.
     67 void* 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