1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "wtf/PageAllocator.h" 33 34 #include "wtf/Assertions.h" 35 #include "wtf/CPU.h" 36 #include "wtf/CryptographicallyRandomNumber.h" 37 38 #if OS(UNIX) 39 40 #include <sys/mman.h> 41 42 #ifndef MADV_FREE 43 #define MADV_FREE MADV_DONTNEED 44 #endif 45 46 #ifndef MAP_ANONYMOUS 47 #define MAP_ANONYMOUS MAP_ANON 48 #endif 49 50 #elif OS(WINDOWS) 51 52 #include <windows.h> 53 54 #else 55 #error Unknown OS 56 #endif // OS(UNIX) 57 58 #include <stdio.h> 59 60 namespace WTF { 61 62 void* allocSuperPages(void* addr, size_t len) 63 { 64 ASSERT(!(len & kSuperPageOffsetMask)); 65 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kSuperPageOffsetMask)); 66 #if OS(UNIX) 67 char* ptr = reinterpret_cast<char*>(mmap(addr, len, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); 68 RELEASE_ASSERT(ptr != MAP_FAILED); 69 // If our requested address collided with another mapping, there's a 70 // chance we'll get back an unaligned address. We fix this by attempting 71 // the allocation again, but with enough slack pages that we can find 72 // correct alignment within the allocation. 73 if (UNLIKELY(reinterpret_cast<uintptr_t>(ptr) & kSuperPageOffsetMask)) { 74 int ret = munmap(ptr, len); 75 ASSERT(!ret); 76 ptr = reinterpret_cast<char*>(mmap(0, len + kSuperPageSize - kSystemPageSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); 77 RELEASE_ASSERT(ptr != MAP_FAILED); 78 int numSystemPagesToUnmap = kNumSystemPagesPerSuperPage - 1; 79 int numSystemPagesBefore = (kNumSystemPagesPerSuperPage - ((reinterpret_cast<uintptr_t>(ptr) & kSuperPageOffsetMask) / kSystemPageSize)) % kNumSystemPagesPerSuperPage; 80 ASSERT(numSystemPagesBefore <= numSystemPagesToUnmap); 81 int numSystemPagesAfter = numSystemPagesToUnmap - numSystemPagesBefore; 82 if (numSystemPagesBefore) { 83 size_t beforeSize = kSystemPageSize * numSystemPagesBefore; 84 ret = munmap(ptr, beforeSize); 85 ASSERT(!ret); 86 ptr += beforeSize; 87 } 88 if (numSystemPagesAfter) { 89 ret = munmap(ptr + len, kSystemPageSize * numSystemPagesAfter); 90 ASSERT(!ret); 91 } 92 } 93 void* ret = ptr; 94 #else 95 // Windows is a lot simpler because we've designed around its 96 // coarser-grained alignement. 97 void* ret = VirtualAlloc(addr, len, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 98 if (!ret) 99 ret = VirtualAlloc(0, len, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 100 RELEASE_ASSERT(ret); 101 #endif // OS(UNIX) 102 return ret; 103 } 104 105 void freeSuperPages(void* addr, size_t len) 106 { 107 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kSuperPageOffsetMask)); 108 ASSERT(!(len & kSuperPageOffsetMask)); 109 #if OS(UNIX) 110 int ret = munmap(addr, len); 111 ASSERT(!ret); 112 #else 113 BOOL ret = VirtualFree(addr, 0, MEM_RELEASE); 114 ASSERT(ret); 115 #endif 116 } 117 118 void setSystemPagesInaccessible(void* addr, size_t len) 119 { 120 ASSERT(!(len & kSystemPageOffsetMask)); 121 #if OS(UNIX) 122 int ret = mprotect(addr, len, PROT_NONE); 123 ASSERT(!ret); 124 #else 125 BOOL ret = VirtualFree(addr, len, MEM_DECOMMIT); 126 ASSERT(ret); 127 #endif 128 } 129 130 void decommitSystemPages(void* addr, size_t len) 131 { 132 ASSERT(!(len & kSystemPageOffsetMask)); 133 #if OS(UNIX) 134 int ret = madvise(addr, len, MADV_FREE); 135 ASSERT(!ret); 136 #else 137 void* ret = VirtualAlloc(addr, len, MEM_RESET, PAGE_READWRITE); 138 ASSERT(ret); 139 #endif 140 } 141 142 char* getRandomSuperPageBase() 143 { 144 uintptr_t random; 145 random = static_cast<uintptr_t>(cryptographicallyRandomNumber()); 146 #if CPU(X86_64) 147 random <<= 32UL; 148 random |= static_cast<uintptr_t>(cryptographicallyRandomNumber()); 149 // This address mask gives a low liklihood of address space collisions. 150 // We handle the situation gracefully if there is a collision. 151 #if OS(WINDOWS) 152 // 64-bit Windows has a bizarrely small 8TB user address space. 153 // Allocates in the 1-5TB region. 154 random &= (0x3ffffffffffUL & kSuperPageBaseMask); 155 random += 0x10000000000UL; 156 #else 157 random &= (0x3fffffffffffUL & kSuperPageBaseMask); 158 #endif 159 #else // !CPU(X86_64) 160 // This is a good range on Windows, Linux and Mac. 161 // Allocates in the 0.5-1.5GB region. 162 random &= (0x3fffffff & kSuperPageBaseMask); 163 random += 0x20000000; 164 #endif // CPU(X86_64) 165 return reinterpret_cast<char*>(random); 166 } 167 168 } // namespace WTF 169 170