address_space_randomization.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_SPACE_RANDOMIZATION_H_
  5. #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_SPACE_RANDOMIZATION_H_
  6. #include <cstdint>
  7. #include "base/allocator/partition_allocator/page_allocator_constants.h"
  8. #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
  9. #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
  10. #include "build/build_config.h"
  11. namespace partition_alloc {
  12. // Calculates a random preferred mapping address. In calculating an address, we
  13. // balance good ASLR against not fragmenting the address space too badly.
  14. PA_COMPONENT_EXPORT(PARTITION_ALLOC) uintptr_t GetRandomPageBase();
  15. namespace internal {
  16. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE uintptr_t
  17. AslrAddress(uintptr_t mask) {
  18. return mask & PageAllocationGranularityBaseMask();
  19. }
  20. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE uintptr_t
  21. AslrMask(uintptr_t bits) {
  22. return AslrAddress((1ULL << bits) - 1ULL);
  23. }
  24. // Turn off formatting, because the thicket of nested ifdefs below is
  25. // incomprehensible without indentation. It is also incomprehensible with
  26. // indentation, but the only other option is a combinatorial explosion of
  27. // *_{win,linux,mac,foo}_{32,64}.h files.
  28. //
  29. // clang-format off
  30. #if defined(ARCH_CPU_64_BITS)
  31. #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
  32. // We shouldn't allocate system pages at all for sanitizer builds. However,
  33. // we do, and if random hint addresses interfere with address ranges
  34. // hard-coded in those tools, bad things happen. This address range is
  35. // copied from TSAN source but works with all tools. See
  36. // https://crbug.com/539863.
  37. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE uintptr_t
  38. ASLRMask() {
  39. return AslrAddress(0x007fffffffffULL);
  40. }
  41. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE uintptr_t
  42. ASLROffset() {
  43. return AslrAddress(0x7e8000000000ULL);
  44. }
  45. #elif BUILDFLAG(IS_WIN)
  46. // Windows 8.10 and newer support the full 48 bit address range. Older
  47. // versions of Windows only support 44 bits. Since ASLROffset() is non-zero
  48. // and may cause a carry, use 47 and 43 bit masks. See
  49. // http://www.alex-ionescu.com/?p=246
  50. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  51. return AslrMask(47);
  52. }
  53. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMaskBefore8_10() {
  54. return AslrMask(43);
  55. }
  56. // Try not to map pages into the range where Windows loads DLLs by default.
  57. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  58. return 0x80000000ULL;
  59. }
  60. #elif BUILDFLAG(IS_APPLE)
  61. // macOS as of 10.12.5 does not clean up entries in page map levels 3/4
  62. // [PDP/PML4] created from mmap or mach_vm_allocate, even after the region
  63. // is destroyed. Using a virtual address space that is too large causes a
  64. // leak of about 1 wired [can never be paged out] page per call to mmap. The
  65. // page is only reclaimed when the process is killed. Confine the hint to a
  66. // 39-bit section of the virtual address space.
  67. //
  68. // This implementation adapted from
  69. // https://chromium-review.googlesource.com/c/v8/v8/+/557958. The difference
  70. // is that here we clamp to 39 bits, not 32.
  71. //
  72. // TODO(crbug.com/738925): Remove this limitation if/when the macOS behavior
  73. // changes.
  74. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE uintptr_t
  75. ASLRMask() {
  76. return AslrMask(38);
  77. }
  78. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE uintptr_t
  79. ASLROffset() {
  80. // Be careful, there is a zone where macOS will not map memory, at least
  81. // on ARM64. From an ARM64 machine running 12.3, the range seems to be
  82. // [0x1000000000, 0x7000000000). Make sure that the range we use is
  83. // outside these bounds. In 12.3, there is a reserved area between
  84. // MACH_VM_MIN_GPU_CARVEOUT_ADDRESS and MACH_VM_MAX_GPU_CARVEOUT_ADDRESS,
  85. // which is reserved on ARM64. See these constants in XNU's source code
  86. // for details (xnu-8019.80.24/osfmk/mach/arm/vm_param.h).
  87. return AslrAddress(0x10000000000ULL);
  88. }
  89. #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  90. #if defined(ARCH_CPU_X86_64)
  91. // Linux (and macOS) support the full 47-bit user space of x64 processors.
  92. // Use only 46 to allow the kernel a chance to fulfill the request.
  93. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  94. return AslrMask(46);
  95. }
  96. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  97. return AslrAddress(0);
  98. }
  99. #elif defined(ARCH_CPU_ARM64)
  100. #if BUILDFLAG(IS_ANDROID)
  101. // Restrict the address range on Android to avoid a large performance
  102. // regression in single-process WebViews. See https://crbug.com/837640.
  103. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  104. return AslrMask(30);
  105. }
  106. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  107. return AslrAddress(0x20000000ULL);
  108. }
  109. #elif BUILDFLAG(IS_LINUX)
  110. // Linux on arm64 can use 39, 42, 48, or 52-bit user space, depending on
  111. // page size and number of levels of translation pages used. We use
  112. // 39-bit as base as all setups should support this, lowered to 38-bit
  113. // as ASLROffset() could cause a carry.
  114. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE uintptr_t
  115. ASLRMask() {
  116. return AslrMask(38);
  117. }
  118. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE uintptr_t
  119. ASLROffset() {
  120. return AslrAddress(0x1000000000ULL);
  121. }
  122. #else
  123. // ARM64 on Linux has 39-bit user space. Use 38 bits since ASLROffset()
  124. // could cause a carry.
  125. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  126. return AslrMask(38);
  127. }
  128. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  129. return AslrAddress(0x1000000000ULL);
  130. }
  131. #endif
  132. #elif defined(ARCH_CPU_PPC64)
  133. #if BUILDFLAG(IS_AIX)
  134. // AIX has 64 bits of virtual addressing, but we limit the address range
  135. // to (a) minimize segment lookaside buffer (SLB) misses; and (b) use
  136. // extra address space to isolate the mmap regions.
  137. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  138. return AslrMask(30);
  139. }
  140. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  141. return AslrAddress(0x400000000000ULL);
  142. }
  143. #elif defined(ARCH_CPU_BIG_ENDIAN)
  144. // Big-endian Linux PPC has 44 bits of virtual addressing. Use 42.
  145. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  146. return AslrMask(42);
  147. }
  148. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  149. return AslrAddress(0);
  150. }
  151. #else // !BUILDFLAG(IS_AIX) && !defined(ARCH_CPU_BIG_ENDIAN)
  152. // Little-endian Linux PPC has 48 bits of virtual addressing. Use 46.
  153. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  154. return AslrMask(46);
  155. }
  156. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  157. return AslrAddress(0);
  158. }
  159. #endif // !BUILDFLAG(IS_AIX) && !defined(ARCH_CPU_BIG_ENDIAN)
  160. #elif defined(ARCH_CPU_S390X)
  161. // Linux on Z uses bits 22 - 32 for Region Indexing, which translates to
  162. // 42 bits of virtual addressing. Truncate to 40 bits to allow kernel a
  163. // chance to fulfill the request.
  164. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  165. return AslrMask(40);
  166. }
  167. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  168. return AslrAddress(0);
  169. }
  170. #elif defined(ARCH_CPU_S390)
  171. // 31 bits of virtual addressing. Truncate to 29 bits to allow the kernel
  172. // a chance to fulfill the request.
  173. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  174. return AslrMask(29);
  175. }
  176. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  177. return AslrAddress(0);
  178. }
  179. #else // !defined(ARCH_CPU_X86_64) && !defined(ARCH_CPU_PPC64) &&
  180. // !defined(ARCH_CPU_S390X) && !defined(ARCH_CPU_S390)
  181. // For all other POSIX variants, use 30 bits.
  182. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  183. return AslrMask(30);
  184. }
  185. #if BUILDFLAG(IS_SOLARIS)
  186. // For our Solaris/illumos mmap hint, we pick a random address in the
  187. // bottom half of the top half of the address space (that is, the third
  188. // quarter). Because we do not MAP_FIXED, this will be treated only as a
  189. // hint -- the system will not fail to mmap because something else
  190. // happens to already be mapped at our random address. We deliberately
  191. // set the hint high enough to get well above the system's break (that
  192. // is, the heap); Solaris and illumos will try the hint and if that
  193. // fails allocate as if there were no hint at all. The high hint
  194. // prevents the break from getting hemmed in at low values, ceding half
  195. // of the address space to the system heap.
  196. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  197. return AslrAddress(0x80000000ULL);
  198. }
  199. #elif BUILDFLAG(IS_AIX)
  200. // The range 0x30000000 - 0xD0000000 is available on AIX; choose the
  201. // upper range.
  202. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  203. return AslrAddress(0x90000000ULL);
  204. }
  205. #else // !BUILDFLAG(IS_SOLARIS) && !BUILDFLAG(IS_AIX)
  206. // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
  207. // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macOS
  208. // 10.6 and 10.7.
  209. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  210. return AslrAddress(0x20000000ULL);
  211. }
  212. #endif // !BUILDFLAG(IS_SOLARIS) && !BUILDFLAG(IS_AIX)
  213. #endif // !defined(ARCH_CPU_X86_64) && !defined(ARCH_CPU_PPC64) &&
  214. // !defined(ARCH_CPU_S390X) && !defined(ARCH_CPU_S390)
  215. #endif // BUILDFLAG(IS_POSIX)
  216. #elif defined(ARCH_CPU_32_BITS)
  217. // This is a good range on 32-bit Windows and Android (the only platforms on
  218. // which we support 32-bitness). Allocates in the 0.5 - 1.5 GiB region. There
  219. // is no issue with carries here.
  220. constexpr PA_ALWAYS_INLINE uintptr_t ASLRMask() {
  221. return AslrMask(30);
  222. }
  223. constexpr PA_ALWAYS_INLINE uintptr_t ASLROffset() {
  224. return AslrAddress(0x20000000ULL);
  225. }
  226. #else
  227. #error Please tell us about your exotic hardware! Sounds interesting.
  228. #endif // defined(ARCH_CPU_32_BITS)
  229. // clang-format on
  230. } // namespace internal
  231. } // namespace partition_alloc
  232. #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_SPACE_RANDOMIZATION_H_