Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: third_party/WebKit/Source/wtf/PageAllocator.cpp

Issue 1401483002: Fix PartitionAlloc randomization on 32-bit systems (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: carve out tsan's range in getRandomPageBase Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 30 matching lines...) Expand all
41 #include <sys/mman.h> 41 #include <sys/mman.h>
42 42
43 #ifndef MADV_FREE 43 #ifndef MADV_FREE
44 #define MADV_FREE MADV_DONTNEED 44 #define MADV_FREE MADV_DONTNEED
45 #endif 45 #endif
46 46
47 #ifndef MAP_ANONYMOUS 47 #ifndef MAP_ANONYMOUS
48 #define MAP_ANONYMOUS MAP_ANON 48 #define MAP_ANONYMOUS MAP_ANON
49 #endif 49 #endif
50 50
51 // On POSIX memmap uses a nearby address if the hint address is blocked.
52 static const bool kHintIsAdvisory = true;
53
51 #elif OS(WIN) 54 #elif OS(WIN)
52 55
53 #include <windows.h> 56 #include <windows.h>
54 57
58 // VirtualAlloc will fail if allocation at the hint address is blocked.
59 static const bool kHintIsAdvisory = false;
60
55 #else 61 #else
56 #error Unknown OS 62 #error Unknown OS
57 #endif // OS(POSIX) 63 #endif // OS(POSIX)
58 64
59 namespace WTF { 65 namespace WTF {
60 66
61 // This simple internal function wraps the OS-specific page allocation call so 67 // This internal function wraps the OS-specific page allocation call. The
62 // that it behaves consistently: the address is a hint and if it cannot be used, 68 // behavior of the hint address is determined by the kHintIsAdvisory constant.
63 // the allocation will be placed elsewhere. 69 // If true, a non-zero hint is advisory and the returned address may differ from
64 static void* systemAllocPages(void* addr, size_t len, PageAccessibilityConfigura tion pageAccessibility) 70 // the hint. If false, the hint is mandatory and a successful allocation will
71 // not differ from the hint.
72 static void* systemAllocPages(void* hint, size_t len, PageAccessibilityConfigura tion pageAccessibility)
65 { 73 {
66 ASSERT(!(len & kPageAllocationGranularityOffsetMask)); 74 ASSERT(!(len & kPageAllocationGranularityOffsetMask));
67 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kPageAllocationGranularityOffse tMask)); 75 ASSERT(!(reinterpret_cast<uintptr_t>(hint) & kPageAllocationGranularityOffse tMask));
68 void* ret; 76 void* ret;
69 #if OS(WIN) 77 #if OS(WIN)
70 int accessFlag = pageAccessibility == PageAccessible ? PAGE_READWRITE : PAGE _NOACCESS; 78 DWORD accessFlag = pageAccessibility == PageAccessible ? PAGE_READWRITE : PA GE_NOACCESS;
71 ret = VirtualAlloc(addr, len, MEM_RESERVE | MEM_COMMIT, accessFlag); 79 ret = VirtualAlloc(hint, len, MEM_RESERVE | MEM_COMMIT, accessFlag);
72 if (!ret)
73 ret = VirtualAlloc(0, len, MEM_RESERVE | MEM_COMMIT, accessFlag);
74 #else 80 #else
75 int accessFlag = pageAccessibility == PageAccessible ? (PROT_READ | PROT_WRI TE) : PROT_NONE; 81 int accessFlag = pageAccessibility == PageAccessible ? (PROT_READ | PROT_WRI TE) : PROT_NONE;
76 ret = mmap(addr, len, accessFlag, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 82 ret = mmap(hint, len, accessFlag, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
77 if (ret == MAP_FAILED) 83 if (ret == MAP_FAILED)
78 ret = 0; 84 ret = 0;
79 #endif 85 #endif
80 return ret; 86 return ret;
81 } 87 }
82 88
83 static bool trimMapping(void* baseAddr, size_t baseLen, void* trimAddr, size_t t rimLen) 89 // Trims base to given length and alignment. Windows returns null on failure and frees base.
90 static void* trimMapping(void *base, size_t baseLen, size_t trimLen, uintptr_t a lign, PageAccessibilityConfiguration pageAccessibility)
84 { 91 {
85 #if OS(WIN) 92 size_t preSlack = reinterpret_cast<uintptr_t>(base) & (align - 1);
86 return false; 93 if (preSlack)
87 #else 94 preSlack = align - preSlack;
88 char* basePtr = static_cast<char*>(baseAddr); 95 size_t postSlack = baseLen - preSlack - trimLen;
89 char* trimPtr = static_cast<char*>(trimAddr); 96 ASSERT(baseLen >= trimLen || preSlack || postSlack);
90 ASSERT(trimPtr >= basePtr); 97 ASSERT(preSlack < baseLen);
91 ASSERT(trimPtr + trimLen <= basePtr + baseLen); 98 ASSERT(postSlack < baseLen);
92 size_t preLen = trimPtr - basePtr; 99 void* ret = base;
93 if (preLen) { 100
94 int ret = munmap(basePtr, preLen); 101 #if OS(POSIX) // On POSIX we can resize the allocation run.
95 RELEASE_ASSERT(!ret); 102 (void) pageAccessibility;
103 if (preSlack) {
104 int res = munmap(base, preSlack);
105 RELEASE_ASSERT(!res);
106 ret = reinterpret_cast<char*>(base) + preSlack;
96 } 107 }
97 size_t postLen = (basePtr + baseLen) - (trimPtr + trimLen); 108 if (postSlack) {
98 if (postLen) { 109 int res = munmap(reinterpret_cast<char*>(ret) + trimLen, postSlack);
99 int ret = munmap(trimPtr + trimLen, postLen); 110 RELEASE_ASSERT(!res);
100 RELEASE_ASSERT(!ret);
101 } 111 }
102 return true; 112 #else // On Windows we can't resize the allocation run.
113 if (preSlack || postSlack) {
114 ret = reinterpret_cast<char*>(base) + preSlack;
115 freePages(base, baseLen);
116 ret = systemAllocPages(ret, trimLen, pageAccessibility);
117 }
103 #endif 118 #endif
119
120 return ret;
104 } 121 }
105 122
106 void* allocPages(void* addr, size_t len, size_t align, PageAccessibilityConfigur ation pageAccessibility) 123 void* allocPages(void* addr, size_t len, size_t align, PageAccessibilityConfigur ation pageAccessibility)
107 { 124 {
108 ASSERT(len >= kPageAllocationGranularity); 125 ASSERT(len >= kPageAllocationGranularity);
109 ASSERT(!(len & kPageAllocationGranularityOffsetMask)); 126 ASSERT(!(len & kPageAllocationGranularityOffsetMask));
110 ASSERT(align >= kPageAllocationGranularity); 127 ASSERT(align >= kPageAllocationGranularity);
111 ASSERT(!(align & kPageAllocationGranularityOffsetMask)); 128 ASSERT(!(align & kPageAllocationGranularityOffsetMask));
112 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kPageAllocationGranularityOffse tMask)); 129 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kPageAllocationGranularityOffse tMask));
113 size_t alignOffsetMask = align - 1; 130 uintptr_t alignOffsetMask = align - 1;
114 size_t alignBaseMask = ~alignOffsetMask; 131 uintptr_t alignBaseMask = ~alignOffsetMask;
115 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & alignOffsetMask)); 132 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & alignOffsetMask));
133
116 // If the client passed null as the address, choose a good one. 134 // If the client passed null as the address, choose a good one.
117 if (!addr) { 135 if (!addr) {
118 addr = getRandomPageBase(); 136 addr = getRandomPageBase();
119 addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & align BaseMask); 137 addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & align BaseMask);
120 } 138 }
121 139
122 // The common case, which is also the least work we can do, is that the 140 // First try to force an exact-size, aligned allocation from our random base .
123 // address and length are suitable. Just try it. 141 for (int count = 0; count < 3; ++count) {
124 void* ret = systemAllocPages(addr, len, pageAccessibility); 142 void* ret = systemAllocPages(addr, len, pageAccessibility);
125 // If the alignment is to our liking, we're done. 143 if (kHintIsAdvisory || ret) {
126 if (!ret || !(reinterpret_cast<uintptr_t>(ret) & alignOffsetMask)) 144 // If the alignment is to our liking, we're done.
127 return ret; 145 if (!(reinterpret_cast<uintptr_t>(ret)& alignOffsetMask))
146 return ret;
147 freePages(ret, len);
148 #if CPU(32BIT)
149 addr = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(ret)+ali gn) & alignBaseMask);
150 #endif
151 } else if (!addr) { // We know we're OOM when an unhinted allocation fai ls.
152 return nullptr;
128 153
129 // Annoying. Unmap and map a larger range to be sure to succeed on the 154 } else {
130 // second, slower attempt. 155 #if CPU(32BIT)
131 freePages(ret, len); 156 addr = reinterpret_cast<char*>(addr) + align;
157 #endif
158 }
132 159
133 size_t tryLen = len + (align - kPageAllocationGranularity); 160 #if !CPU(32BIT) // Keep trying random addresses on systems that have a large add ress space.
134 RELEASE_ASSERT(tryLen > len);
135
136 // We loop to cater for the unlikely case where another thread maps on top
137 // of the aligned location we choose.
138 int count = 0;
139 while (count++ < 100) {
140 ret = systemAllocPages(addr, tryLen, pageAccessibility);
141 if (!ret)
142 return 0;
143 // We can now try and trim out a subset of the mapping.
144 addr = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(ret) + align OffsetMask) & alignBaseMask);
145
146 // On POSIX systems, we can trim the oversized mapping to fit exactly.
147 // This will always work on POSIX systems.
148 if (trimMapping(ret, tryLen, addr, len))
149 return addr;
150
151 // On Windows, you can't trim an existing mapping so we unmap and remap
152 // a subset. We used to do for all platforms, but OSX 10.8 has a
153 // broken mmap() that ignores address hints for valid, unused addresses.
154 freePages(ret, tryLen);
155 ret = systemAllocPages(addr, len, pageAccessibility);
156 if (ret == addr || !ret)
157 return ret;
158
159 // Unlikely race / collision. Do the simple thing and just start again.
160 freePages(ret, len);
161 addr = getRandomPageBase(); 161 addr = getRandomPageBase();
162 addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & align BaseMask); 162 addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & align BaseMask);
163 #endif
163 } 164 }
164 IMMEDIATE_CRASH(); 165
165 return 0; 166 // Map a larger allocation so we can force alignment, but continue randomizi ng only on 64-bit POSIX.
167 size_t tryLen = len + (align - kPageAllocationGranularity);
168 RELEASE_ASSERT(tryLen >= len);
169 void* ret;
170
171 do {
172 // Don't continue to burn cycles on mandatory hints (Windows).
173 addr = kHintIsAdvisory ? getRandomPageBase() : nullptr;
174 ret = systemAllocPages(addr, tryLen, pageAccessibility);
175 // The retries are for Windows, where a race can steal our mapping on resize .
176 } while (ret && !(ret = trimMapping(ret, tryLen, len, align, pageAccessibili ty)));
177
178 return ret;
166 } 179 }
167 180
168 void freePages(void* addr, size_t len) 181 void freePages(void* addr, size_t len)
169 { 182 {
170 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kPageAllocationGranularityOffse tMask)); 183 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kPageAllocationGranularityOffse tMask));
171 ASSERT(!(len & kPageAllocationGranularityOffsetMask)); 184 ASSERT(!(len & kPageAllocationGranularityOffsetMask));
172 #if OS(POSIX) 185 #if OS(POSIX)
173 int ret = munmap(addr, len); 186 int ret = munmap(addr, len);
174 RELEASE_ASSERT(!ret); 187 RELEASE_ASSERT(!ret);
175 #else 188 #else
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 #else 246 #else
234 (void) addr; 247 (void) addr;
235 (void) len; 248 (void) len;
236 // TODO(cevans): implement this using MEM_RESET for Windows, once we've 249 // TODO(cevans): implement this using MEM_RESET for Windows, once we've
237 // decided that the semantics are a match. 250 // decided that the semantics are a match.
238 #endif 251 #endif
239 } 252 }
240 253
241 } // namespace WTF 254 } // namespace WTF
242 255
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698