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 21 #include <cstring> 22 23 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less 24 // complicated string formatting code. The following is a 25 // temporary workaround to be able to use __sanitizer::VSNPrintf. 26 namespace __sanitizer { 27 28 extern int VSNPrintf(char *buff, int buff_length, const char *format, 29 va_list args); 30 31 } // namespace __sanitizer 32 33 namespace __scudo { 34 35 FORMAT(1, 2) 36 void dieWithMessage(const char *Format, ...) { 37 // Our messages are tiny, 128 characters is more than enough. 38 char Message[128]; 39 va_list Args; 40 va_start(Args, Format); 41 __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args); 42 va_end(Args); 43 RawWrite(Message); 44 Die(); 45 } 46 47 typedef struct { 48 u32 Eax; 49 u32 Ebx; 50 u32 Ecx; 51 u32 Edx; 52 } CPUIDInfo; 53 54 static void getCPUID(CPUIDInfo *info, u32 leaf, u32 subleaf) 55 { 56 asm volatile("cpuid" 57 : "=a" (info->Eax), "=b" (info->Ebx), "=c" (info->Ecx), "=d" (info->Edx) 58 : "a" (leaf), "c" (subleaf) 59 ); 60 } 61 62 // Returns true is the CPU is a "GenuineIntel" or "AuthenticAMD" 63 static bool isSupportedCPU() 64 { 65 CPUIDInfo Info; 66 67 getCPUID(&Info, 0, 0); 68 if (memcmp(reinterpret_cast<char *>(&Info.Ebx), "Genu", 4) == 0 && 69 memcmp(reinterpret_cast<char *>(&Info.Edx), "ineI", 4) == 0 && 70 memcmp(reinterpret_cast<char *>(&Info.Ecx), "ntel", 4) == 0) { 71 return true; 72 } 73 if (memcmp(reinterpret_cast<char *>(&Info.Ebx), "Auth", 4) == 0 && 74 memcmp(reinterpret_cast<char *>(&Info.Edx), "enti", 4) == 0 && 75 memcmp(reinterpret_cast<char *>(&Info.Ecx), "cAMD", 4) == 0) { 76 return true; 77 } 78 return false; 79 } 80 81 bool testCPUFeature(CPUFeature feature) 82 { 83 static bool InfoInitialized = false; 84 static CPUIDInfo CPUInfo = {}; 85 86 if (InfoInitialized == false) { 87 if (isSupportedCPU() == true) 88 getCPUID(&CPUInfo, 1, 0); 89 else 90 UNIMPLEMENTED(); 91 InfoInitialized = true; 92 } 93 switch (feature) { 94 case SSE4_2: 95 return ((CPUInfo.Ecx >> 20) & 0x1) != 0; 96 default: 97 break; 98 } 99 return false; 100 } 101 102 // readRetry will attempt to read Count bytes from the Fd specified, and if 103 // interrupted will retry to read additional bytes to reach Count. 104 static ssize_t readRetry(int Fd, u8 *Buffer, size_t Count) { 105 ssize_t AmountRead = 0; 106 while (static_cast<size_t>(AmountRead) < Count) { 107 ssize_t Result = read(Fd, Buffer + AmountRead, Count - AmountRead); 108 if (Result > 0) 109 AmountRead += Result; 110 else if (!Result) 111 break; 112 else if (errno != EINTR) { 113 AmountRead = -1; 114 break; 115 } 116 } 117 return AmountRead; 118 } 119 120 // Default constructor for Xorshift128Plus seeds the state with /dev/urandom 121 Xorshift128Plus::Xorshift128Plus() { 122 int Fd = open("/dev/urandom", O_RDONLY); 123 bool Success = readRetry(Fd, reinterpret_cast<u8 *>(&State_0_), 124 sizeof(State_0_)) == sizeof(State_0_); 125 Success &= readRetry(Fd, reinterpret_cast<u8 *>(&State_1_), 126 sizeof(State_1_)) == sizeof(State_1_); 127 close(Fd); 128 if (!Success) { 129 dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n"); 130 } 131 } 132 133 } // namespace __scudo 134