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