Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 1 | //===-- scudo_utils.h -------------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | /// |
| 10 | /// Header for scudo_utils.cpp. |
| 11 | /// |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef SCUDO_UTILS_H_ |
| 15 | #define SCUDO_UTILS_H_ |
| 16 | |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 17 | #include "sanitizer_common/sanitizer_common.h" |
| 18 | |
Kostya Kortchinsky | 4a0ebbf | 2017-11-03 23:48:25 +0000 | [diff] [blame^] | 19 | #include <string.h> |
| 20 | |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 21 | namespace __scudo { |
| 22 | |
| 23 | template <class Dest, class Source> |
| 24 | inline Dest bit_cast(const Source& source) { |
| 25 | static_assert(sizeof(Dest) == sizeof(Source), "Sizes are not equal!"); |
| 26 | Dest dest; |
| 27 | memcpy(&dest, &source, sizeof(dest)); |
| 28 | return dest; |
| 29 | } |
| 30 | |
Kostya Serebryany | 8b4904f | 2016-08-02 23:23:13 +0000 | [diff] [blame] | 31 | void NORETURN dieWithMessage(const char *Format, ...); |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 32 | |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 33 | enum CPUFeature { |
| 34 | CRC32CPUFeature = 0, |
| 35 | MaxCPUFeature, |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 36 | }; |
Kostya Kortchinsky | 4a0ebbf | 2017-11-03 23:48:25 +0000 | [diff] [blame^] | 37 | bool testCPUFeature(CPUFeature Feature); |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 38 | |
Kostya Kortchinsky | 0058256 | 2017-07-12 15:29:08 +0000 | [diff] [blame] | 39 | INLINE u64 rotl(const u64 X, int K) { |
| 40 | return (X << K) | (X >> (64 - K)); |
| 41 | } |
| 42 | |
| 43 | // XoRoShiRo128+ PRNG (http://xoroshiro.di.unimi.it/). |
| 44 | struct XoRoShiRo128Plus { |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 45 | public: |
Kostya Kortchinsky | 0058256 | 2017-07-12 15:29:08 +0000 | [diff] [blame] | 46 | void init() { |
Kostya Kortchinsky | e1dde07 | 2017-08-14 14:53:47 +0000 | [diff] [blame] | 47 | if (UNLIKELY(!GetRandom(reinterpret_cast<void *>(State), sizeof(State), |
| 48 | /*blocking=*/false))) { |
| 49 | // On some platforms, early processes like `init` do not have an |
| 50 | // initialized random pool (getrandom blocks and /dev/urandom doesn't |
| 51 | // exist yet), but we still have to provide them with some degree of |
| 52 | // entropy. Not having a secure seed is not as problematic for them, as |
| 53 | // they are less likely to be the target of heap based vulnerabilities |
| 54 | // exploitation attempts. |
Kostya Kortchinsky | 0058256 | 2017-07-12 15:29:08 +0000 | [diff] [blame] | 55 | State[0] = NanoTime(); |
| 56 | State[1] = 0; |
| 57 | } |
| 58 | fillCache(); |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 59 | } |
Kostya Kortchinsky | 0058256 | 2017-07-12 15:29:08 +0000 | [diff] [blame] | 60 | u8 getU8() { |
| 61 | if (UNLIKELY(isCacheEmpty())) |
| 62 | fillCache(); |
| 63 | const u8 Result = static_cast<u8>(CachedBytes & 0xff); |
| 64 | CachedBytes >>= 8; |
| 65 | CachedBytesAvailable--; |
| 66 | return Result; |
| 67 | } |
| 68 | u64 getU64() { return next(); } |
| 69 | |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 70 | private: |
Kostya Kortchinsky | 0058256 | 2017-07-12 15:29:08 +0000 | [diff] [blame] | 71 | u8 CachedBytesAvailable; |
| 72 | u64 CachedBytes; |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 73 | u64 State[2]; |
Kostya Kortchinsky | 0058256 | 2017-07-12 15:29:08 +0000 | [diff] [blame] | 74 | u64 next() { |
| 75 | const u64 S0 = State[0]; |
| 76 | u64 S1 = State[1]; |
| 77 | const u64 Result = S0 + S1; |
| 78 | S1 ^= S0; |
| 79 | State[0] = rotl(S0, 55) ^ S1 ^ (S1 << 14); |
| 80 | State[1] = rotl(S1, 36); |
| 81 | return Result; |
| 82 | } |
| 83 | bool isCacheEmpty() { |
| 84 | return CachedBytesAvailable == 0; |
| 85 | } |
| 86 | void fillCache() { |
| 87 | CachedBytes = next(); |
| 88 | CachedBytesAvailable = sizeof(CachedBytes); |
| 89 | } |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 90 | }; |
| 91 | |
Kostya Kortchinsky | 0058256 | 2017-07-12 15:29:08 +0000 | [diff] [blame] | 92 | typedef XoRoShiRo128Plus ScudoPrng; |
| 93 | |
Kostya Kortchinsky | 1148dc5 | 2016-11-30 17:32:20 +0000 | [diff] [blame] | 94 | } // namespace __scudo |
Kostya Serebryany | 712fc98 | 2016-06-07 01:20:26 +0000 | [diff] [blame] | 95 | |
| 96 | #endif // SCUDO_UTILS_H_ |