| 1 | //===-- common.h ------------------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef SCUDO_COMMON_H_ |
| 10 | #define SCUDO_COMMON_H_ |
| 11 | |
| 12 | #include "internal_defs.h" |
| 13 | |
| 14 | #include "fuchsia.h" |
| 15 | #include "linux.h" |
| 16 | #include "trusty.h" |
| 17 | |
| 18 | #include <stddef.h> |
| 19 | #include <string.h> |
| 20 | #include <unistd.h> |
| 21 | |
| 22 | namespace scudo { |
| 23 | |
| 24 | template <class Dest, class Source> inline Dest bit_cast(const Source &S) { |
| 25 | static_assert(sizeof(Dest) == sizeof(Source), "" ); |
| 26 | Dest D; |
| 27 | memcpy(&D, &S, sizeof(D)); |
| 28 | return D; |
| 29 | } |
| 30 | |
| 31 | inline constexpr bool isPowerOfTwo(uptr X) { |
| 32 | if (X == 0) |
| 33 | return false; |
| 34 | return (X & (X - 1)) == 0; |
| 35 | } |
| 36 | |
| 37 | inline constexpr uptr roundUp(uptr X, uptr Boundary) { |
| 38 | DCHECK(isPowerOfTwo(Boundary)); |
| 39 | return (X + Boundary - 1) & ~(Boundary - 1); |
| 40 | } |
| 41 | inline constexpr uptr roundUpSlow(uptr X, uptr Boundary) { |
| 42 | return ((X + Boundary - 1) / Boundary) * Boundary; |
| 43 | } |
| 44 | |
| 45 | inline constexpr uptr roundDown(uptr X, uptr Boundary) { |
| 46 | DCHECK(isPowerOfTwo(Boundary)); |
| 47 | return X & ~(Boundary - 1); |
| 48 | } |
| 49 | inline constexpr uptr roundDownSlow(uptr X, uptr Boundary) { |
| 50 | return (X / Boundary) * Boundary; |
| 51 | } |
| 52 | |
| 53 | inline constexpr bool isAligned(uptr X, uptr Alignment) { |
| 54 | DCHECK(isPowerOfTwo(Alignment)); |
| 55 | return (X & (Alignment - 1)) == 0; |
| 56 | } |
| 57 | inline constexpr bool isAlignedSlow(uptr X, uptr Alignment) { |
| 58 | return X % Alignment == 0; |
| 59 | } |
| 60 | |
| 61 | template <class T> constexpr T Min(T A, T B) { return A < B ? A : B; } |
| 62 | |
| 63 | template <class T> constexpr T Max(T A, T B) { return A > B ? A : B; } |
| 64 | |
| 65 | template <class T> void Swap(T &A, T &B) { |
| 66 | T Tmp = A; |
| 67 | A = B; |
| 68 | B = Tmp; |
| 69 | } |
| 70 | |
| 71 | inline uptr getMostSignificantSetBitIndex(uptr X) { |
| 72 | DCHECK_NE(X, 0U); |
| 73 | return SCUDO_WORDSIZE - 1U - static_cast<uptr>(__builtin_clzl(X)); |
| 74 | } |
| 75 | |
| 76 | inline uptr roundUpPowerOfTwo(uptr Size) { |
| 77 | DCHECK(Size); |
| 78 | if (isPowerOfTwo(X: Size)) |
| 79 | return Size; |
| 80 | const uptr Up = getMostSignificantSetBitIndex(X: Size); |
| 81 | DCHECK_LT(Size, (1UL << (Up + 1))); |
| 82 | DCHECK_GT(Size, (1UL << Up)); |
| 83 | return 1UL << (Up + 1); |
| 84 | } |
| 85 | |
| 86 | inline uptr getLeastSignificantSetBitIndex(uptr X) { |
| 87 | DCHECK_NE(X, 0U); |
| 88 | return static_cast<uptr>(__builtin_ctzl(X)); |
| 89 | } |
| 90 | |
| 91 | inline uptr getLog2(uptr X) { |
| 92 | DCHECK(isPowerOfTwo(X)); |
| 93 | return getLeastSignificantSetBitIndex(X); |
| 94 | } |
| 95 | |
| 96 | inline u32 getRandomU32(u32 *State) { |
| 97 | // ANSI C linear congruential PRNG (16-bit output). |
| 98 | // return (*State = *State * 1103515245 + 12345) >> 16; |
| 99 | // XorShift (32-bit output). |
| 100 | *State ^= *State << 13; |
| 101 | *State ^= *State >> 17; |
| 102 | *State ^= *State << 5; |
| 103 | return *State; |
| 104 | } |
| 105 | |
| 106 | inline u32 getRandomModN(u32 *State, u32 N) { |
| 107 | return getRandomU32(State) % N; // [0, N) |
| 108 | } |
| 109 | |
| 110 | template <typename T> inline void shuffle(T *A, u32 N, u32 *RandState) { |
| 111 | if (N <= 1) |
| 112 | return; |
| 113 | u32 State = *RandState; |
| 114 | for (u32 I = N - 1; I > 0; I--) |
| 115 | Swap(A[I], A[getRandomModN(State: &State, N: I + 1)]); |
| 116 | *RandState = State; |
| 117 | } |
| 118 | |
| 119 | inline void computePercentage(uptr Numerator, uptr Denominator, uptr *Integral, |
| 120 | uptr *Fractional) { |
| 121 | constexpr uptr Digits = 100; |
| 122 | if (Denominator == 0) { |
| 123 | *Integral = 100; |
| 124 | *Fractional = 0; |
| 125 | return; |
| 126 | } |
| 127 | |
| 128 | *Integral = Numerator * Digits / Denominator; |
| 129 | *Fractional = |
| 130 | (((Numerator * Digits) % Denominator) * Digits + Denominator / 2) / |
| 131 | Denominator; |
| 132 | } |
| 133 | |
| 134 | // Platform specific functions. |
| 135 | |
| 136 | #if defined(SCUDO_PAGE_SIZE) |
| 137 | |
| 138 | inline constexpr uptr getPageSizeCached() { return SCUDO_PAGE_SIZE; } |
| 139 | |
| 140 | inline constexpr uptr getPageSizeSlow() { return getPageSizeCached(); } |
| 141 | |
| 142 | inline constexpr uptr getPageSizeLogCached() { |
| 143 | return static_cast<uptr>(__builtin_ctzl(SCUDO_PAGE_SIZE)); |
| 144 | } |
| 145 | |
| 146 | #else |
| 147 | |
| 148 | extern uptr PageSizeCached; |
| 149 | extern uptr PageSizeLogCached; |
| 150 | |
| 151 | uptr getPageSizeSlow(); |
| 152 | |
| 153 | inline uptr getPageSizeCached() { |
| 154 | if (LIKELY(PageSizeCached)) |
| 155 | return PageSizeCached; |
| 156 | return getPageSizeSlow(); |
| 157 | } |
| 158 | |
| 159 | inline uptr getPageSizeLogCached() { |
| 160 | if (LIKELY(PageSizeLogCached)) |
| 161 | return PageSizeLogCached; |
| 162 | // PageSizeLogCached and PageSizeCached are both set in getPageSizeSlow() |
| 163 | getPageSizeSlow(); |
| 164 | DCHECK_NE(PageSizeLogCached, 0); |
| 165 | return PageSizeLogCached; |
| 166 | } |
| 167 | |
| 168 | #endif |
| 169 | |
| 170 | // Returns 0 if the number of CPUs could not be determined. |
| 171 | u32 getNumberOfCPUs(); |
| 172 | |
| 173 | const char *getEnv(const char *Name); |
| 174 | |
| 175 | u64 getMonotonicTime(); |
| 176 | // Gets the time faster but with less accuracy. Can call getMonotonicTime |
| 177 | // if no fast version is available. |
| 178 | u64 getMonotonicTimeFast(); |
| 179 | |
| 180 | u32 getThreadID(); |
| 181 | |
| 182 | // Our randomness gathering function is limited to 256 bytes to ensure we get |
| 183 | // as many bytes as requested, and avoid interruptions (on Linux). |
| 184 | constexpr uptr MaxRandomLength = 256U; |
| 185 | bool getRandom(void *Buffer, uptr Length, bool Blocking = false); |
| 186 | |
| 187 | // Platform memory mapping functions. |
| 188 | |
| 189 | #define MAP_ALLOWNOMEM (1U << 0) |
| 190 | #define MAP_NOACCESS (1U << 1) |
| 191 | #define MAP_RESIZABLE (1U << 2) |
| 192 | #define MAP_MEMTAG (1U << 3) |
| 193 | #define MAP_PRECOMMIT (1U << 4) |
| 194 | |
| 195 | // Our platform memory mapping use is restricted to 3 scenarios: |
| 196 | // - reserve memory at a random address (MAP_NOACCESS); |
| 197 | // - commit memory in a previously reserved space; |
| 198 | // - commit memory at a random address. |
| 199 | // As such, only a subset of parameters combinations is valid, which is checked |
| 200 | // by the function implementation. The Data parameter allows to pass opaque |
| 201 | // platform specific data to the function. |
| 202 | // Returns nullptr on error or dies if MAP_ALLOWNOMEM is not specified. |
| 203 | void *map(void *Addr, uptr Size, const char *Name, uptr Flags = 0, |
| 204 | MapPlatformData *Data = nullptr); |
| 205 | |
| 206 | // Indicates that we are getting rid of the whole mapping, which might have |
| 207 | // further consequences on Data, depending on the platform. |
| 208 | #define UNMAP_ALL (1U << 0) |
| 209 | |
| 210 | void unmap(void *Addr, uptr Size, uptr Flags = 0, |
| 211 | MapPlatformData *Data = nullptr); |
| 212 | |
| 213 | void setMemoryPermission(uptr Addr, uptr Size, uptr Flags, |
| 214 | MapPlatformData *Data = nullptr); |
| 215 | |
| 216 | void releasePagesToOS(uptr BaseAddress, uptr Offset, uptr Size, |
| 217 | MapPlatformData *Data = nullptr); |
| 218 | |
| 219 | // Logging related functions. |
| 220 | |
| 221 | void setAbortMessage(const char *Message); |
| 222 | |
| 223 | struct BlockInfo { |
| 224 | uptr BlockBegin; |
| 225 | uptr BlockSize; |
| 226 | uptr RegionBegin; |
| 227 | uptr RegionEnd; |
| 228 | }; |
| 229 | |
| 230 | enum class Option : u8 { |
| 231 | ReleaseInterval, // Release to OS interval in milliseconds. |
| 232 | MemtagTuning, // Whether to tune tagging for UAF or overflow. |
| 233 | ThreadDisableMemInit, // Whether to disable automatic heap initialization and, |
| 234 | // where possible, memory tagging, on this thread. |
| 235 | MaxCacheEntriesCount, // Maximum number of blocks that can be cached. |
| 236 | MaxCacheEntrySize, // Maximum size of a block that can be cached. |
| 237 | MaxTSDsCount, // Number of usable TSDs for the shared registry. |
| 238 | }; |
| 239 | |
| 240 | enum class ReleaseToOS : u8 { |
| 241 | Normal, // Follow the normal rules for releasing pages to the OS |
| 242 | Force, // Force release pages to the OS, but avoid cases that take too long. |
| 243 | ForceAll, // Force release every page possible regardless of how long it will |
| 244 | // take. |
| 245 | }; |
| 246 | |
| 247 | constexpr unsigned char PatternFillByte = 0xAB; |
| 248 | |
| 249 | enum FillContentsMode { |
| 250 | NoFill = 0, |
| 251 | ZeroFill = 1, |
| 252 | PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be |
| 253 | // zero-initialized already. |
| 254 | }; |
| 255 | |
| 256 | } // namespace scudo |
| 257 | |
| 258 | #endif // SCUDO_COMMON_H_ |
| 259 | |