1 //===-- scudo_utils.cpp -----------------------------------------*- 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 /// Platform specific utility functions. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "scudo_utils.h" 15 16 #include <errno.h> 17 #include <fcntl.h> 18 #include <stdarg.h> 19 #include <unistd.h> 20 #if defined(__x86_64__) || defined(__i386__) 21 # include <cpuid.h> 22 #endif 23 #if defined(__arm__) || defined(__aarch64__) 24 # include <sys/auxv.h> 25 #endif 26 27 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less 28 // complicated string formatting code. The following is a 29 // temporary workaround to be able to use __sanitizer::VSNPrintf. 30 namespace __sanitizer { 31 32 extern int VSNPrintf(char *buff, int buff_length, const char *format, 33 va_list args); 34 35 } // namespace __sanitizer 36 37 namespace __scudo { 38 39 FORMAT(1, 2) 40 void NORETURN dieWithMessage(const char *Format, ...) { 41 // Our messages are tiny, 256 characters is more than enough. 42 char Message[256]; 43 va_list Args; 44 va_start(Args, Format); 45 __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args); 46 va_end(Args); 47 RawWrite(Message); 48 Die(); 49 } 50 51 #if defined(__x86_64__) || defined(__i386__) 52 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID. 53 // CRC32 requires the SSE 4.2 instruction set. 54 typedef struct { 55 u32 Eax; 56 u32 Ebx; 57 u32 Ecx; 58 u32 Edx; 59 } CPUIDRegs; 60 61 static void getCPUID(CPUIDRegs *Regs, u32 Level) 62 { 63 __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx); 64 } 65 66 CPUIDRegs getCPUFeatures() { 67 CPUIDRegs VendorRegs = {}; 68 getCPUID(&VendorRegs, 0); 69 bool IsIntel = 70 (VendorRegs.Ebx == signature_INTEL_ebx) && 71 (VendorRegs.Edx == signature_INTEL_edx) && 72 (VendorRegs.Ecx == signature_INTEL_ecx); 73 bool IsAMD = 74 (VendorRegs.Ebx == signature_AMD_ebx) && 75 (VendorRegs.Edx == signature_AMD_edx) && 76 (VendorRegs.Ecx == signature_AMD_ecx); 77 // Default to an empty feature set if not on a supported CPU. 78 CPUIDRegs FeaturesRegs = {}; 79 if (IsIntel || IsAMD) { 80 getCPUID(&FeaturesRegs, 1); 81 } 82 return FeaturesRegs; 83 } 84 85 #ifndef bit_SSE4_2 86 # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines. 87 #endif 88 89 bool testCPUFeature(CPUFeature Feature) 90 { 91 CPUIDRegs FeaturesRegs = getCPUFeatures(); 92 93 switch (Feature) { 94 case CRC32CPUFeature: // CRC32 is provided by SSE 4.2. 95 return !!(FeaturesRegs.Ecx & bit_SSE4_2); 96 default: 97 break; 98 } 99 return false; 100 } 101 #elif defined(__arm__) || defined(__aarch64__) 102 // For ARM and AArch64, hardware CRC32 support is indicated in the 103 // AT_HWVAL auxiliary vector. 104 105 #ifndef HWCAP_CRC32 106 # define HWCAP_CRC32 (1<<7) // HWCAP_CRC32 is missing on older platforms. 107 #endif 108 109 bool testCPUFeature(CPUFeature Feature) { 110 uptr HWCap = getauxval(AT_HWCAP); 111 112 switch (Feature) { 113 case CRC32CPUFeature: 114 return !!(HWCap & HWCAP_CRC32); 115 default: 116 break; 117 } 118 return false; 119 } 120 #else 121 bool testCPUFeature(CPUFeature Feature) { 122 return false; 123 } 124 #endif // defined(__x86_64__) || defined(__i386__) 125 126 // readRetry will attempt to read Count bytes from the Fd specified, and if 127 // interrupted will retry to read additional bytes to reach Count. 128 static ssize_t readRetry(int Fd, u8 *Buffer, size_t Count) { 129 ssize_t AmountRead = 0; 130 while (static_cast<size_t>(AmountRead) < Count) { 131 ssize_t Result = read(Fd, Buffer + AmountRead, Count - AmountRead); 132 if (Result > 0) 133 AmountRead += Result; 134 else if (!Result) 135 break; 136 else if (errno != EINTR) { 137 AmountRead = -1; 138 break; 139 } 140 } 141 return AmountRead; 142 } 143 144 static void fillRandom(u8 *Data, ssize_t Size) { 145 int Fd = open("/dev/urandom", O_RDONLY); 146 if (Fd < 0) { 147 dieWithMessage("ERROR: failed to open /dev/urandom.\n"); 148 } 149 bool Success = readRetry(Fd, Data, Size) == Size; 150 close(Fd); 151 if (!Success) { 152 dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n"); 153 } 154 } 155 156 // Default constructor for Xorshift128Plus seeds the state with /dev/urandom. 157 // TODO(kostyak): investigate using getrandom() if available. 158 Xorshift128Plus::Xorshift128Plus() { 159 fillRandom(reinterpret_cast<u8 *>(State), sizeof(State)); 160 } 161 162 } // namespace __scudo 163